From aa9acd04ca929dfbc684937d4466b7b6f01719fe Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 24 Jan 2024 21:36:24 +0000 Subject: [PATCH 01/90] solana: [wip] implement native token transfers TODO: admin functionality TODO: tests TODO: support multiple endpoints --- solana/.gitignore | 8 + solana/.prettierignore | 8 + solana/Anchor.toml | 15 + solana/Cargo.lock | 2408 +++++++++++++++++ solana/Cargo.toml | 13 + solana/keys/test.json | 1 + solana/migrations/deploy.ts | 12 + solana/package.json | 20 + .../example-native-token-transfers/Cargo.toml | 24 + .../example-native-token-transfers/Xargo.toml | 2 + .../src/chain_id.rs | 37 + .../src/config.rs | 28 + .../src/error.rs | 18 + .../src/instructions/initialize.rs | 41 + .../src/instructions/mod.rs | 11 + .../src/instructions/redeem.rs | 110 + .../src/instructions/release_inbound.rs | 70 + .../src/instructions/release_outbound.rs | 121 + .../src/instructions/transfer.rs | 123 + .../example-native-token-transfers/src/lib.rs | 42 + .../src/messages.rs | 143 + .../src/queue/inbound.rs | 31 + .../src/queue/mod.rs | 3 + .../src/queue/outbound.rs | 38 + .../src/queue/rate_limit.rs | 51 + .../src/sequence.rs | 18 + solana/tsconfig.json | 11 + solana/yarn.lock | 1154 ++++++++ 28 files changed, 4561 insertions(+) create mode 100644 solana/.gitignore create mode 100644 solana/.prettierignore create mode 100644 solana/Anchor.toml create mode 100644 solana/Cargo.lock create mode 100644 solana/Cargo.toml create mode 100644 solana/keys/test.json create mode 100644 solana/migrations/deploy.ts create mode 100644 solana/package.json create mode 100644 solana/programs/example-native-token-transfers/Cargo.toml create mode 100644 solana/programs/example-native-token-transfers/Xargo.toml create mode 100644 solana/programs/example-native-token-transfers/src/chain_id.rs create mode 100644 solana/programs/example-native-token-transfers/src/config.rs create mode 100644 solana/programs/example-native-token-transfers/src/error.rs create mode 100644 solana/programs/example-native-token-transfers/src/instructions/initialize.rs create mode 100644 solana/programs/example-native-token-transfers/src/instructions/mod.rs create mode 100644 solana/programs/example-native-token-transfers/src/instructions/redeem.rs create mode 100644 solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs create mode 100644 solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs create mode 100644 solana/programs/example-native-token-transfers/src/instructions/transfer.rs create mode 100644 solana/programs/example-native-token-transfers/src/lib.rs create mode 100644 solana/programs/example-native-token-transfers/src/messages.rs create mode 100644 solana/programs/example-native-token-transfers/src/queue/inbound.rs create mode 100644 solana/programs/example-native-token-transfers/src/queue/mod.rs create mode 100644 solana/programs/example-native-token-transfers/src/queue/outbound.rs create mode 100644 solana/programs/example-native-token-transfers/src/queue/rate_limit.rs create mode 100644 solana/programs/example-native-token-transfers/src/sequence.rs create mode 100644 solana/tsconfig.json create mode 100644 solana/yarn.lock diff --git a/solana/.gitignore b/solana/.gitignore new file mode 100644 index 000000000..8d401163f --- /dev/null +++ b/solana/.gitignore @@ -0,0 +1,8 @@ + +.anchor +.DS_Store +target +**/*.rs.bk +node_modules +test-ledger +.yarn diff --git a/solana/.prettierignore b/solana/.prettierignore new file mode 100644 index 000000000..c1a0b75f0 --- /dev/null +++ b/solana/.prettierignore @@ -0,0 +1,8 @@ + +.anchor +.DS_Store +target +node_modules +dist +build +test-ledger diff --git a/solana/Anchor.toml b/solana/Anchor.toml new file mode 100644 index 000000000..170bd1000 --- /dev/null +++ b/solana/Anchor.toml @@ -0,0 +1,15 @@ +[features] +seeds = false +skip-lint = false +[programs.localnet] +solana_multi_endpoint = "CjjU6T8ZowfYmK3bDrb5k8TdTSQxCMnhZz1xFXUwUYsn" + +[registry] +url = "https://api.apr.dev" + +[provider] +cluster = "Localnet" +wallet = "keys/test.json" + +[scripts] +test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" diff --git a/solana/Cargo.lock b/solana/Cargo.lock new file mode 100644 index 000000000..9fb605ae7 --- /dev/null +++ b/solana/Cargo.lock @@ -0,0 +1,2408 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aead" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +dependencies = [ + "generic-array", +] + +[[package]] +name = "aes" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", + "opaque-debug", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +dependencies = [ + "getrandom 0.2.12", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +dependencies = [ + "cfg-if", + "getrandom 0.2.12", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +dependencies = [ + "memchr", +] + +[[package]] +name = "anchor-attribute-access-control" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "faa5be5b72abea167f87c868379ba3c2be356bfca9e6f474fd055fa0f7eeb4f2" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f468970344c7c9f9d03b4da854fd7c54f21305059f53789d0045c1dd803f0018" +dependencies = [ + "anchor-syn", + "anyhow", + "bs58 0.5.0", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59948e7f9ef8144c2aefb3f32a40c5fce2798baeec765ba038389e82301017ef" +dependencies = [ + "anchor-syn", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc753c9d1c7981cb8948cf7e162fb0f64558999c0413058e2d43df1df5448086" +dependencies = [ + "anchor-syn", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38b4e172ba1b52078f53fdc9f11e3dc0668ad27997838a0aad2d148afac8c97" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eebd21543606ab61e2d83d9da37d24d3886a49f390f9c43a1964735e8c0f0d5" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec4720d899b3686396cced9508f23dab420f1308344456ec78ef76f98fda42af" +dependencies = [ + "anchor-syn", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-space" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f495e85480bd96ddeb77b71d499247c7d4e8b501e75ecb234e9ef7ae7bd6552a" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-lang" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d2d4b20100f1310a774aba3471ef268e5c4ba4d5c28c0bbe663c2658acbc414" +dependencies = [ + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", + "anchor-derive-space", + "arrayref", + "base64 0.13.1", + "bincode", + "borsh 0.10.3", + "bytemuck", + "getrandom 0.2.12", + "solana-program", + "thiserror", +] + +[[package]] +name = "anchor-spl" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78f860599da1c2354e7234c768783049eb42e2f54509ecfc942d2e0076a2da7b" +dependencies = [ + "anchor-lang", + "solana-program", + "spl-associated-token-account", + "spl-token", + "spl-token-2022", +] + +[[package]] +name = "anchor-syn" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a125e4b0cc046cfec58f5aa25038e34cf440151d58f0db3afc55308251fe936d" +dependencies = [ + "anyhow", + "bs58 0.5.0", + "heck", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.8", + "syn 1.0.109", + "thiserror", +] + +[[package]] +name = "anyhow" +version = "1.0.79" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "array-bytes" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" + +[[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 = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi", + "libc", + "winapi", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[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 = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitmaps" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2" +dependencies = [ + "typenum", +] + +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "block-padding", + "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 = "block-padding" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae" + +[[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 = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.13.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 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[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.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-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.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 = "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.109", +] + +[[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.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5353f36341f7451062466f0b755b96ac3a9547e4d7f6b70d603fc721a7d7896" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "jobserver", + "libc", +] + +[[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.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" +dependencies = [ + "num-traits", +] + +[[package]] +name = "cipher" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +dependencies = [ + "generic-array", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + +[[package]] +name = "cpufeatures" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +dependencies = [ + "libc", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +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 = "ctr" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +dependencies = [ + "cipher", +] + +[[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", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "darling" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.48", +] + +[[package]] +name = "darling_macro" +version = "0.20.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "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 = "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 = "ed25519-dalek-bip32" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" +dependencies = [ + "derivation-path", + "ed25519-dalek", + "hmac 0.12.1", + "sha2 0.10.8", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[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 = "example-native-token-transfers" +version = "0.1.0" +dependencies = [ + "ahash 0.8.6", + "anchor-lang", + "anchor-spl", + "wormhole-anchor-sdk", + "wormhole-io", +] + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "serde", + "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", + "js-sys", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[package]] +name = "hashbrown" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +dependencies = [ + "ahash 0.7.7", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.6", +] + +[[package]] +name = "hashbrown" +version = "0.14.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" + +[[package]] +name = "heck" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +dependencies = [ + "unicode-segmentation", +] + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[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 = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "im" +version = "15.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +dependencies = [ + "bitmaps", + "rand_core 0.6.4", + "rand_xoshiro", + "rayon", + "serde", + "sized-chunks", + "typenum", + "version_check", +] + +[[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 = "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.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +dependencies = [ + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +dependencies = [ + "wasm-bindgen", +] + +[[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" + +[[package]] +name = "libc" +version = "0.2.152" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "hmac-drbg", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", + "typenum", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[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.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[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.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[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-derive" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[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-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +dependencies = [ + "num_enum_derive 0.5.11", +] + +[[package]] +name = "num_enum" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +dependencies = [ + "num_enum_derive 0.6.1", +] + +[[package]] +name = "num_enum_derive" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "num_enum_derive" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +dependencies = [ + "proc-macro-crate 1.3.1", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[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 = "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", + "libc", + "redox_syscall", + "smallvec", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac", +] + +[[package]] +name = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" + +[[package]] +name = "polyval" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[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.78" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quote" +version = "1.0.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "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 = "rand_xoshiro" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" +dependencies = [ + "rand_core 0.6.4", +] + +[[package]] +name = "rayon" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +dependencies = [ + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +dependencies = [ + "crossbeam-deque", + "crossbeam-utils", +] + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags", +] + +[[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", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b7fa1134405e2ec9353fd416b17f8dacd46c473d7d3fd1cf202706a14eb792a" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "semver" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + +[[package]] +name = "serde" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.195" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.111" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[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", + "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", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", +] + +[[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 = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[package]] +name = "smallvec" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" + +[[package]] +name = "solana-frozen-abi" +version = "1.16.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7077f6495ccc313dff49c3e3f3ed03e49058258bae7fee77ac29ba0a474ba82" +dependencies = [ + "ahash 0.8.6", + "blake3", + "block-buffer 0.10.4", + "bs58 0.4.0", + "bv", + "byteorder", + "cc", + "either", + "generic-array", + "getrandom 0.1.16", + "im", + "lazy_static", + "log", + "memmap2", + "once_cell", + "rand_core 0.6.4", + "rustc_version", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "solana-frozen-abi-macro", + "subtle", + "thiserror", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.16.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f516f992211a2ab70de5c367190575c97e02d156f9f1d8b76886d673f30e88a2" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.48", +] + +[[package]] +name = "solana-logger" +version = "1.16.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b64def674bfaa4a3f8be7ba19c03c9caec4ec028ba62b9a427ec1bf608a2486" +dependencies = [ + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "solana-program" +version = "1.16.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e92350aa5b42564681655331e7e0b9d5c99a442de317ceeb4741efbbe9a6c05" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "array-bytes", + "base64 0.21.7", + "bincode", + "bitflags", + "blake3", + "borsh 0.10.3", + "borsh 0.9.3", + "bs58 0.4.0", + "bv", + "bytemuck", + "cc", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.12", + "itertools", + "js-sys", + "lazy_static", + "libc", + "libsecp256k1", + "log", + "memoffset", + "num-bigint", + "num-derive", + "num-traits", + "parking_lot", + "rand 0.7.3", + "rand_chacha 0.2.2", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk-macro", + "thiserror", + "tiny-bip39", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-sdk" +version = "1.16.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2087e15c92d4d6b3f085dc12fbe9614141c811f90a54cc418240ac30b608133f" +dependencies = [ + "assert_matches", + "base64 0.21.7", + "bincode", + "bitflags", + "borsh 0.10.3", + "bs58 0.4.0", + "bytemuck", + "byteorder", + "chrono", + "derivation-path", + "digest 0.10.7", + "ed25519-dalek", + "ed25519-dalek-bip32", + "generic-array", + "hmac 0.12.1", + "itertools", + "js-sys", + "lazy_static", + "libsecp256k1", + "log", + "memmap2", + "num-derive", + "num-traits", + "num_enum 0.6.1", + "pbkdf2 0.11.0", + "qstring", + "rand 0.7.3", + "rand_chacha 0.2.2", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "serde_with", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-logger", + "solana-program", + "solana-sdk-macro", + "thiserror", + "uriparse", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.16.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0e0e7ee984b0f9179a1d4f4e9e67ce675de2324b5a98b61d2bdb61be3c19bb" +dependencies = [ + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + +[[package]] +name = "solana-zk-token-sdk" +version = "1.16.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1457c85ab70a518438b9ac2b0c56037b9f6693060dfb617bbb93c7116e4f0c22" +dependencies = [ + "aes-gcm-siv", + "base64 0.21.7", + "bincode", + "bytemuck", + "byteorder", + "curve25519-dalek", + "getrandom 0.1.16", + "itertools", + "lazy_static", + "merlin", + "num-derive", + "num-traits", + "rand 0.7.3", + "serde", + "serde_json", + "sha3 0.9.1", + "solana-program", + "solana-sdk", + "subtle", + "thiserror", + "zeroize", +] + +[[package]] +name = "spl-associated-token-account" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" +dependencies = [ + "assert_matches", + "borsh 0.9.3", + "num-derive", + "num-traits", + "solana-program", + "spl-token", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "spl-memo" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-token" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum 0.5.11", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum 0.5.11", + "solana-program", + "solana-zk-token-sdk", + "spl-memo", + "spl-token", + "thiserror", +] + +[[package]] +name = "strsim" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" + +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + +[[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.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac 0.8.1", + "once_cell", + "pbkdf2 0.4.0", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[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 = "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 = "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.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" + +[[package]] +name = "universal-hash" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +dependencies = [ + "generic-array", + "subtle", +] + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[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.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +dependencies = [ + "cfg-if", + "wasm-bindgen-macro", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +dependencies = [ + "bumpalo", + "log", + "once_cell", + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "wasm-bindgen-backend", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.90" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" + +[[package]] +name = "web-sys" +version = "0.3.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[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-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.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +dependencies = [ + "memchr", +] + +[[package]] +name = "wormhole-anchor-sdk" +version = "0.1.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd5b515d674db0fd7b562bc6ecd1b3e35912e6a9a101f486513b8978205736a2" +dependencies = [ + "anchor-lang", + "anchor-spl", + "cfg-if", +] + +[[package]] +name = "wormhole-io" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b021a14ea7bcef9517ed9f81d4466c4a663dd90e726c5724707a976fa83ad8f3" + +[[package]] +name = "zerocopy" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[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.48", +] diff --git a/solana/Cargo.toml b/solana/Cargo.toml new file mode 100644 index 000000000..ef17a63c0 --- /dev/null +++ b/solana/Cargo.toml @@ -0,0 +1,13 @@ +[workspace] +members = [ + "programs/*" +] + +[profile.release] +overflow-checks = true +lto = "fat" +codegen-units = 1 +[profile.release.build-override] +opt-level = 3 +incremental = false +codegen-units = 1 diff --git a/solana/keys/test.json b/solana/keys/test.json new file mode 100644 index 000000000..99b8808c4 --- /dev/null +++ b/solana/keys/test.json @@ -0,0 +1 @@ +[213,246,85,73,29,91,32,148,195,92,64,142,118,34,101,229,59,139,218,40,163,102,81,107,46,153,187,237,126,42,189,93,120,211,113,71,64,76,148,56,204,160,188,30,143,107,128,200,113,79,11,124,22,136,211,45,40,183,115,220,36,154,56,82] \ No newline at end of file diff --git a/solana/migrations/deploy.ts b/solana/migrations/deploy.ts new file mode 100644 index 000000000..82fb175fa --- /dev/null +++ b/solana/migrations/deploy.ts @@ -0,0 +1,12 @@ +// Migrations are an early feature. Currently, they're nothing more than this +// single deploy script that's invoked from the CLI, injecting a provider +// configured from the workspace's Anchor.toml. + +const anchor = require("@coral-xyz/anchor"); + +module.exports = async function (provider) { + // Configure client to use the provider. + anchor.setProvider(provider); + + // Add your deploy script here. +}; diff --git a/solana/package.json b/solana/package.json new file mode 100644 index 000000000..bde2858ad --- /dev/null +++ b/solana/package.json @@ -0,0 +1,20 @@ +{ + "license": "Apache-2.0", + "scripts": { + "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + }, + "dependencies": { + "@coral-xyz/anchor": "^0.28.0" + }, + "devDependencies": { + "chai": "^4.3.4", + "mocha": "^9.0.3", + "ts-mocha": "^10.0.0", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "typescript": "^4.3.5", + "prettier": "^2.6.2" + } +} diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml new file mode 100644 index 000000000..2c1347d53 --- /dev/null +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "example-native-token-transfers" +version = "0.1.0" +description = "Example implementation of native token transfer standard" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "example_native_token_transfers" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] + +[dependencies] +ahash = "=0.8.6" + +anchor-lang = "0.28.0" +anchor-spl = "0.28.0" +wormhole-anchor-sdk = "0.1.0-alpha.2" +wormhole-io = "0.1.3" diff --git a/solana/programs/example-native-token-transfers/Xargo.toml b/solana/programs/example-native-token-transfers/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/solana/programs/example-native-token-transfers/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/solana/programs/example-native-token-transfers/src/chain_id.rs b/solana/programs/example-native-token-transfers/src/chain_id.rs new file mode 100644 index 000000000..56d54ce21 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/chain_id.rs @@ -0,0 +1,37 @@ +use std::io; + +use anchor_lang::prelude::*; +use wormhole_io::{Readable, Writeable}; + +#[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone, Debug, PartialEq, Eq, Copy)] +pub struct ChainId { + pub id: u16, +} + +impl Readable for ChainId { + const SIZE: Option = u16::SIZE; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let id = Readable::read(reader)?; + + Ok(Self { id }) + } +} + +impl Writeable for ChainId { + fn written_size(&self) -> usize { + ::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let ChainId { id } = self; + id.write(writer) + } +} diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs new file mode 100644 index 000000000..1ba9ff044 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -0,0 +1,28 @@ +use anchor_lang::prelude::*; + +use crate::chain_id::ChainId; + +#[account] +#[derive(InitSpace)] +pub struct Config { + pub bump: u8, + /// Mint address of the token managed by this program. + pub mint: Pubkey, + /// The mode that this program is running in. This is used to determine + /// whether the program is burning tokens or locking tokens. + pub mode: Mode, + /// The chain id of the chain that this program is running on. We don't + /// hardcode this so that the program is deployable on any potential SVM + /// forks. + pub chain_id: ChainId, +} + +impl Config { + pub const SEED_PREFIX: &'static [u8] = b"config"; +} + +#[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone)] +pub enum Mode { + Burning, + Locking, +} diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs new file mode 100644 index 000000000..701a99ef2 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -0,0 +1,18 @@ +use anchor_lang::prelude::error_code; + +#[error_code] +// TODO(csongor): rename +pub enum NTTError { + #[msg("ReleaseTimestampNotReached")] + ReleaseTimestampNotReached, + #[msg("InvalidChainId")] + InvalidChainId, + #[msg("InvalidRecipientAddress")] + InvalidRecipientAddress, + #[msg("InvalidSibling")] + InvalidSibling, + #[msg("TransferAlreadyRedeemed")] + TransferAlreadyRedeemed, + #[msg("MessageAlreadySent")] + MessageAlreadySent, +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs new file mode 100644 index 000000000..bb2e74f16 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -0,0 +1,41 @@ +use anchor_lang::prelude::*; + +use crate::chain_id::ChainId; + +// TODO: upgradeability +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + init, + space = 8 + crate::config::Config::INIT_SPACE, + payer = payer, + seeds = [crate::config::Config::SEED_PREFIX], + bump + )] + pub config: Account<'info, crate::config::Config>, + + #[account()] + pub mint: Account<'info, anchor_spl::token::Mint>, + + system_program: Program<'info, System>, + // TODO: initialize rate limits +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct InitializeArgs { + pub chain_id: u16, +} + +pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> { + ctx.accounts.config.set_inner(crate::config::Config { + bump: ctx.bumps["config"], + mint: ctx.accounts.mint.key(), + mode: crate::config::Mode::Locking, + chain_id: ChainId { id: args.chain_id }, + }); + + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/mod.rs b/solana/programs/example-native-token-transfers/src/instructions/mod.rs new file mode 100644 index 000000000..ae35f471c --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/mod.rs @@ -0,0 +1,11 @@ +pub mod initialize; +pub mod redeem; +pub mod release_inbound; +pub mod release_outbound; +pub mod transfer; + +pub use initialize::*; +pub use redeem::*; +pub use release_inbound::*; +pub use release_outbound::*; +pub use transfer::*; diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs new file mode 100644 index 000000000..f6b81d991 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -0,0 +1,110 @@ +use anchor_lang::{prelude::*, solana_program::clock}; + +use wormhole_anchor_sdk::wormhole::{self, PostedVaa, PostedVaaData}; + +use crate::{ + config::Config, + error::NTTError, + messages::{ManagerMessage, NativeTokenTransfer}, + queue::inbound::{InboundQueuedTransfer, InboundRateLimit}, +}; + +#[account] +#[derive(InitSpace)] +/// A sibling on another chain. Stored in a PDA seeded by the chain id. +pub struct Sibling { + pub bump: u8, + // TODO: variable address length? + pub address: [u8; 32], +} + +impl Sibling { + pub const SEED_PREFIX: &'static [u8] = b"sibling"; +} + +#[derive(Accounts)] +pub struct Redeem<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: Account<'info, Config>, + + #[account( + seeds = [Sibling::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], + constraint = sibling.address == *vaa.emitter_address() @ NTTError::InvalidSibling, + bump = sibling.bump, + )] + pub sibling: Account<'info, Sibling>, + + #[account( + seeds = [PostedVaaData::SEED_PREFIX], + seeds::program = wormhole::program::ID, + bump, + // check that the VAA's emitter agrees with what's in the message + constraint = vaa.emitter_chain() == vaa.message().chain_id.id @ NTTError::InvalidChainId, + // TODO: once the manager payload has sending manager address, check + // that too (against VAA emitter) + // constraint = vaa.emitter_address() == vaa.message().payload.from @ NTTError::InvalidEmitter, + // check that the messages is targeted to this chain + constraint = vaa.message().payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + // NOTE: we don't replay protect VAAs. Instead, we replay protect + // executing the messages themselves with the [`released`] flag. + )] + pub vaa: Account<'info, PostedVaa>>, + + #[account( + init, + payer = payer, + space = 8 + InboundQueuedTransfer::INIT_SPACE, + seeds = [ + InboundQueuedTransfer::SEED_PREFIX, + vaa.message().chain_id.id.to_be_bytes().as_ref(), + vaa.message().sequence.to_be_bytes().as_ref(), + ], + bump, + )] + // NOTE: in order to handle multiple endpoints, we can just augment the + // queued transfer struct with a bitmap storing which endpoints have + // attested to the transfer. Then we only release it if there's quorum. + // We would need to maybe_init this account in that case. + pub enqueued: Account<'info, InboundQueuedTransfer>, + + #[account( + mut, + seeds = [ + InboundRateLimit::SEED_PREFIX, + vaa.emitter_chain().to_be_bytes().as_ref() + ], + bump, + )] + pub rate_limit: Account<'info, InboundRateLimit>, + + pub system_program: Program<'info, System>, +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct RedeemArgs {} + +pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { + let accs = ctx.accounts; + + let message: ManagerMessage = accs.vaa.message().clone(); + + let amount = message.payload.amount; + let recipient_address = + Pubkey::try_from(message.payload.to).map_err(|_| NTTError::InvalidRecipientAddress)?; + + let now = clock::Clock::get()?.unix_timestamp; + + let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); + + accs.enqueued.set_inner(InboundQueuedTransfer { + bump: ctx.bumps["enqueued"], + amount, + recipient_address, + release_timestamp, + released: false, + }); + + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs new file mode 100644 index 000000000..8e25b0b38 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -0,0 +1,70 @@ +use anchor_lang::{prelude::*, solana_program::clock}; +use anchor_spl::token::{self, Token}; + +use crate::{config::Config, error::NTTError, queue::inbound::InboundQueuedTransfer}; + +#[derive(Accounts)] +pub struct ReleaseInbound<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: Account<'info, Config>, + + #[account( + mut, + constraint = !enqueued.released @ NTTError::TransferAlreadyRedeemed, + )] + pub enqueued: Account<'info, InboundQueuedTransfer>, + + #[account( + mut, + address = enqueued.recipient_address, + )] + /// CHECK: the address is checked to match th recipient address in the + /// queued transfer + pub recipient: AccountInfo<'info>, + + #[account( + mut, + address = config.mint, + )] + /// CHECK: the mint address matches the config + pub mint: AccountInfo<'info>, + + #[account( + seeds = [b"token_minter"], + bump, + )] + /// CHECK: the token program checks if this indeed the right authority for the mint + pub mint_authority: AccountInfo<'info>, + + pub token_program: Program<'info, Token>, +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct ReleaseInboundArgs {} + +pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) -> Result<()> { + let enqueued = &mut ctx.accounts.enqueued; + + let now = clock::Clock::get()?.unix_timestamp; + + if enqueued.release_timestamp > now { + return Err(NTTError::ReleaseTimestampNotReached.into()); + } + + enqueued.released = true; + + token::mint_to( + CpiContext::new_with_signer( + ctx.accounts.token_program.to_account_info(), + token::MintTo { + mint: ctx.accounts.mint.clone(), + to: ctx.accounts.recipient.clone(), + authority: ctx.accounts.mint_authority.clone(), + }, + &[&[b"token_minter", &[ctx.bumps["token_minter"]]]], + ), + enqueued.amount, + ) +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs new file mode 100644 index 000000000..474e9785c --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -0,0 +1,121 @@ +use anchor_lang::{prelude::*, solana_program::clock}; + +use wormhole_anchor_sdk::wormhole; +use wormhole_io::TypePrefixedPayload; + +use crate::{ + config::Config, + error::NTTError, + messages::{ManagerMessage, NativeTokenTransfer}, + queue::outbound::OutboundQueuedTransfer, +}; + +#[derive(Accounts)] +pub struct ReleaseOutbound<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: Account<'info, Config>, + + #[account( + mut, + constraint = !enqueued.released @ NTTError::MessageAlreadySent, + )] + pub enqueued: Account<'info, OutboundQueuedTransfer>, + + #[account( + mut, + seeds = [b"message", enqueued.sequence.to_be_bytes().as_ref()], + bump, + )] + /// CHECK: initialized and written to by wormhole core bridge + pub wormhole_message: UncheckedAccount<'info>, + + #[account( + mut, + seeds = [b"emitter"], + bump + )] + // TODO: do we want to put anything in here? + /// CHECK: wormhole uses this as the emitter address + pub emitter: UncheckedAccount<'info>, + + // wormhole stuff + #[account(mut)] + /// CHECK: address will be checked by the wormhole core bridge + pub wormhole_bridge: Account<'info, wormhole::BridgeData>, + + #[account(mut)] + /// CHECK: account will be checked by the wormhole core bridge + pub wormhole_fee_collector: UncheckedAccount<'info>, + + #[account(mut)] + /// CHECK: account will be checked and maybe initialized by the wormhole core bridge + pub wormhole_sequence: UncheckedAccount<'info>, + + pub wormhole_program: Program<'info, wormhole::program::Wormhole>, + + pub system_program: Program<'info, System>, + + // legacy + pub clock: Sysvar<'info, Clock>, + pub rent: Sysvar<'info, Rent>, +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct ReleaseOutboundArgs {} + +pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArgs) -> Result<()> { + let accs = ctx.accounts; + let batch_id = 0; + + let now = clock::Clock::get()?.unix_timestamp; + + if accs.enqueued.release_timestamp > now { + return Err(NTTError::ReleaseTimestampNotReached.into()); + } + + // TODO: record endpoint position + + // TODO: normalise amounts. + + let message: ManagerMessage = ManagerMessage { + chain_id: accs.config.chain_id, + sequence: accs.enqueued.sequence, + sender: accs.emitter.key().to_bytes().to_vec(), + payload: NativeTokenTransfer { + amount: accs.enqueued.amount, + to: accs.enqueued.recipient_address.clone(), + to_chain: accs.enqueued.recipient_chain, + }, + }; + + wormhole::post_message( + CpiContext::new_with_signer( + accs.wormhole_program.to_account_info(), + wormhole::PostMessage { + config: accs.wormhole_bridge.to_account_info(), + message: accs.wormhole_message.to_account_info(), + emitter: accs.emitter.to_account_info(), + sequence: accs.wormhole_sequence.to_account_info(), + payer: accs.payer.to_account_info(), + fee_collector: accs.wormhole_fee_collector.to_account_info(), + clock: accs.clock.to_account_info(), + rent: accs.rent.to_account_info(), + system_program: accs.system_program.to_account_info(), + }, + &[ + &[b"emitter", &[ctx.bumps["emitter"]]], + &[ + b"message", + accs.enqueued.sequence.to_be_bytes().as_ref(), + &[ctx.bumps["wormhole_message"]], + ], + ], + ), + batch_id, + TypePrefixedPayload::to_vec_payload(&message), + wormhole::Finality::Finalized, + )?; + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs new file mode 100644 index 000000000..e4922571f --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -0,0 +1,123 @@ +use anchor_lang::{prelude::*, solana_program::clock}; +use anchor_spl::token::{self, Token, TokenAccount}; + +use crate::{ + chain_id::ChainId, + config::Mode, + queue::outbound::{OutboundQueuedTransfer, OutboundRateLimit}, +}; + +// this will burn the funds and create an account that either allows sending the +// transfer immediately, or queuing up the transfer for later +#[derive(Accounts)] +pub struct Transfer<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub config: Account<'info, crate::config::Config>, + + #[account( + mut, + address = config.mint, + )] + /// CHECK: the mint address matches the config + pub mint: AccountInfo<'info>, + + #[account( + mut, + token::mint = config.mint, + )] + pub from: Account<'info, TokenAccount>, + + /// authority to burn the tokens (owner) + /// CHECK: this is checked by the token program + pub from_authority: Signer<'info>, + + pub token_program: Program<'info, Token>, + + #[account( + mut, + seeds = [crate::sequence::Sequence::SEED_PREFIX], + bump = seq.bump, + )] + pub seq: Account<'info, crate::sequence::Sequence>, + + #[account( + init, + payer = payer, + space = 8 + OutboundQueuedTransfer::INIT_SPACE, + // TODO: this creates a race condition + // when two people try to send a transfer at the same time + // only one of them can claim the sequence number. + // Not sure if there's a way around this, the PDA has to be seeded by + // something unique to this transfer, so I think it has to include the + // sequence number (everything else can be the same) + seeds = [OutboundQueuedTransfer::SEED_PREFIX, seq.sequence.to_be_bytes().as_ref()], + bump, + )] + pub enqueued: Account<'info, OutboundQueuedTransfer>, + + #[account(mut)] + pub rate_limit: Account<'info, OutboundRateLimit>, + + pub system_program: Program<'info, System>, +} + +#[derive(AnchorSerialize, AnchorDeserialize)] +pub struct TransferArgs { + pub amount: u64, + pub recipient_chain: ChainId, + pub recipient_address: Vec, +} + +// TODO: fees for relaying? +pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { + let accs = ctx.accounts; + let TransferArgs { + amount, + recipient_chain, + recipient_address, + } = args; + + match accs.config.mode { + Mode::Burning => token::burn( + CpiContext::new( + accs.token_program.to_account_info(), + token::Burn { + mint: accs.mint.to_account_info(), + from: accs.from.to_account_info(), + authority: accs.from_authority.to_account_info(), + }, + ), + amount, + )?, + + // TODO: implement locking mode. it will require a custody account. + // we could take it as optional, and just ignore it in burning mode. + // Alternatively we could do conditional compilation (feature flags), but + // that would complicate testing and leak more into the interface. + // Another option is to introduce a different instruction for locking + // and burning, and just error if the wrong one is used. Again, that leaks + // into the client interface. + Mode::Locking => todo!(), + } + + let now = clock::Clock::get()?.unix_timestamp; + + // consume the rate limit, or delay the transfer if it's outside the limit + let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); + + let sequence = accs.seq.next(); + + accs.enqueued.set_inner(OutboundQueuedTransfer { + bump: ctx.bumps["enqueued"], + sequence, + amount, + recipient_chain, + recipient_address, + release_timestamp, + released: false, + }); + + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs new file mode 100644 index 000000000..fb64440e1 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -0,0 +1,42 @@ +use anchor_lang::prelude::*; + +pub mod chain_id; +pub mod config; +pub mod error; +pub mod instructions; +pub mod messages; +pub mod queue; +pub mod sequence; + +use instructions::*; + +declare_id!("CjjU6T8ZowfYmK3bDrb5k8TdTSQxCMnhZz1xFXUwUYsn"); + +#[program] +pub mod example_native_token_transfers { + + use super::*; + + pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> { + instructions::initialize(ctx, args) + } + + pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { + instructions::transfer(ctx, args) + } + + pub fn release_outbound( + ctx: Context, + args: ReleaseOutboundArgs, + ) -> Result<()> { + instructions::release_outbound(ctx, args) + } + + pub fn redeem(ctx: Context, args: RedeemArgs) -> Result<()> { + instructions::redeem(ctx, args) + } + + pub fn release_inbound(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { + instructions::release_inbound(ctx, args) + } +} diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs new file mode 100644 index 000000000..3c8c778ed --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -0,0 +1,143 @@ +use anchor_lang::prelude::*; +use std::io; + +use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; + +use crate::chain_id::ChainId; + +// TODO: might make sense to break this up into multiple files + +#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] +pub struct ManagerMessage { + pub chain_id: ChainId, + pub sequence: u64, + pub sender: Vec, + pub payload: A, +} + +impl TypePrefixedPayload for ManagerMessage { + const TYPE: Option = None; +} + +impl Readable for ManagerMessage { + const SIZE: Option = None; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let chain_id = Readable::read(reader)?; + let sequence = Readable::read(reader)?; + let sender_len = u16::read(reader)?; + let mut sender = vec![0u8; sender_len.into()]; + reader.read_exact(&mut sender)?; + let payload = A::read_payload(reader)?; + + Ok(Self { + chain_id, + sequence, + sender, + payload, + }) + } +} + +impl Writeable for ManagerMessage { + fn written_size(&self) -> usize { + ChainId::SIZE.unwrap() + + u64::SIZE.unwrap() + + u8::SIZE.unwrap() + + u16::SIZE.unwrap() // sender length + + self.sender.len() + + self.payload.written_size() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let ManagerMessage { + chain_id, + sequence, + sender, + payload, + } = self; + + chain_id.write(writer)?; + sequence.write(writer)?; + (sender.len() as u16).write(writer)?; + writer.write_all(sender)?; + A::write_payload(payload, writer) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] +pub struct NativeTokenTransfer { + // TODO: should we use a U256 library here? might be pointless since we're + // only looking at the least significant 64 bits (last since BE), and + // requring the rest to be 0 + // TODO: change to NormalizedAmount type + pub amount: u64, + pub to: Vec, + // TODO: shouldn't we put this in the outer message? + pub to_chain: ChainId, +} + +impl TypePrefixedPayload for NativeTokenTransfer { + const TYPE: Option = Some(1); +} + +impl Readable for NativeTokenTransfer { + const SIZE: Option = None; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + // read 0s + let zeros: [u64; 3] = Readable::read(reader)?; + assert_eq!(zeros, [0, 0, 0]); + + let amount = Readable::read(reader)?; + let to_len = u16::read(reader)?; + let mut to = vec![0u8; to_len.into()]; + reader.read_exact(&mut to)?; + let to_chain = Readable::read(reader)?; + + Ok(Self { + amount, + to, + to_chain, + }) + } +} + +impl Writeable for NativeTokenTransfer { + fn written_size(&self) -> usize { + <[u64; 4]>::SIZE.unwrap() + + u16::SIZE.unwrap() // payload length + + self.to.len() + + ChainId::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let NativeTokenTransfer { + amount, + to, + to_chain, + } = self; + + // write 0s + [0u64; 3].write(writer)?; + + amount.write(writer)?; + (to.len() as u16).write(writer)?; + writer.write_all(to)?; + to_chain.write(writer) + } +} diff --git a/solana/programs/example-native-token-transfers/src/queue/inbound.rs b/solana/programs/example-native-token-transfers/src/queue/inbound.rs new file mode 100644 index 000000000..2901ab81f --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/queue/inbound.rs @@ -0,0 +1,31 @@ +use anchor_lang::prelude::*; + +use super::rate_limit::RateLimitState; + +#[account] +#[derive(InitSpace)] +// TODO: maybe remove the queue from the name? it's not always queued +pub struct InboundQueuedTransfer { + pub bump: u8, + pub amount: u64, + pub recipient_address: Pubkey, + pub release_timestamp: i64, + pub released: bool, +} + +impl InboundQueuedTransfer { + pub const SEED_PREFIX: &'static [u8] = b"inbound_queue"; +} + +/// Inbound rate limit per chain. +/// SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.) +#[account] +#[derive(InitSpace)] +pub struct InboundRateLimit { + pub bump: u8, + pub rate_limit: RateLimitState, +} + +impl InboundRateLimit { + pub const SEED_PREFIX: &'static [u8] = b"inbound_rate_limit"; +} diff --git a/solana/programs/example-native-token-transfers/src/queue/mod.rs b/solana/programs/example-native-token-transfers/src/queue/mod.rs new file mode 100644 index 000000000..645643297 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/queue/mod.rs @@ -0,0 +1,3 @@ +pub mod outbound; +pub mod inbound; +pub mod rate_limit; diff --git a/solana/programs/example-native-token-transfers/src/queue/outbound.rs b/solana/programs/example-native-token-transfers/src/queue/outbound.rs new file mode 100644 index 000000000..3d914b0b3 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/queue/outbound.rs @@ -0,0 +1,38 @@ +use anchor_lang::prelude::*; + +use crate::chain_id::ChainId; + +use super::rate_limit::RateLimitState; + +#[account] +#[derive(InitSpace)] +// TODO: maybe remove the queue from the name? it's not always queued +pub struct OutboundQueuedTransfer { + pub bump: u8, + pub sequence: u64, + pub amount: u64, + pub recipient_chain: ChainId, + // TODO: revise max length? + #[max_len(120)] + pub recipient_address: Vec, + pub release_timestamp: i64, + // TODO: change this to a bitmap to store which endpoints have released the + // transfer? (multi endpoint) + pub released: bool, +} + +impl OutboundQueuedTransfer { + pub const SEED_PREFIX: &'static [u8] = b"outbound_queue"; +} + +#[account] +#[derive(InitSpace)] +pub struct OutboundRateLimit { + pub rate_limit: RateLimitState, +} + +/// Global rate limit for all outbound transfers to all chains. +/// NOTE: only one of this account can exist, so we don't need to check the PDA. +impl OutboundRateLimit { + pub const SEED_PREFIX: &'static [u8] = b"outbound_rate_limit"; +} diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs new file mode 100644 index 000000000..6a1afc0ec --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -0,0 +1,51 @@ +use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}; + +#[account] +#[derive(InitSpace)] +pub struct RateLimitState { + /// The maximum capacity of the rate limiter. + limit: u64, + /// The capacity of the rate limiter at `last_tx_timestamp`. + /// The actual current capacity is calculated in `capacity_at`, by + /// accounting for the time that has passed since `last_tx_timestamp` and + /// the refill rate. + capacity_at_last_tx: u64, + /// The timestamp of the last transaction that counted towards the current + /// capacity. Transactions that exceeded the capacity do not count, they are + /// just delayed. + last_tx_timestamp: i64, + /// The rate per second at which the capacity is refilled. + refill_rate: u64, +} + +impl RateLimitState { + pub const RATE_LIMIT_DURATION: i64 = 60 * 60 * 24; // 24 hours + + /// Returns the capacity of the rate limiter at the given timestamp. + pub fn capacity_at(&self, now: UnixTimestamp) -> u64 { + assert!(self.last_tx_timestamp <= now); + + let calculated_capacity = { + let time_passed = (now - self.last_tx_timestamp) as u64; + self.capacity_at_last_tx + (time_passed * self.refill_rate) + }; + + calculated_capacity.min(self.limit) + } + + /// Computes the timestamp at which the given amount can be consumed. + /// If it fits within the current capacity, the current timestamp is + /// returned, and the remaining capacity is reduced. + /// Otherwise, the timestamp at which the capacity will be available is + /// returned. + pub fn consume_or_delay(&mut self, now: UnixTimestamp, amount: u64) -> UnixTimestamp { + let capacity = self.capacity_at(now); + if capacity >= amount { + self.capacity_at_last_tx = capacity - amount; + self.last_tx_timestamp = now; + now + } else { + now + Self::RATE_LIMIT_DURATION + } + } +} diff --git a/solana/programs/example-native-token-transfers/src/sequence.rs b/solana/programs/example-native-token-transfers/src/sequence.rs new file mode 100644 index 000000000..5cf20d484 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/sequence.rs @@ -0,0 +1,18 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct Sequence { + pub bump: u8, + pub sequence: u64, +} + +impl Sequence { + pub const SEED_PREFIX: &'static [u8] = b"sequence"; + + pub fn next(&mut self) -> u64 { + let next = self.sequence; + self.sequence += 1; + next + } +} diff --git a/solana/tsconfig.json b/solana/tsconfig.json new file mode 100644 index 000000000..558b83e5e --- /dev/null +++ b/solana/tsconfig.json @@ -0,0 +1,11 @@ +{ + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } + } + \ No newline at end of file diff --git a/solana/yarn.lock b/solana/yarn.lock new file mode 100644 index 000000000..b2834db0f --- /dev/null +++ b/solana/yarn.lock @@ -0,0 +1,1154 @@ +# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. +# yarn lockfile v1 + + +"@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4": + version "7.23.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650" + integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw== + dependencies: + regenerator-runtime "^0.14.0" + +"@coral-xyz/anchor@^0.28.0": + version "0.28.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.28.0.tgz#8345c3c9186a91f095f704d7b90cd256f7e8b2dc" + integrity sha512-kQ02Hv2ZqxtWP30WN1d4xxT4QqlOXYDxmEd3k/bbneqhV3X5QMO4LAtoUFs7otxyivOgoqam5Il5qx81FuI4vw== + dependencies: + "@coral-xyz/borsh" "^0.28.0" + "@solana/web3.js" "^1.68.0" + base64-js "^1.5.1" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^6.3.0" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + js-sha256 "^0.9.0" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" + +"@coral-xyz/borsh@^0.28.0": + version "0.28.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.28.0.tgz#fa368a2f2475bbf6f828f4657f40a52102e02b6d" + integrity sha512-/u1VTzw7XooK7rqeD7JLUSwOyRSesPUk0U37BV9zK0axJc1q0nRbKFGFLYCQ16OtdOJTTwGfGp11Lx9B45bRCQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@noble/curves@^1.2.0": + version "1.3.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== + dependencies: + "@noble/hashes" "1.3.3" + +"@noble/hashes@1.3.3", "@noble/hashes@^1.3.2": + version "1.3.3" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== + +"@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== + dependencies: + buffer "~6.0.3" + +"@solana/web3.js@^1.68.0": + version "1.89.1" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.89.1.tgz#52df6820f2d088c4558aa359af40580a03d10ec9" + integrity sha512-t9TTLtPQxtQB3SAf/5E8xPXfVDsC6WGOsgKY02l2cbe0HLymT7ynE8Hu48Lk5qynHCquj6nhISfEHcjMkYpu/A== + dependencies: + "@babel/runtime" "^7.23.4" + "@noble/curves" "^1.2.0" + "@noble/hashes" "^1.3.2" + "@solana/buffer-layout" "^4.0.1" + agentkeepalive "^4.5.0" + bigint-buffer "^1.1.5" + bn.js "^5.2.1" + borsh "^0.7.0" + bs58 "^4.0.1" + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.0" + node-fetch "^2.7.0" + rpc-websockets "^7.5.1" + superstruct "^0.14.2" + +"@types/bn.js@^5.1.0": + version "5.1.5" + resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" + integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== + dependencies: + "@types/node" "*" + +"@types/chai@^4.3.0": + version "4.3.11" + resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" + integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== + +"@types/connect@^3.4.33": + version "3.4.38" + resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== + dependencies: + "@types/node" "*" + +"@types/json5@^0.0.29": + version "0.0.29" + resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== + +"@types/mocha@^9.0.0": + version "9.1.1" + resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" + integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== + +"@types/node@*": + version "20.11.5" + resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.5.tgz#be10c622ca7fcaa3cf226cf80166abc31389d86e" + integrity sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w== + dependencies: + undici-types "~5.26.4" + +"@types/node@^12.12.54": + version "12.20.55" + resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== + +"@types/ws@^7.4.4": + version "7.4.7" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== + dependencies: + "@types/node" "*" + +"@ungap/promise-all-settled@1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== + +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +agentkeepalive@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + +ansi-colors@4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== + +ansi-regex@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== + +ansi-styles@^4.0.0, ansi-styles@^4.1.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== + dependencies: + color-convert "^2.0.1" + +anymatch@~3.1.2: + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== + dependencies: + normalize-path "^3.0.0" + picomatch "^2.0.4" + +argparse@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== + +arrify@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== + +assertion-error@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== + +balanced-match@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== + +base-x@^3.0.2: + version "3.0.9" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== + dependencies: + safe-buffer "^5.0.1" + +base64-js@^1.3.1, base64-js@^1.5.1: + version "1.5.1" + resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== + +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + +binary-extensions@^2.0.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" + +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== + dependencies: + bn.js "^5.2.0" + bs58 "^4.0.0" + text-encoding-utf-8 "^1.0.2" + +brace-expansion@^1.1.7: + version "1.1.11" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== + dependencies: + balanced-match "^1.0.0" + concat-map "0.0.1" + +braces@~3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + dependencies: + fill-range "^7.0.1" + +browser-stdout@1.3.1: + version "1.3.1" + resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== + +bs58@^4.0.0, bs58@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== + dependencies: + base-x "^3.0.2" + +buffer-from@^1.0.0, buffer-from@^1.1.0: + version "1.1.2" + resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== + +buffer-layout@^1.2.0, buffer-layout@^1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" + integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== + +buffer@6.0.3, buffer@~6.0.3: + version "6.0.3" + resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== + dependencies: + base64-js "^1.3.1" + ieee754 "^1.2.1" + +bufferutil@^4.0.1: + version "4.0.8" + resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea" + integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== + dependencies: + node-gyp-build "^4.3.0" + +camelcase@^6.0.0, camelcase@^6.3.0: + version "6.3.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== + +chai@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" + integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== + dependencies: + assertion-error "^1.1.0" + check-error "^1.0.3" + deep-eql "^4.1.3" + get-func-name "^2.0.2" + loupe "^2.3.6" + pathval "^1.1.1" + type-detect "^4.0.8" + +chalk@^4.1.0: + version "4.1.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== + dependencies: + ansi-styles "^4.1.0" + supports-color "^7.1.0" + +check-error@^1.0.3: + version "1.0.3" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== + dependencies: + get-func-name "^2.0.2" + +chokidar@3.5.3: + version "3.5.3" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== + dependencies: + anymatch "~3.1.2" + braces "~3.0.2" + glob-parent "~5.1.2" + is-binary-path "~2.1.0" + is-glob "~4.0.1" + normalize-path "~3.0.0" + readdirp "~3.6.0" + optionalDependencies: + fsevents "~2.3.2" + +cliui@^7.0.2: + version "7.0.4" + resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== + dependencies: + string-width "^4.2.0" + strip-ansi "^6.0.0" + wrap-ansi "^7.0.0" + +color-convert@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== + dependencies: + color-name "~1.1.4" + +color-name@~1.1.4: + version "1.1.4" + resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== + +commander@^2.20.3: + version "2.20.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== + +concat-map@0.0.1: + version "0.0.1" + resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== + +cross-fetch@^3.1.5: + version "3.1.8" + resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== + dependencies: + node-fetch "^2.6.12" + +crypto-hash@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247" + integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== + +debug@4.3.3: + version "4.3.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== + dependencies: + ms "2.1.2" + +decamelize@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== + +deep-eql@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== + dependencies: + type-detect "^4.0.0" + +delay@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== + +diff@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +diff@^3.1.0: + version "3.5.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== + +dot-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== + dependencies: + no-case "^3.0.4" + tslib "^2.0.3" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +es6-promise@^4.0.3: + version "4.2.8" + resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + +es6-promisify@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== + dependencies: + es6-promise "^4.0.3" + +escalade@^3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + +escape-string-regexp@4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== + +eventemitter3@^4.0.7: + version "4.0.7" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== + +eyes@^0.1.8: + version "0.1.8" + resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== + +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== + dependencies: + to-regex-range "^5.0.1" + +find-up@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== + dependencies: + locate-path "^6.0.0" + path-exists "^4.0.0" + +flat@^5.0.2: + version "5.0.2" + resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== + +fs.realpath@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== + +fsevents@~2.3.2: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== + +get-caller-file@^2.0.5: + version "2.0.5" + resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== + +get-func-name@^2.0.1, get-func-name@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +glob-parent@~5.1.2: + version "5.1.2" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== + dependencies: + is-glob "^4.0.1" + +glob@7.2.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== + dependencies: + fs.realpath "^1.0.0" + inflight "^1.0.4" + inherits "2" + minimatch "^3.0.4" + once "^1.3.0" + path-is-absolute "^1.0.0" + +growl@1.10.5: + version "1.10.5" + resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== + +has-flag@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== + +he@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== + +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== + dependencies: + ms "^2.0.0" + +ieee754@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== + +inflight@^1.0.4: + version "1.0.6" + resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== + dependencies: + once "^1.3.0" + wrappy "1" + +inherits@2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== + +is-binary-path@~2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== + dependencies: + binary-extensions "^2.0.0" + +is-extglob@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== + +is-fullwidth-code-point@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== + +is-glob@^4.0.1, is-glob@~4.0.1: + version "4.0.3" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== + dependencies: + is-extglob "^2.1.1" + +is-number@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== + +is-plain-obj@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== + +is-unicode-supported@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== + +isexe@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== + +isomorphic-ws@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== + +jayson@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9" + integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A== + dependencies: + "@types/connect" "^3.4.33" + "@types/node" "^12.12.54" + "@types/ws" "^7.4.4" + JSONStream "^1.3.5" + commander "^2.20.3" + delay "^5.0.0" + es6-promisify "^5.0.0" + eyes "^0.1.8" + isomorphic-ws "^4.0.1" + json-stringify-safe "^5.0.1" + uuid "^8.3.2" + ws "^7.4.5" + +js-sha256@^0.9.0: + version "0.9.0" + resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" + integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + +js-yaml@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== + dependencies: + argparse "^2.0.1" + +json-stringify-safe@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== + +json5@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== + dependencies: + minimist "^1.2.0" + +jsonparse@^1.2.0: + version "1.3.1" + resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== + +locate-path@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== + dependencies: + p-locate "^5.0.0" + +log-symbols@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== + dependencies: + chalk "^4.1.0" + is-unicode-supported "^0.1.0" + +loupe@^2.3.6: + version "2.3.7" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== + dependencies: + get-func-name "^2.0.1" + +lower-case@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== + dependencies: + tslib "^2.0.3" + +make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== + +minimatch@4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" + integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimist@^1.2.0, minimist@^1.2.6: + version "1.2.8" + resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== + +mkdirp@^0.5.1: + version "0.5.6" + resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== + dependencies: + minimist "^1.2.6" + +mocha@^9.0.3: + version "9.2.2" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" + integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== + dependencies: + "@ungap/promise-all-settled" "1.1.2" + ansi-colors "4.1.1" + browser-stdout "1.3.1" + chokidar "3.5.3" + debug "4.3.3" + diff "5.0.0" + escape-string-regexp "4.0.0" + find-up "5.0.0" + glob "7.2.0" + growl "1.10.5" + he "1.2.0" + js-yaml "4.1.0" + log-symbols "4.1.0" + minimatch "4.2.1" + ms "2.1.3" + nanoid "3.3.1" + serialize-javascript "6.0.0" + strip-json-comments "3.1.1" + supports-color "8.1.1" + which "2.0.2" + workerpool "6.2.0" + yargs "16.2.0" + yargs-parser "20.2.4" + yargs-unparser "2.0.0" + +ms@2.1.2: + version "2.1.2" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== + +ms@2.1.3, ms@^2.0.0: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +nanoid@3.3.1: + version "3.3.1" + resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== + +no-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== + dependencies: + lower-case "^2.0.2" + tslib "^2.0.3" + +node-fetch@^2.6.12, node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: + version "4.8.0" + resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" + integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== + +normalize-path@^3.0.0, normalize-path@~3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== + +once@^1.3.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== + dependencies: + wrappy "1" + +p-limit@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== + dependencies: + yocto-queue "^0.1.0" + +p-locate@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== + dependencies: + p-limit "^3.0.2" + +pako@^2.0.3: + version "2.1.0" + resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== + +path-exists@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== + +path-is-absolute@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== + +pathval@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== + +picomatch@^2.0.4, picomatch@^2.2.1: + version "2.3.1" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== + +prettier@^2.6.2: + version "2.8.8" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== + +randombytes@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== + dependencies: + safe-buffer "^5.1.0" + +readdirp@~3.6.0: + version "3.6.0" + resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== + dependencies: + picomatch "^2.2.1" + +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== + +require-directory@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== + +rpc-websockets@^7.5.1: + version "7.9.0" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.9.0.tgz#a3938e16d6f134a3999fdfac422a503731bf8973" + integrity sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw== + dependencies: + "@babel/runtime" "^7.17.2" + eventemitter3 "^4.0.7" + uuid "^8.3.2" + ws "^8.5.0" + optionalDependencies: + bufferutil "^4.0.1" + utf-8-validate "^5.0.2" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0: + version "5.2.1" + resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + +serialize-javascript@6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== + dependencies: + randombytes "^2.1.0" + +snake-case@^3.0.4: + version "3.0.4" + resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== + dependencies: + dot-case "^3.0.4" + tslib "^2.0.3" + +source-map-support@^0.5.6: + version "0.5.21" + resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== + dependencies: + buffer-from "^1.0.0" + source-map "^0.6.0" + +source-map@^0.6.0: + version "0.6.1" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== + +string-width@^4.1.0, string-width@^4.2.0: + version "4.2.3" + resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== + dependencies: + emoji-regex "^8.0.0" + is-fullwidth-code-point "^3.0.0" + strip-ansi "^6.0.1" + +strip-ansi@^6.0.0, strip-ansi@^6.0.1: + version "6.0.1" + resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== + dependencies: + ansi-regex "^5.0.1" + +strip-bom@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== + +strip-json-comments@3.1.1: + version "3.1.1" + resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== + +superstruct@^0.14.2: + version "0.14.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" + integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== + +superstruct@^0.15.4: + version "0.15.5" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab" + integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== + +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-color@^7.1.0: + version "7.2.0" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== + dependencies: + has-flag "^4.0.0" + +text-encoding-utf-8@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" + integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== + +"through@>=2.2.7 <3": + version "2.3.8" + resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== + +to-regex-range@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== + dependencies: + is-number "^7.0.0" + +toml@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== + +tr46@~0.0.3: + version "0.0.3" + resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== + +ts-mocha@^10.0.0: + version "10.0.0" + resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.0.0.tgz#41a8d099ac90dbbc64b06976c5025ffaebc53cb9" + integrity sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw== + dependencies: + ts-node "7.0.1" + optionalDependencies: + tsconfig-paths "^3.5.0" + +ts-node@7.0.1: + version "7.0.1" + resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== + dependencies: + arrify "^1.0.0" + buffer-from "^1.1.0" + diff "^3.1.0" + make-error "^1.1.1" + minimist "^1.2.0" + mkdirp "^0.5.1" + source-map-support "^0.5.6" + yn "^2.0.0" + +tsconfig-paths@^3.5.0: + version "3.15.0" + resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== + dependencies: + "@types/json5" "^0.0.29" + json5 "^1.0.2" + minimist "^1.2.6" + strip-bom "^3.0.0" + +tslib@^2.0.3: + version "2.6.2" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== + +type-detect@^4.0.0, type-detect@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== + +typescript@^4.3.5: + version "4.9.5" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== + +undici-types@~5.26.4: + version "5.26.5" + resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== + +utf-8-validate@^5.0.2: + version "5.0.10" + resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== + dependencies: + node-gyp-build "^4.3.0" + +uuid@^8.3.2: + version "8.3.2" + resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== + +webidl-conversions@^3.0.0: + version "3.0.1" + resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== + +whatwg-url@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== + dependencies: + tr46 "~0.0.3" + webidl-conversions "^3.0.0" + +which@2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== + dependencies: + isexe "^2.0.0" + +workerpool@6.2.0: + version "6.2.0" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" + integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== + +wrap-ansi@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== + dependencies: + ansi-styles "^4.0.0" + string-width "^4.1.0" + strip-ansi "^6.0.0" + +wrappy@1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== + +ws@^7.4.5: + version "7.5.9" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== + +ws@^8.5.0: + version "8.16.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== + +y18n@^5.0.5: + version "5.0.8" + resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== + +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + +yargs-parser@^20.2.2: + version "20.2.9" + resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== + +yargs-unparser@2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== + dependencies: + camelcase "^6.0.0" + decamelize "^4.0.0" + flat "^5.0.2" + is-plain-obj "^2.1.0" + +yargs@16.2.0: + version "16.2.0" + resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== + dependencies: + cliui "^7.0.2" + escalade "^3.1.1" + get-caller-file "^2.0.5" + require-directory "^2.1.1" + string-width "^4.2.0" + y18n "^5.0.5" + yargs-parser "^20.2.2" + +yn@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== + +yocto-queue@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== From 12b12a7ba653b8f14653793749745ba72fb6eb24 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 2 Feb 2024 20:03:03 +0000 Subject: [PATCH 02/90] solana: RateLimitSpace is not an account --- .../example-native-token-transfers/src/queue/rate_limit.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index 6a1afc0ec..affffc7d5 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -1,7 +1,6 @@ use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}; -#[account] -#[derive(InitSpace)] +#[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace)] pub struct RateLimitState { /// The maximum capacity of the rate limiter. limit: u64, From cbe53c14ec254f5cddad515463aa146289441dc3 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 2 Feb 2024 20:48:54 +0000 Subject: [PATCH 03/90] solana: normalise amounts in VAAs this is done by introducing a NormalizedAmount newtype, which ensures that normalisation is done consistently --- .../src/instructions/release_inbound.rs | 6 +- .../src/instructions/release_outbound.rs | 2 - .../src/instructions/transfer.rs | 5 +- .../example-native-token-transfers/src/lib.rs | 1 + .../src/messages.rs | 9 +- .../src/normalized_amount.rs | 152 ++++++++++++++++++ .../src/queue/inbound.rs | 4 +- .../src/queue/outbound.rs | 4 +- .../src/queue/rate_limit.rs | 18 ++- 9 files changed, 182 insertions(+), 19 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/src/normalized_amount.rs diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 8e25b0b38..9ebe33929 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -29,7 +29,7 @@ pub struct ReleaseInbound<'info> { address = config.mint, )] /// CHECK: the mint address matches the config - pub mint: AccountInfo<'info>, + pub mint: Account<'info, anchor_spl::token::Mint>, #[account( seeds = [b"token_minter"], @@ -59,12 +59,12 @@ pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) CpiContext::new_with_signer( ctx.accounts.token_program.to_account_info(), token::MintTo { - mint: ctx.accounts.mint.clone(), + mint: ctx.accounts.mint.to_account_info(), to: ctx.accounts.recipient.clone(), authority: ctx.accounts.mint_authority.clone(), }, &[&[b"token_minter", &[ctx.bumps["token_minter"]]]], ), - enqueued.amount, + enqueued.amount.denormalize(ctx.accounts.mint.decimals), ) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 474e9785c..fa9c82f98 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -77,8 +77,6 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg // TODO: record endpoint position - // TODO: normalise amounts. - let message: ManagerMessage = ManagerMessage { chain_id: accs.config.chain_id, sequence: accs.enqueued.sequence, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index e4922571f..40f006770 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -4,6 +4,7 @@ use anchor_spl::token::{self, Token, TokenAccount}; use crate::{ chain_id::ChainId, config::Mode, + normalized_amount::NormalizedAmount, queue::outbound::{OutboundQueuedTransfer, OutboundRateLimit}, }; @@ -21,7 +22,7 @@ pub struct Transfer<'info> { address = config.mint, )] /// CHECK: the mint address matches the config - pub mint: AccountInfo<'info>, + pub mint: Account<'info, anchor_spl::token::Mint>, #[account( mut, @@ -104,6 +105,8 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { let now = clock::Clock::get()?.unix_timestamp; + let amount = NormalizedAmount::normalize(amount, accs.mint.decimals); + // consume the rate limit, or delay the transfer if it's outside the limit let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index fb64440e1..44260a9e1 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -5,6 +5,7 @@ pub mod config; pub mod error; pub mod instructions; pub mod messages; +pub mod normalized_amount; pub mod queue; pub mod sequence; diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 3c8c778ed..b8eb0b527 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -3,7 +3,7 @@ use std::io; use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; -use crate::chain_id::ChainId; +use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; // TODO: might make sense to break this up into multiple files @@ -77,8 +77,7 @@ pub struct NativeTokenTransfer { // TODO: should we use a U256 library here? might be pointless since we're // only looking at the least significant 64 bits (last since BE), and // requring the rest to be 0 - // TODO: change to NormalizedAmount type - pub amount: u64, + pub amount: NormalizedAmount, pub to: Vec, // TODO: shouldn't we put this in the outer message? pub to_chain: ChainId, @@ -138,6 +137,8 @@ impl Writeable for NativeTokenTransfer { amount.write(writer)?; (to.len() as u16).write(writer)?; writer.write_all(to)?; - to_chain.write(writer) + to_chain.write(writer)?; + + Ok(()) } } diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs new file mode 100644 index 000000000..ad3e82475 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -0,0 +1,152 @@ +//! Amounts represented in VAAs are capped at 8 decimals. This +//! means that any amount that's given as having more decimals is truncated to 8 +//! decimals. On the way out, these amount have to be scaled back to the +//! original decimal amount. This module defines [`NormalizedAmount`], which +//! represents amounts that have been capped at 8 decimals. +//! +//! The functions [`normalize`] and [`denormalize`] take care of convertion to/from +//! this type given the original amount's decimals. + +use std::{ + io, + ops::{Add, Mul, Sub}, +}; + +use anchor_lang::prelude::*; +use wormhole_io::{Readable, Writeable}; + +pub const NORMALIZED_DECIMALS: u8 = 8; + +#[derive( + Debug, + Clone, + Copy, + PartialEq, + Eq, + PartialOrd, + Ord, + AnchorSerialize, + AnchorDeserialize, + InitSpace, +)] +pub struct NormalizedAmount { + amount: u64, +} + +impl Mul for NormalizedAmount { + type Output = Self; + + fn mul(self, rhs: Self) -> Self::Output { + Self { + amount: self.amount * rhs.amount, + } + } +} + +impl Mul for NormalizedAmount { + type Output = Self; + + fn mul(self, rhs: u64) -> Self::Output { + Self { + amount: self.amount * rhs, + } + } +} + +impl Add for NormalizedAmount { + type Output = Self; + + fn add(self, rhs: Self) -> Self::Output { + Self { + amount: self.amount + rhs.amount, + } + } +} + +impl Sub for NormalizedAmount { + type Output = Self; + + fn sub(self, rhs: Self) -> Self::Output { + Self { + amount: self.amount - rhs.amount, + } + } +} + +impl NormalizedAmount { + fn scaling_factor(decimals: u8) -> u64 { + if decimals > NORMALIZED_DECIMALS { + 10u64.pow((decimals - NORMALIZED_DECIMALS).into()) + } else { + 1 + } + } + + pub fn normalize(amount: u64, decimals: u8) -> NormalizedAmount { + Self { + amount: amount / Self::scaling_factor(decimals), + } + } + + pub fn denormalize(&self, decimals: u8) -> u64 { + self.amount * Self::scaling_factor(decimals) + } + + #[cfg(test)] + pub fn amount(&self) -> u64 { + self.amount + } +} + +impl Readable for NormalizedAmount { + const SIZE: Option = Some(8); + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let amount = Readable::read(reader)?; + Ok(Self { amount }) + } +} + +impl Writeable for NormalizedAmount { + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let NormalizedAmount { amount } = self; + amount.write(writer)?; + + Ok(()) + } + + fn written_size(&self) -> usize { + Self::SIZE.unwrap() + } +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn test_normalize() { + assert_eq!( + NormalizedAmount::normalize(100_000_000_000_000_000, 18).amount(), + 100_000_00 + ); + + assert_eq!( + NormalizedAmount::normalize(100_000_000_000_000_000, 7).amount(), + 100_000_000_000_000_000 + ); + + assert_eq!( + NormalizedAmount::normalize(100_555_555_555_555_555, 18).denormalize(18), + 100_555_550_000_000_000 + ); + } +} diff --git a/solana/programs/example-native-token-transfers/src/queue/inbound.rs b/solana/programs/example-native-token-transfers/src/queue/inbound.rs index 2901ab81f..e418e720e 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbound.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbound.rs @@ -1,5 +1,7 @@ use anchor_lang::prelude::*; +use crate::normalized_amount::NormalizedAmount; + use super::rate_limit::RateLimitState; #[account] @@ -7,7 +9,7 @@ use super::rate_limit::RateLimitState; // TODO: maybe remove the queue from the name? it's not always queued pub struct InboundQueuedTransfer { pub bump: u8, - pub amount: u64, + pub amount: NormalizedAmount, pub recipient_address: Pubkey, pub release_timestamp: i64, pub released: bool, diff --git a/solana/programs/example-native-token-transfers/src/queue/outbound.rs b/solana/programs/example-native-token-transfers/src/queue/outbound.rs index 3d914b0b3..a9e0f732c 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbound.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbound.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; -use crate::chain_id::ChainId; +use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; use super::rate_limit::RateLimitState; @@ -10,7 +10,7 @@ use super::rate_limit::RateLimitState; pub struct OutboundQueuedTransfer { pub bump: u8, pub sequence: u64, - pub amount: u64, + pub amount: NormalizedAmount, pub recipient_chain: ChainId, // TODO: revise max length? #[max_len(120)] diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index affffc7d5..1f2b148c1 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -1,32 +1,34 @@ use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}; +use crate::normalized_amount::NormalizedAmount; + #[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace)] pub struct RateLimitState { /// The maximum capacity of the rate limiter. - limit: u64, + limit: NormalizedAmount, /// The capacity of the rate limiter at `last_tx_timestamp`. /// The actual current capacity is calculated in `capacity_at`, by /// accounting for the time that has passed since `last_tx_timestamp` and /// the refill rate. - capacity_at_last_tx: u64, + capacity_at_last_tx: NormalizedAmount, /// The timestamp of the last transaction that counted towards the current /// capacity. Transactions that exceeded the capacity do not count, they are /// just delayed. last_tx_timestamp: i64, /// The rate per second at which the capacity is refilled. - refill_rate: u64, + refill_rate: NormalizedAmount, } impl RateLimitState { pub const RATE_LIMIT_DURATION: i64 = 60 * 60 * 24; // 24 hours /// Returns the capacity of the rate limiter at the given timestamp. - pub fn capacity_at(&self, now: UnixTimestamp) -> u64 { + pub fn capacity_at(&self, now: UnixTimestamp) -> NormalizedAmount { assert!(self.last_tx_timestamp <= now); let calculated_capacity = { let time_passed = (now - self.last_tx_timestamp) as u64; - self.capacity_at_last_tx + (time_passed * self.refill_rate) + self.capacity_at_last_tx + (self.refill_rate * time_passed) }; calculated_capacity.min(self.limit) @@ -37,7 +39,11 @@ impl RateLimitState { /// returned, and the remaining capacity is reduced. /// Otherwise, the timestamp at which the capacity will be available is /// returned. - pub fn consume_or_delay(&mut self, now: UnixTimestamp, amount: u64) -> UnixTimestamp { + pub fn consume_or_delay( + &mut self, + now: UnixTimestamp, + amount: NormalizedAmount, + ) -> UnixTimestamp { let capacity = self.capacity_at(now); if capacity >= amount { self.capacity_at_last_tx = capacity - amount; From 3dee8b2232267cb54524f592fcc9e432c20e9b2c Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 5 Feb 2024 12:47:02 +0100 Subject: [PATCH 04/90] solana: set released = true for outbound transfers too --- .../src/instructions/release_inbound.rs | 8 +------- .../src/instructions/release_outbound.rs | 7 +------ .../src/queue/inbound.rs | 18 +++++++++++++++++- .../src/queue/outbound.rs | 19 +++++++++++++++++-- 4 files changed, 36 insertions(+), 16 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 9ebe33929..1db036698 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -47,13 +47,7 @@ pub struct ReleaseInboundArgs {} pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) -> Result<()> { let enqueued = &mut ctx.accounts.enqueued; - let now = clock::Clock::get()?.unix_timestamp; - - if enqueued.release_timestamp > now { - return Err(NTTError::ReleaseTimestampNotReached.into()); - } - - enqueued.released = true; + enqueued.release()?; token::mint_to( CpiContext::new_with_signer( diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index fa9c82f98..4cdc2dccb 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -69,13 +69,8 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg let accs = ctx.accounts; let batch_id = 0; - let now = clock::Clock::get()?.unix_timestamp; - - if accs.enqueued.release_timestamp > now { - return Err(NTTError::ReleaseTimestampNotReached.into()); - } - // TODO: record endpoint position + accs.enqueued.release()?; let message: ManagerMessage = ManagerMessage { chain_id: accs.config.chain_id, diff --git a/solana/programs/example-native-token-transfers/src/queue/inbound.rs b/solana/programs/example-native-token-transfers/src/queue/inbound.rs index e418e720e..b3c016355 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbound.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbound.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; -use crate::normalized_amount::NormalizedAmount; +use crate::{error::NTTError, normalized_amount::NormalizedAmount}; use super::rate_limit::RateLimitState; @@ -17,6 +17,22 @@ pub struct InboundQueuedTransfer { impl InboundQueuedTransfer { pub const SEED_PREFIX: &'static [u8] = b"inbound_queue"; + + pub fn release(&mut self) -> Result<()> { + let now = Clock::get()?.unix_timestamp; + + if self.release_timestamp > now { + return Err(NTTError::ReleaseTimestampNotReached.into()); + } + + if self.released { + return Err(NTTError::TransferAlreadyRedeemed.into()); + } + + self.released = true; + + Ok(()) + } } /// Inbound rate limit per chain. diff --git a/solana/programs/example-native-token-transfers/src/queue/outbound.rs b/solana/programs/example-native-token-transfers/src/queue/outbound.rs index a9e0f732c..fc3fe64bf 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbound.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbound.rs @@ -1,6 +1,6 @@ -use anchor_lang::prelude::*; +use anchor_lang::{prelude::*, solana_program::clock}; -use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; +use crate::{chain_id::ChainId, error::NTTError, normalized_amount::NormalizedAmount}; use super::rate_limit::RateLimitState; @@ -23,6 +23,21 @@ pub struct OutboundQueuedTransfer { impl OutboundQueuedTransfer { pub const SEED_PREFIX: &'static [u8] = b"outbound_queue"; + + pub fn release(&mut self) -> Result<()> { + let now = clock::Clock::get()?.unix_timestamp; + if self.release_timestamp > now { + return Err(NTTError::ReleaseTimestampNotReached.into()); + } + + if self.released { + return Err(NTTError::MessageAlreadySent.into()); + } + + self.released = true; + + Ok(()) + } } #[account] From b9760d025a321b4846b19c8988c261f04655cdb7 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 5 Feb 2024 13:04:21 +0100 Subject: [PATCH 05/90] solana: rename in/outbound queued transfer -> in/outbox item --- .../src/instructions/redeem.rs | 14 ++++++------ .../src/instructions/release_inbound.rs | 20 ++++++++--------- .../src/instructions/release_outbound.rs | 22 +++++++++---------- .../src/instructions/transfer.rs | 14 ++++++------ .../src/queue/{inbound.rs => inbox.rs} | 10 ++++----- .../src/queue/mod.rs | 4 ++-- .../src/queue/{outbound.rs => outbox.rs} | 14 ++++++------ 7 files changed, 49 insertions(+), 49 deletions(-) rename solana/programs/example-native-token-transfers/src/queue/{inbound.rs => inbox.rs} (77%) rename solana/programs/example-native-token-transfers/src/queue/{outbound.rs => outbox.rs} (77%) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index f6b81d991..b5269e95f 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -6,7 +6,7 @@ use crate::{ config::Config, error::NTTError, messages::{ManagerMessage, NativeTokenTransfer}, - queue::inbound::{InboundQueuedTransfer, InboundRateLimit}, + queue::inbox::{InboundRateLimit, InboxItem}, }; #[account] @@ -55,19 +55,19 @@ pub struct Redeem<'info> { #[account( init, payer = payer, - space = 8 + InboundQueuedTransfer::INIT_SPACE, + space = 8 + InboxItem::INIT_SPACE, seeds = [ - InboundQueuedTransfer::SEED_PREFIX, + InboxItem::SEED_PREFIX, vaa.message().chain_id.id.to_be_bytes().as_ref(), vaa.message().sequence.to_be_bytes().as_ref(), ], bump, )] // NOTE: in order to handle multiple endpoints, we can just augment the - // queued transfer struct with a bitmap storing which endpoints have + // inbox item transfer struct with a bitmap storing which endpoints have // attested to the transfer. Then we only release it if there's quorum. // We would need to maybe_init this account in that case. - pub enqueued: Account<'info, InboundQueuedTransfer>, + pub inbox_item: Account<'info, InboxItem>, #[account( mut, @@ -98,8 +98,8 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); - accs.enqueued.set_inner(InboundQueuedTransfer { - bump: ctx.bumps["enqueued"], + accs.inbox_item.set_inner(InboxItem { + bump: ctx.bumps["inbox_item"], amount, recipient_address, release_timestamp, diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 1db036698..2c47540d7 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -1,7 +1,7 @@ -use anchor_lang::{prelude::*, solana_program::clock}; +use anchor_lang::prelude::*; use anchor_spl::token::{self, Token}; -use crate::{config::Config, error::NTTError, queue::inbound::InboundQueuedTransfer}; +use crate::{config::Config, error::NTTError, queue::inbox::InboxItem}; #[derive(Accounts)] pub struct ReleaseInbound<'info> { @@ -12,16 +12,16 @@ pub struct ReleaseInbound<'info> { #[account( mut, - constraint = !enqueued.released @ NTTError::TransferAlreadyRedeemed, + constraint = !inbox_item.released @ NTTError::TransferAlreadyRedeemed, )] - pub enqueued: Account<'info, InboundQueuedTransfer>, + pub inbox_item: Account<'info, InboxItem>, #[account( mut, - address = enqueued.recipient_address, + address = inbox_item.recipient_address, )] - /// CHECK: the address is checked to match th recipient address in the - /// queued transfer + /// CHECK: the address is checked to match the recipient address in the + /// inbox item pub recipient: AccountInfo<'info>, #[account( @@ -45,9 +45,9 @@ pub struct ReleaseInbound<'info> { pub struct ReleaseInboundArgs {} pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) -> Result<()> { - let enqueued = &mut ctx.accounts.enqueued; + let inbox_item = &mut ctx.accounts.inbox_item; - enqueued.release()?; + inbox_item.release()?; token::mint_to( CpiContext::new_with_signer( @@ -59,6 +59,6 @@ pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) }, &[&[b"token_minter", &[ctx.bumps["token_minter"]]]], ), - enqueued.amount.denormalize(ctx.accounts.mint.decimals), + inbox_item.amount.denormalize(ctx.accounts.mint.decimals), ) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 4cdc2dccb..430bf0287 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -1,4 +1,4 @@ -use anchor_lang::{prelude::*, solana_program::clock}; +use anchor_lang::prelude::*; use wormhole_anchor_sdk::wormhole; use wormhole_io::TypePrefixedPayload; @@ -7,7 +7,7 @@ use crate::{ config::Config, error::NTTError, messages::{ManagerMessage, NativeTokenTransfer}, - queue::outbound::OutboundQueuedTransfer, + queue::outbox::OutboxItem, }; #[derive(Accounts)] @@ -19,13 +19,13 @@ pub struct ReleaseOutbound<'info> { #[account( mut, - constraint = !enqueued.released @ NTTError::MessageAlreadySent, + constraint = !outbox_item.released @ NTTError::MessageAlreadySent, )] - pub enqueued: Account<'info, OutboundQueuedTransfer>, + pub outbox_item: Account<'info, OutboxItem>, #[account( mut, - seeds = [b"message", enqueued.sequence.to_be_bytes().as_ref()], + seeds = [b"message", outbox_item.sequence.to_be_bytes().as_ref()], bump, )] /// CHECK: initialized and written to by wormhole core bridge @@ -70,16 +70,16 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg let batch_id = 0; // TODO: record endpoint position - accs.enqueued.release()?; + accs.outbox_item.release()?; let message: ManagerMessage = ManagerMessage { chain_id: accs.config.chain_id, - sequence: accs.enqueued.sequence, + sequence: accs.outbox_item.sequence, sender: accs.emitter.key().to_bytes().to_vec(), payload: NativeTokenTransfer { - amount: accs.enqueued.amount, - to: accs.enqueued.recipient_address.clone(), - to_chain: accs.enqueued.recipient_chain, + amount: accs.outbox_item.amount, + to: accs.outbox_item.recipient_address.clone(), + to_chain: accs.outbox_item.recipient_chain, }, }; @@ -101,7 +101,7 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg &[b"emitter", &[ctx.bumps["emitter"]]], &[ b"message", - accs.enqueued.sequence.to_be_bytes().as_ref(), + accs.outbox_item.sequence.to_be_bytes().as_ref(), &[ctx.bumps["wormhole_message"]], ], ], diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 40f006770..e4e86710b 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -5,7 +5,7 @@ use crate::{ chain_id::ChainId, config::Mode, normalized_amount::NormalizedAmount, - queue::outbound::{OutboundQueuedTransfer, OutboundRateLimit}, + queue::outbox::{OutboxItem, OutboxRateLimit}, }; // this will burn the funds and create an account that either allows sending the @@ -46,20 +46,20 @@ pub struct Transfer<'info> { #[account( init, payer = payer, - space = 8 + OutboundQueuedTransfer::INIT_SPACE, + space = 8 + OutboxItem::INIT_SPACE, // TODO: this creates a race condition // when two people try to send a transfer at the same time // only one of them can claim the sequence number. // Not sure if there's a way around this, the PDA has to be seeded by // something unique to this transfer, so I think it has to include the // sequence number (everything else can be the same) - seeds = [OutboundQueuedTransfer::SEED_PREFIX, seq.sequence.to_be_bytes().as_ref()], + seeds = [OutboxItem::SEED_PREFIX, seq.sequence.to_be_bytes().as_ref()], bump, )] - pub enqueued: Account<'info, OutboundQueuedTransfer>, + pub outbox_item: Account<'info, OutboxItem>, #[account(mut)] - pub rate_limit: Account<'info, OutboundRateLimit>, + pub rate_limit: Account<'info, OutboxRateLimit>, pub system_program: Program<'info, System>, } @@ -112,8 +112,8 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { let sequence = accs.seq.next(); - accs.enqueued.set_inner(OutboundQueuedTransfer { - bump: ctx.bumps["enqueued"], + accs.outbox_item.set_inner(OutboxItem { + bump: ctx.bumps["outbox_item"], sequence, amount, recipient_chain, diff --git a/solana/programs/example-native-token-transfers/src/queue/inbound.rs b/solana/programs/example-native-token-transfers/src/queue/inbox.rs similarity index 77% rename from solana/programs/example-native-token-transfers/src/queue/inbound.rs rename to solana/programs/example-native-token-transfers/src/queue/inbox.rs index b3c016355..30413dd85 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbound.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbox.rs @@ -6,8 +6,8 @@ use super::rate_limit::RateLimitState; #[account] #[derive(InitSpace)] -// TODO: maybe remove the queue from the name? it's not always queued -pub struct InboundQueuedTransfer { +// TODO: generalise this to arbitrary inbound messages (via a generic parameter in place of amount and recipient info) +pub struct InboxItem { pub bump: u8, pub amount: NormalizedAmount, pub recipient_address: Pubkey, @@ -15,8 +15,8 @@ pub struct InboundQueuedTransfer { pub released: bool, } -impl InboundQueuedTransfer { - pub const SEED_PREFIX: &'static [u8] = b"inbound_queue"; +impl InboxItem { + pub const SEED_PREFIX: &'static [u8] = b"inbox_item"; pub fn release(&mut self) -> Result<()> { let now = Clock::get()?.unix_timestamp; @@ -45,5 +45,5 @@ pub struct InboundRateLimit { } impl InboundRateLimit { - pub const SEED_PREFIX: &'static [u8] = b"inbound_rate_limit"; + pub const SEED_PREFIX: &'static [u8] = b"inbox_rate_limit"; } diff --git a/solana/programs/example-native-token-transfers/src/queue/mod.rs b/solana/programs/example-native-token-transfers/src/queue/mod.rs index 645643297..3a721b406 100644 --- a/solana/programs/example-native-token-transfers/src/queue/mod.rs +++ b/solana/programs/example-native-token-transfers/src/queue/mod.rs @@ -1,3 +1,3 @@ -pub mod outbound; -pub mod inbound; +pub mod inbox; +pub mod outbox; pub mod rate_limit; diff --git a/solana/programs/example-native-token-transfers/src/queue/outbound.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs similarity index 77% rename from solana/programs/example-native-token-transfers/src/queue/outbound.rs rename to solana/programs/example-native-token-transfers/src/queue/outbox.rs index fc3fe64bf..c0d448ca4 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbound.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -6,8 +6,8 @@ use super::rate_limit::RateLimitState; #[account] #[derive(InitSpace)] -// TODO: maybe remove the queue from the name? it's not always queued -pub struct OutboundQueuedTransfer { +// TODO: generalise this to arbitrary outbound messages (via a generic parameter in place of amount and recipient info) +pub struct OutboxItem { pub bump: u8, pub sequence: u64, pub amount: NormalizedAmount, @@ -21,8 +21,8 @@ pub struct OutboundQueuedTransfer { pub released: bool, } -impl OutboundQueuedTransfer { - pub const SEED_PREFIX: &'static [u8] = b"outbound_queue"; +impl OutboxItem { + pub const SEED_PREFIX: &'static [u8] = b"outbox_item"; pub fn release(&mut self) -> Result<()> { let now = clock::Clock::get()?.unix_timestamp; @@ -42,12 +42,12 @@ impl OutboundQueuedTransfer { #[account] #[derive(InitSpace)] -pub struct OutboundRateLimit { +pub struct OutboxRateLimit { pub rate_limit: RateLimitState, } /// Global rate limit for all outbound transfers to all chains. /// NOTE: only one of this account can exist, so we don't need to check the PDA. -impl OutboundRateLimit { - pub const SEED_PREFIX: &'static [u8] = b"outbound_rate_limit"; +impl OutboxRateLimit { + pub const SEED_PREFIX: &'static [u8] = b"outbox_rate_limit"; } From e78302d822d116df5faf45446dc9f9f207d1094b Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 5 Feb 2024 13:26:24 +0100 Subject: [PATCH 06/90] solana: use anchor 0.29.0 --- solana/Cargo.lock | 273 ++++++++++++++---- .../example-native-token-transfers/Cargo.toml | 6 +- .../src/instructions/initialize.rs | 2 +- .../src/instructions/redeem.rs | 2 +- .../src/instructions/release_inbound.rs | 2 +- .../src/instructions/release_outbound.rs | 4 +- .../src/instructions/transfer.rs | 2 +- 7 files changed, 220 insertions(+), 71 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 9fb605ae7..6d0854bc4 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -73,64 +73,58 @@ dependencies = [ [[package]] name = "anchor-attribute-access-control" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faa5be5b72abea167f87c868379ba3c2be356bfca9e6f474fd055fa0f7eeb4f2" +checksum = "e5f619f1d04f53621925ba8a2e633ba5a6081f2ae14758cbb67f38fd823e0a3e" dependencies = [ "anchor-syn", - "anyhow", "proc-macro2", "quote", - "regex", "syn 1.0.109", ] [[package]] name = "anchor-attribute-account" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f468970344c7c9f9d03b4da854fd7c54f21305059f53789d0045c1dd803f0018" +checksum = "e7f2a3e1df4685f18d12a943a9f2a7456305401af21a07c9fe076ef9ecd6e400" dependencies = [ "anchor-syn", - "anyhow", "bs58 0.5.0", "proc-macro2", "quote", - "rustversion", "syn 1.0.109", ] [[package]] name = "anchor-attribute-constant" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59948e7f9ef8144c2aefb3f32a40c5fce2798baeec765ba038389e82301017ef" +checksum = "9423945cb55627f0b30903288e78baf6f62c6c8ab28fb344b6b25f1ffee3dca7" dependencies = [ "anchor-syn", - "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-error" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc753c9d1c7981cb8948cf7e162fb0f64558999c0413058e2d43df1df5448086" +checksum = "93ed12720033cc3c3bf3cfa293349c2275cd5ab99936e33dd4bf283aaad3e241" dependencies = [ "anchor-syn", - "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-event" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38b4e172ba1b52078f53fdc9f11e3dc0668ad27997838a0aad2d148afac8c97" +checksum = "eef4dc0371eba2d8c8b54794b0b0eb786a234a559b77593d6f80825b6d2c77a2" dependencies = [ "anchor-syn", - "anyhow", "proc-macro2", "quote", "syn 1.0.109", @@ -138,25 +132,34 @@ dependencies = [ [[package]] name = "anchor-attribute-program" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eebd21543606ab61e2d83d9da37d24d3886a49f390f9c43a1964735e8c0f0d5" +checksum = "b18c4f191331e078d4a6a080954d1576241c29c56638783322a18d308ab27e4f" dependencies = [ "anchor-syn", - "anyhow", - "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "anchor-derive-accounts" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec4720d899b3686396cced9508f23dab420f1308344456ec78ef76f98fda42af" +checksum = "5de10d6e9620d3bcea56c56151cad83c5992f50d5960b3a9bebc4a50390ddc3c" dependencies = [ "anchor-syn", - "anyhow", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-serde" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4e2e5be518ec6053d90a2a7f26843dbee607583c779e6c8395951b9739bdfbe" +dependencies = [ + "anchor-syn", + "borsh-derive-internal 0.10.3", "proc-macro2", "quote", "syn 1.0.109", @@ -164,9 +167,9 @@ dependencies = [ [[package]] name = "anchor-derive-space" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f495e85480bd96ddeb77b71d499247c7d4e8b501e75ecb234e9ef7ae7bd6552a" +checksum = "1ecc31d19fa54840e74b7a979d44bcea49d70459de846088a1d71e87ba53c419" dependencies = [ "proc-macro2", "quote", @@ -175,9 +178,9 @@ dependencies = [ [[package]] name = "anchor-lang" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d2d4b20100f1310a774aba3471ef268e5c4ba4d5c28c0bbe663c2658acbc414" +checksum = "35da4785497388af0553586d55ebdc08054a8b1724720ef2749d313494f2b8ad" dependencies = [ "anchor-attribute-access-control", "anchor-attribute-account", @@ -186,6 +189,7 @@ dependencies = [ "anchor-attribute-event", "anchor-attribute-program", "anchor-derive-accounts", + "anchor-derive-serde", "anchor-derive-space", "arrayref", "base64 0.13.1", @@ -199,9 +203,9 @@ dependencies = [ [[package]] name = "anchor-spl" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78f860599da1c2354e7234c768783049eb42e2f54509ecfc942d2e0076a2da7b" +checksum = "6c4fd6e43b2ca6220d2ef1641539e678bfc31b6cc393cf892b373b5997b6a39a" dependencies = [ "anchor-lang", "solana-program", @@ -212,9 +216,9 @@ dependencies = [ [[package]] name = "anchor-syn" -version = "0.28.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a125e4b0cc046cfec58f5aa25038e34cf440151d58f0db3afc55308251fe936d" +checksum = "d9101b84702fed2ea57bd22992f75065da5648017135b844283a2f6d74f27825" dependencies = [ "anyhow", "bs58 0.5.0", @@ -1241,6 +1245,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "num-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "num-integer" version = "0.1.45" @@ -1262,39 +1277,39 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.11" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" +checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" dependencies = [ - "num_enum_derive 0.5.11", + "num_enum_derive 0.6.1", ] [[package]] name = "num_enum" -version = "0.6.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.6.1", + "num_enum_derive 0.7.2", ] [[package]] name = "num_enum_derive" -version = "0.5.11" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" +checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.48", ] [[package]] name = "num_enum_derive" -version = "0.6.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", @@ -1826,7 +1841,7 @@ dependencies = [ "log", "memoffset", "num-bigint", - "num-derive", + "num-derive 0.3.3", "num-traits", "parking_lot", "rand 0.7.3", @@ -1875,7 +1890,7 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive", + "num-derive 0.3.3", "num-traits", "num_enum 0.6.1", "pbkdf2 0.11.0", @@ -1930,7 +1945,7 @@ dependencies = [ "itertools", "lazy_static", "merlin", - "num-derive", + "num-derive 0.3.3", "num-traits", "rand 0.7.3", "serde", @@ -1945,13 +1960,13 @@ dependencies = [ [[package]] name = "spl-associated-token-account" -version = "1.1.3" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" +checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3" dependencies = [ "assert_matches", - "borsh 0.9.3", - "num-derive", + "borsh 0.10.3", + "num-derive 0.4.1", "num-traits", "solana-program", "spl-token", @@ -1959,48 +1974,182 @@ dependencies = [ "thiserror", ] +[[package]] +name = "spl-discriminator" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.48", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.48", + "thiserror", +] + [[package]] name = "spl-memo" -version = "3.0.1" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-pod" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079" +dependencies = [ + "borsh 0.10.3", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error", +] + +[[package]] +name = "spl-program-error" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" +dependencies = [ + "num-derive 0.4.1", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.48", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" +checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9" dependencies = [ + "bytemuck", "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", ] [[package]] name = "spl-token" -version = "3.5.0" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" +checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.3.3", "num-traits", - "num_enum 0.5.11", + "num_enum 0.6.1", "solana-program", "thiserror", ] [[package]] name = "spl-token-2022" -version = "0.6.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" +checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86" dependencies = [ "arrayref", "bytemuck", - "num-derive", + "num-derive 0.4.1", "num-traits", - "num_enum 0.5.11", + "num_enum 0.7.2", "solana-program", "solana-zk-token-sdk", "spl-memo", + "spl-pod", "spl-token", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", "thiserror", ] +[[package]] +name = "spl-token-metadata-interface" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" +dependencies = [ + "borsh 0.10.3", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", +] + +[[package]] +name = "spl-type-length-value" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator", + "spl-pod", + "spl-program-error", +] + [[package]] name = "strsim" version = "0.10.0" @@ -2352,9 +2501,9 @@ dependencies = [ [[package]] name = "wormhole-anchor-sdk" -version = "0.1.0-alpha.2" +version = "0.29.0-alpha.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd5b515d674db0fd7b562bc6ecd1b3e35912e6a9a101f486513b8978205736a2" +checksum = "4470d5c9ac1072a8b15e2361dfa4f919849f1c41a6004941f6df49d628a797f0" dependencies = [ "anchor-lang", "anchor-spl", diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index 2c1347d53..ba9ce4008 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -18,7 +18,7 @@ default = [] [dependencies] ahash = "=0.8.6" -anchor-lang = "0.28.0" -anchor-spl = "0.28.0" -wormhole-anchor-sdk = "0.1.0-alpha.2" +anchor-lang = "0.29.0" +anchor-spl = "0.29.0" +wormhole-anchor-sdk = "0.29.0-alpha.1" wormhole-io = "0.1.3" diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index bb2e74f16..1c9421127 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -31,7 +31,7 @@ pub struct InitializeArgs { pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> { ctx.accounts.config.set_inner(crate::config::Config { - bump: ctx.bumps["config"], + bump: ctx.bumps.config, mint: ctx.accounts.mint.key(), mode: crate::config::Mode::Locking, chain_id: ChainId { id: args.chain_id }, diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index b5269e95f..89174d23b 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -99,7 +99,7 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); accs.inbox_item.set_inner(InboxItem { - bump: ctx.bumps["inbox_item"], + bump: ctx.bumps.inbox_item, amount, recipient_address, release_timestamp, diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 2c47540d7..419dd5409 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -57,7 +57,7 @@ pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) to: ctx.accounts.recipient.clone(), authority: ctx.accounts.mint_authority.clone(), }, - &[&[b"token_minter", &[ctx.bumps["token_minter"]]]], + &[&[b"token_minter", &[ctx.bumps.mint_authority]]], ), inbox_item.amount.denormalize(ctx.accounts.mint.decimals), ) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 430bf0287..6c57be812 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -98,11 +98,11 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg system_program: accs.system_program.to_account_info(), }, &[ - &[b"emitter", &[ctx.bumps["emitter"]]], + &[b"emitter", &[ctx.bumps.emitter]], &[ b"message", accs.outbox_item.sequence.to_be_bytes().as_ref(), - &[ctx.bumps["wormhole_message"]], + &[ctx.bumps.wormhole_message], ], ], ), diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index e4e86710b..949e60ed1 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -113,7 +113,7 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { let sequence = accs.seq.next(); accs.outbox_item.set_inner(OutboxItem { - bump: ctx.bumps["outbox_item"], + bump: ctx.bumps.outbox_item, sequence, amount, recipient_chain, From edad44e4da843ecb82bb6233febdd805e5fde137 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 5 Feb 2024 13:28:46 +0100 Subject: [PATCH 07/90] solana: Cargo.toml: use resolver = 2 --- solana/Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/solana/Cargo.toml b/solana/Cargo.toml index ef17a63c0..f39770481 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -2,6 +2,7 @@ members = [ "programs/*" ] +resolver = "2" [profile.release] overflow-checks = true From 724f6e7acd12bb744a455aa32065c38b88b37ba6 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 5 Feb 2024 13:33:39 +0100 Subject: [PATCH 08/90] solana: use anchor idl build feature this supports generic types so the IDL now builds --- solana/Cargo.lock | 1 + solana/programs/example-native-token-transfers/Cargo.toml | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 6d0854bc4..fab999eae 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -191,6 +191,7 @@ dependencies = [ "anchor-derive-accounts", "anchor-derive-serde", "anchor-derive-space", + "anchor-syn", "arrayref", "base64 0.13.1", "bincode", diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index ba9ce4008..d1f14dbf7 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -14,6 +14,10 @@ no-idl = [] no-log-ix-name = [] cpi = ["no-entrypoint"] default = [] +idl-build = [ + "anchor-lang/idl-build", + "anchor-spl/idl-build" +] [dependencies] ahash = "=0.8.6" From 2fa3e9b3d575fceb80cfd0063255907a6059f57a Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 5 Feb 2024 17:05:38 +0100 Subject: [PATCH 09/90] solana: support token22 (via anchor interfaces) --- .../src/instructions/initialize.rs | 3 ++- .../src/instructions/release_inbound.rs | 10 +++++----- .../src/instructions/transfer.rs | 12 ++++++------ 3 files changed, 13 insertions(+), 12 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 1c9421127..f5bbb3e78 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -1,4 +1,5 @@ use anchor_lang::prelude::*; +use anchor_spl::token_interface; use crate::chain_id::ChainId; @@ -18,7 +19,7 @@ pub struct Initialize<'info> { pub config: Account<'info, crate::config::Config>, #[account()] - pub mint: Account<'info, anchor_spl::token::Mint>, + pub mint: InterfaceAccount<'info, token_interface::Mint>, system_program: Program<'info, System>, // TODO: initialize rate limits diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 419dd5409..d9b64dd63 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -1,5 +1,5 @@ use anchor_lang::prelude::*; -use anchor_spl::token::{self, Token}; +use anchor_spl::token_interface; use crate::{config::Config, error::NTTError, queue::inbox::InboxItem}; @@ -29,7 +29,7 @@ pub struct ReleaseInbound<'info> { address = config.mint, )] /// CHECK: the mint address matches the config - pub mint: Account<'info, anchor_spl::token::Mint>, + pub mint: InterfaceAccount<'info, token_interface::Mint>, #[account( seeds = [b"token_minter"], @@ -38,7 +38,7 @@ pub struct ReleaseInbound<'info> { /// CHECK: the token program checks if this indeed the right authority for the mint pub mint_authority: AccountInfo<'info>, - pub token_program: Program<'info, Token>, + pub token_program: Interface<'info, token_interface::TokenInterface>, } #[derive(AnchorSerialize, AnchorDeserialize)] @@ -49,10 +49,10 @@ pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) inbox_item.release()?; - token::mint_to( + token_interface::mint_to( CpiContext::new_with_signer( ctx.accounts.token_program.to_account_info(), - token::MintTo { + token_interface::MintTo { mint: ctx.accounts.mint.to_account_info(), to: ctx.accounts.recipient.clone(), authority: ctx.accounts.mint_authority.clone(), diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 949e60ed1..d4d359457 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -1,5 +1,5 @@ use anchor_lang::{prelude::*, solana_program::clock}; -use anchor_spl::token::{self, Token, TokenAccount}; +use anchor_spl::token_interface; use crate::{ chain_id::ChainId, @@ -22,19 +22,19 @@ pub struct Transfer<'info> { address = config.mint, )] /// CHECK: the mint address matches the config - pub mint: Account<'info, anchor_spl::token::Mint>, + pub mint: InterfaceAccount<'info, token_interface::Mint>, #[account( mut, token::mint = config.mint, )] - pub from: Account<'info, TokenAccount>, + pub from: InterfaceAccount<'info, token_interface::TokenAccount>, /// authority to burn the tokens (owner) /// CHECK: this is checked by the token program pub from_authority: Signer<'info>, - pub token_program: Program<'info, Token>, + pub token_program: Interface<'info, token_interface::TokenInterface>, #[account( mut, @@ -81,10 +81,10 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { } = args; match accs.config.mode { - Mode::Burning => token::burn( + Mode::Burning => token_interface::burn( CpiContext::new( accs.token_program.to_account_info(), - token::Burn { + token_interface::Burn { mint: accs.mint.to_account_info(), from: accs.from.to_account_info(), authority: accs.from_authority.to_account_info(), From e9b9088a5ea61bdc7f1d93c35acd0883491c95b6 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 5 Feb 2024 23:07:41 +0000 Subject: [PATCH 10/90] solana: transfer: don't burn dust --- .../src/instructions/transfer.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index d4d359457..9639d3dce 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -80,6 +80,8 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { recipient_address, } = args; + let amount = NormalizedAmount::normalize(amount, accs.mint.decimals); + match accs.config.mode { Mode::Burning => token_interface::burn( CpiContext::new( @@ -90,7 +92,8 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { authority: accs.from_authority.to_account_info(), }, ), - amount, + // TODO: should we revert if we have dust? + amount.denormalize(accs.mint.decimals), )?, // TODO: implement locking mode. it will require a custody account. @@ -105,8 +108,6 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { let now = clock::Clock::get()?.unix_timestamp; - let amount = NormalizedAmount::normalize(amount, accs.mint.decimals); - // consume the rate limit, or delay the transfer if it's outside the limit let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); From 1dba4b24d00eef8fc1c6f21874d0838340ae4389 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 7 Feb 2024 23:25:31 +0000 Subject: [PATCH 11/90] solana: implement limit update logic --- .../src/clock.rs | 27 ++++ .../src/instructions/redeem.rs | 6 +- .../src/instructions/transfer.rs | 6 +- .../example-native-token-transfers/src/lib.rs | 1 + .../src/normalized_amount.rs | 17 ++- .../src/queue/rate_limit.rs | 115 +++++++++++++++--- 6 files changed, 149 insertions(+), 23 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/src/clock.rs diff --git a/solana/programs/example-native-token-transfers/src/clock.rs b/solana/programs/example-native-token-transfers/src/clock.rs new file mode 100644 index 000000000..25d95fe30 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/clock.rs @@ -0,0 +1,27 @@ +//! This module provides a function to get the current Unix timestamp. +//! During testing, the timestamp can be overridden using the [`set_test_timestamp`] function. +//! When not testing, the timestamp is retrieved from the Solana runtime. +//! This makes it easy to unit test functions that depend on the current time +//! without having to instantiate a Solana runtime. + +#[cfg(not(test))] +use anchor_lang::prelude::*; + +use anchor_lang::solana_program::clock::UnixTimestamp; + +#[cfg(test)] +static TEST_TIMESTAMP: std::sync::Mutex = std::sync::Mutex::new(0); + +pub fn current_timestamp() -> UnixTimestamp { + #[cfg(not(test))] + return anchor_lang::solana_program::clock::Clock::get() + .unwrap() + .unix_timestamp; + #[cfg(test)] + return *TEST_TIMESTAMP.lock().unwrap(); +} + +#[cfg(test)] +pub fn set_test_timestamp(timestamp: UnixTimestamp) { + *TEST_TIMESTAMP.lock().unwrap() = timestamp; +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 89174d23b..e5e602e5d 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -1,4 +1,4 @@ -use anchor_lang::{prelude::*, solana_program::clock}; +use anchor_lang::prelude::*; use wormhole_anchor_sdk::wormhole::{self, PostedVaa, PostedVaaData}; @@ -94,9 +94,7 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let recipient_address = Pubkey::try_from(message.payload.to).map_err(|_| NTTError::InvalidRecipientAddress)?; - let now = clock::Clock::get()?.unix_timestamp; - - let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); + let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(amount); accs.inbox_item.set_inner(InboxItem { bump: ctx.bumps.inbox_item, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 9639d3dce..33a174326 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -1,4 +1,4 @@ -use anchor_lang::{prelude::*, solana_program::clock}; +use anchor_lang::prelude::*; use anchor_spl::token_interface; use crate::{ @@ -106,10 +106,8 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { Mode::Locking => todo!(), } - let now = clock::Clock::get()?.unix_timestamp; - // consume the rate limit, or delay the transfer if it's outside the limit - let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(now, amount); + let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(amount); let sequence = accs.seq.next(); diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 44260a9e1..8bc28b341 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -1,6 +1,7 @@ use anchor_lang::prelude::*; pub mod chain_id; +pub mod clock; pub mod config; pub mod error; pub mod instructions; diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index ad3e82475..7f50f100c 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -74,6 +74,22 @@ impl Sub for NormalizedAmount { } impl NormalizedAmount { + pub fn new(amount: u64) -> Self { + Self { amount } + } + + pub fn saturating_sub(self, rhs: Self) -> Self { + Self { + amount: self.amount.saturating_sub(rhs.amount), + } + } + + pub fn saturating_add(self, rhs: Self) -> Self { + Self { + amount: self.amount.saturating_add(rhs.amount), + } + } + fn scaling_factor(decimals: u8) -> u64 { if decimals > NORMALIZED_DECIMALS { 10u64.pow((decimals - NORMALIZED_DECIMALS).into()) @@ -92,7 +108,6 @@ impl NormalizedAmount { self.amount * Self::scaling_factor(decimals) } - #[cfg(test)] pub fn amount(&self) -> u64 { self.amount } diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index 1f2b148c1..c70e7ef2d 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -1,6 +1,6 @@ use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}; -use crate::normalized_amount::NormalizedAmount; +use crate::{clock::current_timestamp, normalized_amount::NormalizedAmount}; #[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace)] pub struct RateLimitState { @@ -15,23 +15,36 @@ pub struct RateLimitState { /// capacity. Transactions that exceeded the capacity do not count, they are /// just delayed. last_tx_timestamp: i64, - /// The rate per second at which the capacity is refilled. - refill_rate: NormalizedAmount, } impl RateLimitState { pub const RATE_LIMIT_DURATION: i64 = 60 * 60 * 24; // 24 hours - /// Returns the capacity of the rate limiter at the given timestamp. - pub fn capacity_at(&self, now: UnixTimestamp) -> NormalizedAmount { + /// Returns the capacity of the rate limiter. + pub fn capacity(&self) -> NormalizedAmount { + let now = current_timestamp(); assert!(self.last_tx_timestamp <= now); + let limit = self.limit.amount() as u128; + + // morally this is + // capacity = old_capacity + (limit / rate_limit_duration) * time_passed + // + // but we instead write it as + // capacity = old_capacity + (limit * time_passed) / rate_limit_duration + // as it has better numerical stability. + // + // This can overflow u64 (if limit is close to u64 max), so we use u128 + // for the intermediate calculations. Theoretically it could also overflow u128 + // if limit == time_passed == u64 max, but that will take a very long time. + let calculated_capacity = { - let time_passed = (now - self.last_tx_timestamp) as u64; - self.capacity_at_last_tx + (self.refill_rate * time_passed) + let time_passed = now - self.last_tx_timestamp; + self.capacity_at_last_tx.amount() as u128 + + time_passed as u128 * limit / (Self::RATE_LIMIT_DURATION as u128) }; - calculated_capacity.min(self.limit) + NormalizedAmount::new(calculated_capacity.min(limit) as u64) } /// Computes the timestamp at which the given amount can be consumed. @@ -39,12 +52,9 @@ impl RateLimitState { /// returned, and the remaining capacity is reduced. /// Otherwise, the timestamp at which the capacity will be available is /// returned. - pub fn consume_or_delay( - &mut self, - now: UnixTimestamp, - amount: NormalizedAmount, - ) -> UnixTimestamp { - let capacity = self.capacity_at(now); + pub fn consume_or_delay(&mut self, amount: NormalizedAmount) -> UnixTimestamp { + let now = current_timestamp(); + let capacity = self.capacity(); if capacity >= amount { self.capacity_at_last_tx = capacity - amount; self.last_tx_timestamp = now; @@ -53,4 +63,81 @@ impl RateLimitState { now + Self::RATE_LIMIT_DURATION } } + + pub fn set_limit(&mut self, limit: NormalizedAmount) { + let old_limit = self.limit; + let current_capacity = self.capacity(); + + self.limit = limit; + + let new_capacity: NormalizedAmount; + if old_limit > limit { + // decrease in limit, + let diff = old_limit - limit; + new_capacity = current_capacity.saturating_sub(diff); + } else { + // increase in limit + let diff = limit - old_limit; + new_capacity = current_capacity.saturating_add(diff); + } + + self.capacity_at_last_tx = new_capacity.min(limit); + self.last_tx_timestamp = current_timestamp(); + } +} + +#[cfg(test)] +mod tests { + use crate::clock::set_test_timestamp; + + use super::*; + + #[test] + fn test_rate_limit() { + let mut rate_limit_state = RateLimitState { + limit: NormalizedAmount::new(100_000), + capacity_at_last_tx: NormalizedAmount::new(100_000), + last_tx_timestamp: current_timestamp(), + }; + + // consume 30k. should be immediate + let immediately = rate_limit_state.consume_or_delay(NormalizedAmount::new(30_000)); + + assert_eq!(immediately, current_timestamp()); + assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(70_000)); + assert_eq!(rate_limit_state.limit, NormalizedAmount::new(100_000)); // unchanged + assert_eq!(rate_limit_state.last_tx_timestamp, current_timestamp()); + + // replenish 1/4 of the limit, i.e. 25k + set_test_timestamp(current_timestamp() + RateLimitState::RATE_LIMIT_DURATION / 4); + + assert_eq!( + rate_limit_state.capacity(), + NormalizedAmount::new(70_000 + 25_000) + ); + + // now consume 150k. should be delayed + let tomorrow = rate_limit_state.consume_or_delay(NormalizedAmount::new(150_000)); + assert_eq!( + tomorrow, + current_timestamp() + RateLimitState::RATE_LIMIT_DURATION + ); + + // the limit is not changed, since the tx was delayed + assert_eq!( + rate_limit_state.capacity(), + NormalizedAmount::new(70_000 + 25_000) + ); + + // now set the limit to 50k + rate_limit_state.set_limit(NormalizedAmount::new(50_000)); + + // this decreases the capacity by 50k, to 45k + assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(45_000)); + + // now set the limit to 100k + rate_limit_state.set_limit(NormalizedAmount::new(100_000)); + + assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(95_000)); + } } From 1543ceee56905868d4a3f6cfff746e6a2cbcf2f8 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 8 Feb 2024 00:20:02 +0000 Subject: [PATCH 12/90] solana: admin functionality --- .../src/config.rs | 4 + .../src/instructions/admin.rs | 168 ++++++++++++++++++ .../src/instructions/initialize.rs | 4 + .../src/instructions/mod.rs | 2 + .../src/instructions/redeem.rs | 14 +- .../example-native-token-transfers/src/lib.rs | 30 ++++ .../src/queue/inbox.rs | 19 +- .../src/queue/outbox.rs | 25 ++- .../src/sibling.rs | 14 ++ 9 files changed, 262 insertions(+), 18 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/src/instructions/admin.rs create mode 100644 solana/programs/example-native-token-transfers/src/sibling.rs diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 1ba9ff044..6577632be 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -6,6 +6,10 @@ use crate::chain_id::ChainId; #[derive(InitSpace)] pub struct Config { pub bump: u8, + /// Owner of the program. + pub owner: Pubkey, + /// Pending next owner (before claiming ownership). + pub pending_owner: Option, /// Mint address of the token managed by this program. pub mint: Pubkey, /// The mode that this program is running in. This is used to determine diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs new file mode 100644 index 000000000..0460fec6b --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -0,0 +1,168 @@ +use anchor_lang::prelude::*; +use anchor_spl::token_interface; + +use crate::{ + chain_id::ChainId, + config::Config, + normalized_amount::NormalizedAmount, + queue::{inbox::InboundRateLimit, outbox::OutboxRateLimit}, + sibling::Sibling, +}; + +// * Transfer ownership + +#[derive(Accounts)] +pub struct TransferOwnership<'info> { + #[account( + has_one = owner, + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct TransferOwnershipArgs { + pub new_owner: Pubkey, +} + +pub fn transfer_ownership( + ctx: Context, + args: TransferOwnershipArgs, +) -> Result<()> { + ctx.accounts.config.pending_owner = Some(args.new_owner); + Ok(()) +} + +// * Claim ownership + +#[derive(Accounts)] +pub struct ClaimOwnership<'info> { + #[account( + mut, + constraint = config.pending_owner == Some(new_owner.key()) + )] + pub config: Account<'info, Config>, + + pub new_owner: Signer<'info>, +} + +pub fn claim_ownership(ctx: Context) -> Result<()> { + ctx.accounts.config.pending_owner = None; + ctx.accounts.config.owner = ctx.accounts.new_owner.key(); + Ok(()) +} + +// * Set siblings +// TODO: update siblings? should that be a separate instruction? take timestamp +// for modification? (for total ordering) + +#[derive(Accounts)] +#[instruction(args: SetSiblingArgs)] +pub struct SetSibling<'info> { + #[account( + has_one = owner, + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + init, + space = 8 + Sibling::INIT_SPACE, + payer = payer, + seeds = [Sibling::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], + bump + )] + pub sibling: Account<'info, Sibling>, + + pub system_program: Program<'info, System>, +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct SetSiblingArgs { + pub chain_id: ChainId, + pub address: [u8; 32], +} + +pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> { + ctx.accounts.sibling.set_inner(Sibling { + bump: ctx.bumps.sibling, + address: args.address, + }); + Ok(()) +} + +// * Limit rate adjustment +#[derive(Accounts)] +pub struct SetOutboundLimit<'info> { + #[account( + constraint = config.owner == owner.key() + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, + + #[account(mut)] + pub rate_limit: Account<'info, OutboxRateLimit>, + + #[account( + constraint = mint.key() == config.mint + )] + pub mint: InterfaceAccount<'info, token_interface::Mint>, +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct SetOutboundLimitArgs { + pub limit: u64, +} + +pub fn set_outbound_limit( + ctx: Context, + args: SetOutboundLimitArgs, +) -> Result<()> { + let limit = NormalizedAmount::normalize(args.limit, ctx.accounts.mint.decimals); + ctx.accounts.rate_limit.set_limit(limit); + Ok(()) +} + +#[derive(Accounts)] +#[instruction(args: SetInboundLimitArgs)] +pub struct SetInboundLimit<'info> { + #[account( + constraint = config.owner == owner.key() + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, + + #[account( + mut, + seeds = [ + InboundRateLimit::SEED_PREFIX, + args.chain_id.id.to_be_bytes().as_ref() + ], + bump = rate_limit.bump + )] + pub rate_limit: Account<'info, InboundRateLimit>, + + #[account( + constraint = mint.key() == config.mint + )] + pub mint: InterfaceAccount<'info, token_interface::Mint>, +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct SetInboundLimitArgs { + pub limit: u64, + pub chain_id: ChainId, +} + +pub fn set_inbound_limit(ctx: Context, args: SetInboundLimitArgs) -> Result<()> { + let limit = NormalizedAmount::normalize(args.limit, ctx.accounts.mint.decimals); + ctx.accounts.rate_limit.set_limit(limit); + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index f5bbb3e78..69fac2545 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -9,6 +9,8 @@ pub struct Initialize<'info> { #[account(mut)] pub payer: Signer<'info>, + pub owner: Signer<'info>, + #[account( init, space = 8 + crate::config::Config::INIT_SPACE, @@ -36,6 +38,8 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> mint: ctx.accounts.mint.key(), mode: crate::config::Mode::Locking, chain_id: ChainId { id: args.chain_id }, + owner: ctx.accounts.owner.key(), + pending_owner: None, }); Ok(()) diff --git a/solana/programs/example-native-token-transfers/src/instructions/mod.rs b/solana/programs/example-native-token-transfers/src/instructions/mod.rs index ae35f471c..84c453533 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/mod.rs @@ -1,9 +1,11 @@ +pub mod admin; pub mod initialize; pub mod redeem; pub mod release_inbound; pub mod release_outbound; pub mod transfer; +pub use admin::*; pub use initialize::*; pub use redeem::*; pub use release_inbound::*; diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index e5e602e5d..1af6efbb3 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -7,21 +7,9 @@ use crate::{ error::NTTError, messages::{ManagerMessage, NativeTokenTransfer}, queue::inbox::{InboundRateLimit, InboxItem}, + sibling::Sibling, }; -#[account] -#[derive(InitSpace)] -/// A sibling on another chain. Stored in a PDA seeded by the chain id. -pub struct Sibling { - pub bump: u8, - // TODO: variable address length? - pub address: [u8; 32], -} - -impl Sibling { - pub const SEED_PREFIX: &'static [u8] = b"sibling"; -} - #[derive(Accounts)] pub struct Redeem<'info> { #[account(mut)] diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 8bc28b341..1c141d913 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -9,6 +9,7 @@ pub mod messages; pub mod normalized_amount; pub mod queue; pub mod sequence; +pub mod sibling; use instructions::*; @@ -41,4 +42,33 @@ pub mod example_native_token_transfers { pub fn release_inbound(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { instructions::release_inbound(ctx, args) } + + pub fn transfer_ownership( + ctx: Context, + args: TransferOwnershipArgs, + ) -> Result<()> { + instructions::transfer_ownership(ctx, args) + } + + pub fn claim_ownership(ctx: Context) -> Result<()> { + instructions::claim_ownership(ctx) + } + + pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> { + instructions::set_sibling(ctx, args) + } + + pub fn set_outbound_limit( + ctx: Context, + args: SetOutboundLimitArgs, + ) -> Result<()> { + instructions::set_outbound_limit(ctx, args) + } + + pub fn set_inbound_limit( + ctx: Context, + args: SetInboundLimitArgs, + ) -> Result<()> { + instructions::set_inbound_limit(ctx, args) + } } diff --git a/solana/programs/example-native-token-transfers/src/queue/inbox.rs b/solana/programs/example-native-token-transfers/src/queue/inbox.rs index 30413dd85..794e29c1b 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbox.rs @@ -1,6 +1,8 @@ +use std::ops::{Deref, DerefMut}; + use anchor_lang::prelude::*; -use crate::{error::NTTError, normalized_amount::NormalizedAmount}; +use crate::{clock::current_timestamp, error::NTTError, normalized_amount::NormalizedAmount}; use super::rate_limit::RateLimitState; @@ -19,7 +21,7 @@ impl InboxItem { pub const SEED_PREFIX: &'static [u8] = b"inbox_item"; pub fn release(&mut self) -> Result<()> { - let now = Clock::get()?.unix_timestamp; + let now = current_timestamp(); if self.release_timestamp > now { return Err(NTTError::ReleaseTimestampNotReached.into()); @@ -47,3 +49,16 @@ pub struct InboundRateLimit { impl InboundRateLimit { pub const SEED_PREFIX: &'static [u8] = b"inbox_rate_limit"; } + +impl Deref for InboundRateLimit { + type Target = RateLimitState; + fn deref(&self) -> &Self::Target { + &self.rate_limit + } +} + +impl DerefMut for InboundRateLimit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.rate_limit + } +} diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index c0d448ca4..7b1d22b5b 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -1,6 +1,11 @@ -use anchor_lang::{prelude::*, solana_program::clock}; +use std::ops::{Deref, DerefMut}; -use crate::{chain_id::ChainId, error::NTTError, normalized_amount::NormalizedAmount}; +use anchor_lang::prelude::*; + +use crate::{ + chain_id::ChainId, clock::current_timestamp, error::NTTError, + normalized_amount::NormalizedAmount, +}; use super::rate_limit::RateLimitState; @@ -25,7 +30,7 @@ impl OutboxItem { pub const SEED_PREFIX: &'static [u8] = b"outbox_item"; pub fn release(&mut self) -> Result<()> { - let now = clock::Clock::get()?.unix_timestamp; + let now = current_timestamp(); if self.release_timestamp > now { return Err(NTTError::ReleaseTimestampNotReached.into()); } @@ -51,3 +56,17 @@ pub struct OutboxRateLimit { impl OutboxRateLimit { pub const SEED_PREFIX: &'static [u8] = b"outbox_rate_limit"; } + +impl Deref for OutboxRateLimit { + type Target = RateLimitState; + + fn deref(&self) -> &Self::Target { + &self.rate_limit + } +} + +impl DerefMut for OutboxRateLimit { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.rate_limit + } +} diff --git a/solana/programs/example-native-token-transfers/src/sibling.rs b/solana/programs/example-native-token-transfers/src/sibling.rs new file mode 100644 index 000000000..c2bfd8af9 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/sibling.rs @@ -0,0 +1,14 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +/// A sibling on another chain. Stored in a PDA seeded by the chain id. +pub struct Sibling { + pub bump: u8, + // TODO: variable address length? + pub address: [u8; 32], +} + +impl Sibling { + pub const SEED_PREFIX: &'static [u8] = b"sibling"; +} From ceadb25e955ee5fd0bab81b62f31389409046431 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 8 Feb 2024 12:04:02 +0000 Subject: [PATCH 13/90] solana: add ability to pause contract --- .../src/config.rs | 26 +++++++++++++++++++ .../src/instructions/admin.rs | 16 ++++++++++++ .../src/instructions/initialize.rs | 1 + .../src/instructions/redeem.rs | 4 +-- .../src/instructions/release_inbound.rs | 4 +-- .../src/instructions/release_outbound.rs | 4 +-- .../src/instructions/transfer.rs | 4 +-- 7 files changed, 51 insertions(+), 8 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 6577632be..86ab6465c 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -1,3 +1,5 @@ +use std::ops::{Deref, DerefMut}; + use anchor_lang::prelude::*; use crate::chain_id::ChainId; @@ -19,12 +21,36 @@ pub struct Config { /// hardcode this so that the program is deployable on any potential SVM /// forks. pub chain_id: ChainId, + /// Pause the program. This is useful for upgrades and other maintenance. + pub paused: bool, } impl Config { pub const SEED_PREFIX: &'static [u8] = b"config"; } +#[derive(Accounts)] +pub struct NotPausedConfig<'info> { + #[account( + constraint = !config.paused + )] + config: Account<'info, Config>, +} + +impl<'info> Deref for NotPausedConfig<'info> { + type Target = Config; + + fn deref(&self) -> &Self::Target { + &self.config + } +} + +impl<'info> DerefMut for NotPausedConfig<'info> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.config + } +} + #[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone)] pub enum Mode { Burning, diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 0460fec6b..3cb2bf30f 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -166,3 +166,19 @@ pub fn set_inbound_limit(ctx: Context, args: SetInboundLimitArg ctx.accounts.rate_limit.set_limit(limit); Ok(()) } + +// * Pausing +#[derive(Accounts)] +pub struct SetPaused<'info> { + #[account( + has_one = owner, + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, +} + +pub fn set_paused(ctx: Context, paused: bool) -> Result<()> { + ctx.accounts.config.paused = paused; + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 69fac2545..21f094977 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -40,6 +40,7 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> chain_id: ChainId { id: args.chain_id }, owner: ctx.accounts.owner.key(), pending_owner: None, + paused: false, }); Ok(()) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 1af6efbb3..5ad954460 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -3,7 +3,7 @@ use anchor_lang::prelude::*; use wormhole_anchor_sdk::wormhole::{self, PostedVaa, PostedVaaData}; use crate::{ - config::Config, + config::*, error::NTTError, messages::{ManagerMessage, NativeTokenTransfer}, queue::inbox::{InboundRateLimit, InboxItem}, @@ -15,7 +15,7 @@ pub struct Redeem<'info> { #[account(mut)] pub payer: Signer<'info>, - pub config: Account<'info, Config>, + pub config: NotPausedConfig<'info>, #[account( seeds = [Sibling::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index d9b64dd63..6a0c08fc3 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -1,14 +1,14 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; -use crate::{config::Config, error::NTTError, queue::inbox::InboxItem}; +use crate::{config::*, error::NTTError, queue::inbox::InboxItem}; #[derive(Accounts)] pub struct ReleaseInbound<'info> { #[account(mut)] pub payer: Signer<'info>, - pub config: Account<'info, Config>, + pub config: NotPausedConfig<'info>, #[account( mut, diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 6c57be812..ebf1583a0 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -4,7 +4,7 @@ use wormhole_anchor_sdk::wormhole; use wormhole_io::TypePrefixedPayload; use crate::{ - config::Config, + config::*, error::NTTError, messages::{ManagerMessage, NativeTokenTransfer}, queue::outbox::OutboxItem, @@ -15,7 +15,7 @@ pub struct ReleaseOutbound<'info> { #[account(mut)] pub payer: Signer<'info>, - pub config: Account<'info, Config>, + pub config: NotPausedConfig<'info>, #[account( mut, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 33a174326..f933ac007 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -3,7 +3,7 @@ use anchor_spl::token_interface; use crate::{ chain_id::ChainId, - config::Mode, + config::*, normalized_amount::NormalizedAmount, queue::outbox::{OutboxItem, OutboxRateLimit}, }; @@ -15,7 +15,7 @@ pub struct Transfer<'info> { #[account(mut)] pub payer: Signer<'info>, - pub config: Account<'info, crate::config::Config>, + pub config: NotPausedConfig<'info>, #[account( mut, From 0dc731d87788910feac139f154cb343ea33fddac Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 9 Feb 2024 15:19:20 +0000 Subject: [PATCH 14/90] solana: send fee to wh fee collector --- .../src/instructions/release_outbound.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index ebf1583a0..f9c9bc104 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -83,6 +83,19 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg }, }; + if accs.wormhole_bridge.fee() > 0 { + anchor_lang::system_program::transfer( + CpiContext::new( + accs.system_program.to_account_info(), + anchor_lang::system_program::Transfer { + from: accs.payer.to_account_info(), + to: accs.wormhole_fee_collector.to_account_info(), + }, + ), + accs.wormhole_bridge.fee(), + )?; + } + wormhole::post_message( CpiContext::new_with_signer( accs.wormhole_program.to_account_info(), From 935d881f5e333c84c21438abf9a062da18f74e8f Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 9 Feb 2024 15:21:12 +0000 Subject: [PATCH 15/90] solana: update message serialisation --- .../src/instructions/release_outbound.rs | 2 +- .../src/instructions/transfer.rs | 2 +- .../src/messages.rs | 42 +++++++++---------- .../src/queue/outbox.rs | 4 +- 4 files changed, 22 insertions(+), 28 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index f9c9bc104..7c8216e68 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -75,7 +75,7 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg let message: ManagerMessage = ManagerMessage { chain_id: accs.config.chain_id, sequence: accs.outbox_item.sequence, - sender: accs.emitter.key().to_bytes().to_vec(), + sender: accs.emitter.key().to_bytes(), payload: NativeTokenTransfer { amount: accs.outbox_item.amount, to: accs.outbox_item.recipient_address.clone(), diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index f933ac007..005b8bc4b 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -68,7 +68,7 @@ pub struct Transfer<'info> { pub struct TransferArgs { pub amount: u64, pub recipient_chain: ChainId, - pub recipient_address: Vec, + pub recipient_address: [u8; 32], } // TODO: fees for relaying? diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index b8eb0b527..b35b95e78 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -11,7 +11,7 @@ use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; pub struct ManagerMessage { pub chain_id: ChainId, pub sequence: u64, - pub sender: Vec, + pub sender: [u8; 32], pub payload: A, } @@ -29,9 +29,7 @@ impl Readable for ManagerMessage { { let chain_id = Readable::read(reader)?; let sequence = Readable::read(reader)?; - let sender_len = u16::read(reader)?; - let mut sender = vec![0u8; sender_len.into()]; - reader.read_exact(&mut sender)?; + let sender = Readable::read(reader)?; let payload = A::read_payload(reader)?; Ok(Self { @@ -47,8 +45,6 @@ impl Writeable for ManagerMessage { fn written_size(&self) -> usize { ChainId::SIZE.unwrap() + u64::SIZE.unwrap() - + u8::SIZE.unwrap() - + u16::SIZE.unwrap() // sender length + self.sender.len() + self.payload.written_size() } @@ -66,7 +62,6 @@ impl Writeable for ManagerMessage { chain_id.write(writer)?; sequence.write(writer)?; - (sender.len() as u16).write(writer)?; writer.write_all(sender)?; A::write_payload(payload, writer) } @@ -74,17 +69,18 @@ impl Writeable for ManagerMessage { #[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] pub struct NativeTokenTransfer { - // TODO: should we use a U256 library here? might be pointless since we're - // only looking at the least significant 64 bits (last since BE), and - // requring the rest to be 0 pub amount: NormalizedAmount, - pub to: Vec, // TODO: shouldn't we put this in the outer message? pub to_chain: ChainId, + pub to: [u8; 32], +} + +impl NativeTokenTransfer { + const PREFIX: [u8; 4] = [0x99, 0x4E, 0x54, 0x54]; } impl TypePrefixedPayload for NativeTokenTransfer { - const TYPE: Option = Some(1); + const TYPE: Option = None; } impl Readable for NativeTokenTransfer { @@ -95,15 +91,17 @@ impl Readable for NativeTokenTransfer { Self: Sized, R: io::Read, { - // read 0s - let zeros: [u64; 3] = Readable::read(reader)?; - assert_eq!(zeros, [0, 0, 0]); + let prefix: [u8; 4] = Readable::read(reader)?; + if prefix != Self::PREFIX { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid prefix for NativeTokenTransfer", + )); + } let amount = Readable::read(reader)?; - let to_len = u16::read(reader)?; - let mut to = vec![0u8; to_len.into()]; - reader.read_exact(&mut to)?; let to_chain = Readable::read(reader)?; + let to = Readable::read(reader)?; Ok(Self { amount, @@ -115,7 +113,8 @@ impl Readable for NativeTokenTransfer { impl Writeable for NativeTokenTransfer { fn written_size(&self) -> usize { - <[u64; 4]>::SIZE.unwrap() + Self::PREFIX.len() + + NormalizedAmount::SIZE.unwrap() + u16::SIZE.unwrap() // payload length + self.to.len() + ChainId::SIZE.unwrap() @@ -131,11 +130,8 @@ impl Writeable for NativeTokenTransfer { to_chain, } = self; - // write 0s - [0u64; 3].write(writer)?; - + Self::PREFIX.write(writer)?; amount.write(writer)?; - (to.len() as u16).write(writer)?; writer.write_all(to)?; to_chain.write(writer)?; diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 7b1d22b5b..113600381 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -17,9 +17,7 @@ pub struct OutboxItem { pub sequence: u64, pub amount: NormalizedAmount, pub recipient_chain: ChainId, - // TODO: revise max length? - #[max_len(120)] - pub recipient_address: Vec, + pub recipient_address: [u8; 32], pub release_timestamp: i64, // TODO: change this to a bitmap to store which endpoints have released the // transfer? (multi endpoint) From 2a58c96afdf8687d18c06425b8d90f84d8323db9 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 9 Feb 2024 15:21:47 +0000 Subject: [PATCH 16/90] solana: initialise sequence and outbound rate limit --- .../src/instructions/initialize.rs | 40 +++++++++++++++++-- .../src/queue/rate_limit.rs | 8 ++++ 2 files changed, 45 insertions(+), 3 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 21f094977..3752e2d64 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -1,7 +1,12 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; -use crate::chain_id::ChainId; +use crate::{ + chain_id::ChainId, + normalized_amount::NormalizedAmount, + queue::{outbox::OutboxRateLimit, rate_limit::RateLimitState}, + sequence::Sequence, +}; // TODO: upgradeability #[derive(Accounts)] @@ -23,25 +28,54 @@ pub struct Initialize<'info> { #[account()] pub mint: InterfaceAccount<'info, token_interface::Mint>, + #[account( + init, + payer = payer, + space = 8 + Sequence::INIT_SPACE, + seeds = [Sequence::SEED_PREFIX], + bump, + )] + pub seq: Account<'info, Sequence>, + + #[account( + init, + payer = payer, + space = 8 + OutboxRateLimit::INIT_SPACE, + seeds = [OutboxRateLimit::SEED_PREFIX], + bump, + )] + pub rate_limit: Account<'info, OutboxRateLimit>, + system_program: Program<'info, System>, - // TODO: initialize rate limits } #[derive(AnchorSerialize, AnchorDeserialize)] pub struct InitializeArgs { pub chain_id: u16, + pub limit: u64, } pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> { ctx.accounts.config.set_inner(crate::config::Config { bump: ctx.bumps.config, mint: ctx.accounts.mint.key(), - mode: crate::config::Mode::Locking, + mode: crate::config::Mode::Burning, chain_id: ChainId { id: args.chain_id }, owner: ctx.accounts.owner.key(), pending_owner: None, paused: false, }); + ctx.accounts.seq.set_inner(Sequence { + bump: ctx.bumps.seq, + sequence: 0, + }); + + let decimals: u8 = ctx.accounts.mint.decimals; + + ctx.accounts.rate_limit.set_inner(OutboxRateLimit { + rate_limit: RateLimitState::new(NormalizedAmount::normalize(args.limit, decimals)), + }); + Ok(()) } diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index c70e7ef2d..df4656b5a 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -18,6 +18,14 @@ pub struct RateLimitState { } impl RateLimitState { + pub fn new(limit: NormalizedAmount) -> Self { + Self { + limit, + capacity_at_last_tx: limit, + last_tx_timestamp: 0, + } + } + pub const RATE_LIMIT_DURATION: i64 = 60 * 60 * 24; // 24 hours /// Returns the capacity of the rate limiter. From 7923d2773de67726954709116dbdcf3a82e287cf Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 9 Feb 2024 19:37:07 +0000 Subject: [PATCH 17/90] solana: implement lock/unlock --- .../src/error.rs | 2 + .../src/instructions/release_inbound.rs | 83 ++++++++++--- .../src/instructions/transfer.rs | 117 ++++++++++++++---- .../example-native-token-transfers/src/lib.rs | 18 ++- 4 files changed, 178 insertions(+), 42 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index 701a99ef2..5e8b6024a 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -15,4 +15,6 @@ pub enum NTTError { TransferAlreadyRedeemed, #[msg("MessageAlreadySent")] MessageAlreadySent, + #[msg("InvalidMode")] + InvalidMode, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 6a0c08fc3..569ff590e 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -31,34 +31,85 @@ pub struct ReleaseInbound<'info> { /// CHECK: the mint address matches the config pub mint: InterfaceAccount<'info, token_interface::Mint>, + pub token_program: Interface<'info, token_interface::TokenInterface>, +} + +// Burn/mint + +#[derive(Accounts)] +pub struct ReleaseInboundMint<'info> { + common: ReleaseInbound<'info>, + #[account( seeds = [b"token_minter"], bump, )] /// CHECK: the token program checks if this indeed the right authority for the mint pub mint_authority: AccountInfo<'info>, +} - pub token_program: Interface<'info, token_interface::TokenInterface>, +pub fn release_inbound_mint(ctx: Context) -> Result<()> { + let inbox_item = &mut ctx.accounts.common.inbox_item; + + inbox_item.release()?; + + match ctx.accounts.common.config.mode { + Mode::Burning => token_interface::mint_to( + CpiContext::new_with_signer( + ctx.accounts.common.token_program.to_account_info(), + token_interface::MintTo { + mint: ctx.accounts.common.mint.to_account_info(), + to: ctx.accounts.common.recipient.clone(), + authority: ctx.accounts.mint_authority.clone(), + }, + &[&[b"token_minter", &[ctx.bumps.mint_authority]]], + ), + inbox_item + .amount + .denormalize(ctx.accounts.common.mint.decimals), + ), + Mode::Locking => Err(NTTError::InvalidMode.into()), + } } -#[derive(AnchorSerialize, AnchorDeserialize)] -pub struct ReleaseInboundArgs {} +// Lock/unlock + +#[derive(Accounts)] +pub struct ReleaseInboundUnlock<'info> { + common: ReleaseInbound<'info>, + + #[account( + seeds = [b"custody_authoity"], + bump, + )] + pub custody_authority: AccountInfo<'info>, + + /// CHECK: the token program checks if this indeed the right authority for the mint + pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, +} -pub fn release_inbound(ctx: Context, _args: ReleaseInboundArgs) -> Result<()> { - let inbox_item = &mut ctx.accounts.inbox_item; +pub fn release_inbound_unlock(ctx: Context) -> Result<()> { + let inbox_item = &mut ctx.accounts.common.inbox_item; inbox_item.release()?; - token_interface::mint_to( - CpiContext::new_with_signer( - ctx.accounts.token_program.to_account_info(), - token_interface::MintTo { - mint: ctx.accounts.mint.to_account_info(), - to: ctx.accounts.recipient.clone(), - authority: ctx.accounts.mint_authority.clone(), - }, - &[&[b"token_minter", &[ctx.bumps.mint_authority]]], + match ctx.accounts.common.config.mode { + Mode::Burning => Err(NTTError::InvalidMode.into()), + Mode::Locking => token_interface::transfer_checked( + CpiContext::new_with_signer( + ctx.accounts.common.token_program.to_account_info(), + token_interface::TransferChecked { + from: ctx.accounts.custody.to_account_info(), + to: ctx.accounts.common.recipient.clone(), + authority: ctx.accounts.custody_authority.clone(), + mint: ctx.accounts.common.mint.to_account_info(), + }, + &[&[b"custody_authority", &[ctx.bumps.custody_authority]]], + ), + inbox_item + .amount + .denormalize(ctx.accounts.common.mint.decimals), + ctx.accounts.common.mint.decimals, ), - inbox_item.amount.denormalize(ctx.accounts.mint.decimals), - ) + } } diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 005b8bc4b..c2775e1f5 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -4,6 +4,7 @@ use anchor_spl::token_interface; use crate::{ chain_id::ChainId, config::*, + error::NTTError, normalized_amount::NormalizedAmount, queue::outbox::{OutboxItem, OutboxRateLimit}, }; @@ -26,7 +27,7 @@ pub struct Transfer<'info> { #[account( mut, - token::mint = config.mint, + token::mint = mint, )] pub from: InterfaceAccount<'info, token_interface::TokenAccount>, @@ -71,8 +72,15 @@ pub struct TransferArgs { pub recipient_address: [u8; 32], } +// Burn/mint + +#[derive(Accounts)] +pub struct TransferBurn<'info> { + pub common: Transfer<'info>, +} + // TODO: fees for relaying? -pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { +pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<()> { let accs = ctx.accounts; let TransferArgs { amount, @@ -80,39 +88,106 @@ pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { recipient_address, } = args; - let amount = NormalizedAmount::normalize(amount, accs.mint.decimals); + let amount = NormalizedAmount::normalize(amount, accs.common.mint.decimals); - match accs.config.mode { + match accs.common.config.mode { Mode::Burning => token_interface::burn( CpiContext::new( - accs.token_program.to_account_info(), + accs.common.token_program.to_account_info(), token_interface::Burn { - mint: accs.mint.to_account_info(), - from: accs.from.to_account_info(), - authority: accs.from_authority.to_account_info(), + mint: accs.common.mint.to_account_info(), + from: accs.common.from.to_account_info(), + authority: accs.common.from_authority.to_account_info(), }, ), // TODO: should we revert if we have dust? - amount.denormalize(accs.mint.decimals), + amount.denormalize(accs.common.mint.decimals), )?, + Mode::Locking => return Err(NTTError::InvalidMode.into()), + } + + insert_into_outbox( + &mut accs.common, + amount, + ctx.bumps.common.outbox_item, + recipient_chain, + recipient_address, + ) +} + +// Lock/unlock - // TODO: implement locking mode. it will require a custody account. - // we could take it as optional, and just ignore it in burning mode. - // Alternatively we could do conditional compilation (feature flags), but - // that would complicate testing and leak more into the interface. - // Another option is to introduce a different instruction for locking - // and burning, and just error if the wrong one is used. Again, that leaks - // into the client interface. - Mode::Locking => todo!(), +#[derive(Accounts)] +pub struct TransferLock<'info> { + pub common: Transfer<'info>, + + #[account( + seeds = [b"custody_authority"], + bump, + )] + pub custody_authority: AccountInfo<'info>, + + #[account( + mut, + token::mint = common.mint, + token::authority = custody_authority, + )] + pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, +} + +// TODO: fees for relaying? +// TODO: factor out common bits +pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<()> { + let accs = ctx.accounts; + let TransferArgs { + amount, + recipient_chain, + recipient_address, + } = args; + + let amount = NormalizedAmount::normalize(amount, accs.common.mint.decimals); + + match accs.common.config.mode { + Mode::Burning => return Err(NTTError::InvalidMode.into()), + Mode::Locking => token_interface::transfer_checked( + CpiContext::new( + accs.common.token_program.to_account_info(), + token_interface::TransferChecked { + from: accs.common.from.to_account_info(), + to: accs.custody.to_account_info(), + authority: accs.common.from_authority.to_account_info(), + mint: accs.common.mint.to_account_info(), + }, + ), + // TODO: should we revert if we have dust? + amount.denormalize(accs.common.mint.decimals), + accs.common.mint.decimals, + )?, } + insert_into_outbox( + &mut accs.common, + amount, + ctx.bumps.common.outbox_item, + recipient_chain, + recipient_address, + ) +} + +fn insert_into_outbox( + common: &mut Transfer<'_>, + amount: NormalizedAmount, + outbox_item_bump: u8, + recipient_chain: ChainId, + recipient_address: [u8; 32], +) -> Result<()> { // consume the rate limit, or delay the transfer if it's outside the limit - let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(amount); + let release_timestamp = common.rate_limit.rate_limit.consume_or_delay(amount); - let sequence = accs.seq.next(); + let sequence = common.seq.next(); - accs.outbox_item.set_inner(OutboxItem { - bump: ctx.bumps.outbox_item, + common.outbox_item.set_inner(OutboxItem { + bump: outbox_item_bump, sequence, amount, recipient_chain, diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 1c141d913..8aa34ea49 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -13,7 +13,7 @@ pub mod sibling; use instructions::*; -declare_id!("CjjU6T8ZowfYmK3bDrb5k8TdTSQxCMnhZz1xFXUwUYsn"); +declare_id!("J61k8wq3PMLWmpR8meNxuQWfjHdzf8W1TZrFHoock9ou"); #[program] pub mod example_native_token_transfers { @@ -24,8 +24,12 @@ pub mod example_native_token_transfers { instructions::initialize(ctx, args) } - pub fn transfer(ctx: Context, args: TransferArgs) -> Result<()> { - instructions::transfer(ctx, args) + pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<()> { + instructions::transfer_burn(ctx, args) + } + + pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<()> { + instructions::transfer_lock(ctx, args) } pub fn release_outbound( @@ -39,8 +43,12 @@ pub mod example_native_token_transfers { instructions::redeem(ctx, args) } - pub fn release_inbound(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { - instructions::release_inbound(ctx, args) + pub fn release_inbound_mint(ctx: Context) -> Result<()> { + instructions::release_inbound_mint(ctx) + } + + pub fn release_inbound_unlock(ctx: Context) -> Result<()> { + instructions::release_inbound_unlock(ctx) } pub fn transfer_ownership( From ae55cf9462432d99725d030e2075f3da7a4d7fac Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 9 Feb 2024 20:05:43 +0000 Subject: [PATCH 18/90] solana: store decimals of normalised amount this allows correct denormalisation when the decimals are less than 8 --- .../src/normalized_amount.rs | 72 +++++++------------ .../src/queue/rate_limit.rs | 33 +++++---- 2 files changed, 44 insertions(+), 61 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index 7f50f100c..9fc38c059 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -7,10 +7,7 @@ //! The functions [`normalize`] and [`denormalize`] take care of convertion to/from //! this type given the original amount's decimals. -use std::{ - io, - ops::{Add, Mul, Sub}, -}; +use std::{io, ops::Sub}; use anchor_lang::prelude::*; use wormhole_io::{Readable, Writeable}; @@ -30,82 +27,61 @@ pub const NORMALIZED_DECIMALS: u8 = 8; InitSpace, )] pub struct NormalizedAmount { - amount: u64, -} - -impl Mul for NormalizedAmount { - type Output = Self; - - fn mul(self, rhs: Self) -> Self::Output { - Self { - amount: self.amount * rhs.amount, - } - } -} - -impl Mul for NormalizedAmount { - type Output = Self; - - fn mul(self, rhs: u64) -> Self::Output { - Self { - amount: self.amount * rhs, - } - } -} - -impl Add for NormalizedAmount { - type Output = Self; - - fn add(self, rhs: Self) -> Self::Output { - Self { - amount: self.amount + rhs.amount, - } - } + pub amount: u64, + pub decimals: u8, } impl Sub for NormalizedAmount { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { + assert_eq!(self.decimals, rhs.decimals); Self { amount: self.amount - rhs.amount, + decimals: self.decimals, } } } impl NormalizedAmount { - pub fn new(amount: u64) -> Self { - Self { amount } + pub fn new(amount: u64, decimals: u8) -> Self { + Self { amount, decimals } } pub fn saturating_sub(self, rhs: Self) -> Self { + assert_eq!(self.decimals, rhs.decimals); Self { amount: self.amount.saturating_sub(rhs.amount), + decimals: self.decimals, } } pub fn saturating_add(self, rhs: Self) -> Self { + assert_eq!(self.decimals, rhs.decimals); Self { amount: self.amount.saturating_add(rhs.amount), + decimals: self.decimals, } } - fn scaling_factor(decimals: u8) -> u64 { - if decimals > NORMALIZED_DECIMALS { - 10u64.pow((decimals - NORMALIZED_DECIMALS).into()) + fn scaling_factor(orig_decimals: u8, norm_decimals: u8) -> u64 { + if orig_decimals > norm_decimals { + 10u64.pow((orig_decimals - norm_decimals).into()) } else { 1 } } - pub fn normalize(amount: u64, decimals: u8) -> NormalizedAmount { + pub fn normalize(amount: u64, from_decimals: u8) -> NormalizedAmount { + let to_decimals = NORMALIZED_DECIMALS.min(from_decimals); Self { - amount: amount / Self::scaling_factor(decimals), + amount: amount / Self::scaling_factor(from_decimals, to_decimals), + decimals: to_decimals, } } - pub fn denormalize(&self, decimals: u8) -> u64 { - self.amount * Self::scaling_factor(decimals) + pub fn denormalize(&self, to_decimals: u8) -> u64 { + self.amount * Self::scaling_factor(to_decimals, self.decimals) } pub fn amount(&self) -> u64 { @@ -114,15 +90,16 @@ impl NormalizedAmount { } impl Readable for NormalizedAmount { - const SIZE: Option = Some(8); + const SIZE: Option = Some(1 + 8); fn read(reader: &mut R) -> io::Result where Self: Sized, R: io::Read, { + let decimals = Readable::read(reader)?; let amount = Readable::read(reader)?; - Ok(Self { amount }) + Ok(Self { amount, decimals }) } } @@ -131,7 +108,8 @@ impl Writeable for NormalizedAmount { where W: io::Write, { - let NormalizedAmount { amount } = self; + let NormalizedAmount { amount, decimals } = self; + decimals.write(writer)?; amount.write(writer)?; Ok(()) diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index df4656b5a..ced1ea462 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -46,13 +46,18 @@ impl RateLimitState { // for the intermediate calculations. Theoretically it could also overflow u128 // if limit == time_passed == u64 max, but that will take a very long time. + let NormalizedAmount { + amount: capacity_at_last_tx, + decimals, + } = self.capacity_at_last_tx; + let calculated_capacity = { let time_passed = now - self.last_tx_timestamp; - self.capacity_at_last_tx.amount() as u128 + capacity_at_last_tx as u128 + time_passed as u128 * limit / (Self::RATE_LIMIT_DURATION as u128) }; - NormalizedAmount::new(calculated_capacity.min(limit) as u64) + NormalizedAmount::new(calculated_capacity.min(limit) as u64, decimals) } /// Computes the timestamp at which the given amount can be consumed. @@ -103,17 +108,17 @@ mod tests { #[test] fn test_rate_limit() { let mut rate_limit_state = RateLimitState { - limit: NormalizedAmount::new(100_000), - capacity_at_last_tx: NormalizedAmount::new(100_000), + limit: NormalizedAmount::new(100_000, 8), + capacity_at_last_tx: NormalizedAmount::new(100_000, 8), last_tx_timestamp: current_timestamp(), }; // consume 30k. should be immediate - let immediately = rate_limit_state.consume_or_delay(NormalizedAmount::new(30_000)); + let immediately = rate_limit_state.consume_or_delay(NormalizedAmount::new(30_000, 8)); assert_eq!(immediately, current_timestamp()); - assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(70_000)); - assert_eq!(rate_limit_state.limit, NormalizedAmount::new(100_000)); // unchanged + assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(70_000, 8)); + assert_eq!(rate_limit_state.limit, NormalizedAmount::new(100_000, 8)); // unchanged assert_eq!(rate_limit_state.last_tx_timestamp, current_timestamp()); // replenish 1/4 of the limit, i.e. 25k @@ -121,11 +126,11 @@ mod tests { assert_eq!( rate_limit_state.capacity(), - NormalizedAmount::new(70_000 + 25_000) + NormalizedAmount::new(70_000 + 25_000, 8) ); // now consume 150k. should be delayed - let tomorrow = rate_limit_state.consume_or_delay(NormalizedAmount::new(150_000)); + let tomorrow = rate_limit_state.consume_or_delay(NormalizedAmount::new(150_000, 8)); assert_eq!( tomorrow, current_timestamp() + RateLimitState::RATE_LIMIT_DURATION @@ -134,18 +139,18 @@ mod tests { // the limit is not changed, since the tx was delayed assert_eq!( rate_limit_state.capacity(), - NormalizedAmount::new(70_000 + 25_000) + NormalizedAmount::new(70_000 + 25_000, 8) ); // now set the limit to 50k - rate_limit_state.set_limit(NormalizedAmount::new(50_000)); + rate_limit_state.set_limit(NormalizedAmount::new(50_000, 8)); // this decreases the capacity by 50k, to 45k - assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(45_000)); + assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(45_000, 8)); // now set the limit to 100k - rate_limit_state.set_limit(NormalizedAmount::new(100_000)); + rate_limit_state.set_limit(NormalizedAmount::new(100_000, 8)); - assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(95_000)); + assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(95_000, 8)); } } From 6c9854913be8055691098897478c5d9d7c3c9413 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 9 Feb 2024 23:11:07 +0000 Subject: [PATCH 19/90] solana: wrap messages in endpoint message --- .../src/instructions/redeem.rs | 17 +-- .../src/instructions/release_outbound.rs | 24 ++-- .../src/messages.rs | 125 +++++++++++++++++- 3 files changed, 144 insertions(+), 22 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 5ad954460..7b6fabd3c 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -5,7 +5,7 @@ use wormhole_anchor_sdk::wormhole::{self, PostedVaa, PostedVaaData}; use crate::{ config::*, error::NTTError, - messages::{ManagerMessage, NativeTokenTransfer}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, queue::inbox::{InboundRateLimit, InboxItem}, sibling::Sibling, }; @@ -29,16 +29,13 @@ pub struct Redeem<'info> { seeds::program = wormhole::program::ID, bump, // check that the VAA's emitter agrees with what's in the message - constraint = vaa.emitter_chain() == vaa.message().chain_id.id @ NTTError::InvalidChainId, - // TODO: once the manager payload has sending manager address, check - // that too (against VAA emitter) - // constraint = vaa.emitter_address() == vaa.message().payload.from @ NTTError::InvalidEmitter, + constraint = vaa.emitter_chain() == vaa.message().manager_payload.chain_id.id @ NTTError::InvalidChainId, // check that the messages is targeted to this chain - constraint = vaa.message().payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + constraint = vaa.message().manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, // NOTE: we don't replay protect VAAs. Instead, we replay protect // executing the messages themselves with the [`released`] flag. )] - pub vaa: Account<'info, PostedVaa>>, + pub vaa: Account<'info, PostedVaa>>, #[account( init, @@ -46,8 +43,8 @@ pub struct Redeem<'info> { space = 8 + InboxItem::INIT_SPACE, seeds = [ InboxItem::SEED_PREFIX, - vaa.message().chain_id.id.to_be_bytes().as_ref(), - vaa.message().sequence.to_be_bytes().as_ref(), + vaa.message().manager_payload.chain_id.id.to_be_bytes().as_ref(), + vaa.message().manager_payload.sequence.to_be_bytes().as_ref(), ], bump, )] @@ -76,7 +73,7 @@ pub struct RedeemArgs {} pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let accs = ctx.accounts; - let message: ManagerMessage = accs.vaa.message().clone(); + let message: ManagerMessage = accs.vaa.message().manager_payload.clone(); let amount = message.payload.amount; let recipient_address = diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 7c8216e68..930bc6ac2 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -6,7 +6,7 @@ use wormhole_io::TypePrefixedPayload; use crate::{ config::*, error::NTTError, - messages::{ManagerMessage, NativeTokenTransfer}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, queue::outbox::OutboxItem, }; @@ -72,16 +72,18 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg // TODO: record endpoint position accs.outbox_item.release()?; - let message: ManagerMessage = ManagerMessage { - chain_id: accs.config.chain_id, - sequence: accs.outbox_item.sequence, - sender: accs.emitter.key().to_bytes(), - payload: NativeTokenTransfer { - amount: accs.outbox_item.amount, - to: accs.outbox_item.recipient_address.clone(), - to_chain: accs.outbox_item.recipient_chain, - }, - }; + let message: EndpointMessage = + EndpointMessage::new(ManagerMessage { + chain_id: accs.config.chain_id, + sequence: accs.outbox_item.sequence, + source_manager: accs.outbox_item.to_account_info().owner.to_bytes(), + sender: accs.emitter.key().to_bytes(), + payload: NativeTokenTransfer { + amount: accs.outbox_item.amount, + to: accs.outbox_item.recipient_address.clone(), + to_chain: accs.outbox_item.recipient_chain, + }, + }); if accs.wormhole_bridge.fee() > 0 { anchor_lang::system_program::transfer( diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index b35b95e78..01f482b06 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -1,5 +1,6 @@ use anchor_lang::prelude::*; -use std::io; +use core::fmt; +use std::{io, marker::PhantomData, collections::HashMap}; use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; @@ -11,6 +12,8 @@ use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; pub struct ManagerMessage { pub chain_id: ChainId, pub sequence: u64, + // TODO: check sibling registration at the manager level + pub source_manager: [u8; 32], pub sender: [u8; 32], pub payload: A, } @@ -29,12 +32,14 @@ impl Readable for ManagerMessage { { let chain_id = Readable::read(reader)?; let sequence = Readable::read(reader)?; + let source_manager = Readable::read(reader)?; let sender = Readable::read(reader)?; let payload = A::read_payload(reader)?; Ok(Self { chain_id, sequence, + source_manager, sender, payload, }) @@ -45,6 +50,7 @@ impl Writeable for ManagerMessage { fn written_size(&self) -> usize { ChainId::SIZE.unwrap() + u64::SIZE.unwrap() + + self.source_manager.len() + self.sender.len() + self.payload.written_size() } @@ -56,12 +62,14 @@ impl Writeable for ManagerMessage { let ManagerMessage { chain_id, sequence, + source_manager, sender, payload, } = self; chain_id.write(writer)?; sequence.write(writer)?; + writer.write_all(source_manager)?; writer.write_all(sender)?; A::write_payload(payload, writer) } @@ -138,3 +146,118 @@ impl Writeable for NativeTokenTransfer { Ok(()) } } + +pub trait Endpoint { + const PREFIX: [u8; 4]; +} + +pub struct WormholeEndpoint {} + +impl Endpoint for WormholeEndpoint { + const PREFIX: [u8; 4] = [0x99, 0x45, 0xFF, 0x10]; +} + +#[derive(PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] +pub struct EndpointMessage { + _phantom: PhantomData, + pub manager_payload: ManagerMessage, +} + +impl fmt::Debug for EndpointMessage +where + E: Endpoint, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.debug_struct("EndpointMessage") + .field("manager_payload", &self.manager_payload) + .finish() + } +} + +impl Clone for EndpointMessage +where + E: Endpoint, +{ + fn clone(&self) -> Self { + Self { + _phantom: PhantomData, + manager_payload: self.manager_payload.clone(), + } + } +} + +impl EndpointMessage { + pub fn new(manager_payload: ManagerMessage) -> Self { + Self { + _phantom: PhantomData, + manager_payload, + } + } +} + +impl TypePrefixedPayload for EndpointMessage { + const TYPE: Option = None; +} + +impl Readable for EndpointMessage { + const SIZE: Option = None; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let prefix: [u8; 4] = Readable::read(reader)?; + if prefix != E::PREFIX { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid prefix for EndpointMessage", + )); + } + let manager_payload = ManagerMessage::read(reader)?; + + Ok(EndpointMessage::new(manager_payload)) + } +} + +impl Writeable for EndpointMessage { + fn written_size(&self) -> usize { + self.manager_payload.written_size() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let EndpointMessage { + _phantom, + manager_payload, + } = self; + + E::PREFIX.write(writer)?; + manager_payload.write(writer) + } +} + +// This is a hack to get around the fact that the IDL generator doesn't support +// PhantomData. The generator uses the following functions, so we just mix them onto PhantomData. +// +// These types are technically more general than the actual ones, but we can't +// import the actual types from anchor-syn because that crate has a bug where it +// doesn't build against the solana bpf target (due to a missing function). +// Luckily, we don't need to reference those types, as we just want to omit PhantomData from the IDL anyway. +pub trait Hack { + fn __anchor_private_full_path() -> String; + fn __anchor_private_insert_idl_defined(_a: &mut HashMap); + fn __anchor_private_gen_idl_type() -> Option; +} + +impl Hack for PhantomData { + fn __anchor_private_full_path() -> String { + String::new() + } + fn __anchor_private_insert_idl_defined(_a: &mut HashMap) {} + fn __anchor_private_gen_idl_type() -> Option { + None + } +} From db7c3ecb226b7085dfe38742e7273466ab97a812 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sat, 10 Feb 2024 01:40:06 +0000 Subject: [PATCH 20/90] solana: initialise rate limit when adding sibling --- .../src/instructions/admin.rs | 30 ++++++++++++++++++- .../src/instructions/initialize.rs | 3 +- .../src/instructions/redeem.rs | 5 +--- .../src/messages.rs | 20 ++++++++++--- .../src/queue/rate_limit.rs | 15 ++++++++-- 5 files changed, 60 insertions(+), 13 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 3cb2bf30f..60f4547bf 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -5,7 +5,7 @@ use crate::{ chain_id::ChainId, config::Config, normalized_amount::NormalizedAmount, - queue::{inbox::InboundRateLimit, outbox::OutboxRateLimit}, + queue::{inbox::InboundRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, sibling::Sibling, }; @@ -79,6 +79,25 @@ pub struct SetSibling<'info> { )] pub sibling: Account<'info, Sibling>, + #[account( + init, + space = 8 + InboundRateLimit::INIT_SPACE, + payer = payer, + seeds = [ + InboundRateLimit::SEED_PREFIX, + args.chain_id.id.to_be_bytes().as_ref() + ], + bump, + )] + pub rate_limit: Account<'info, InboundRateLimit>, + + #[account( + constraint = mint.key() == config.mint + )] + // TODO: should we just store the decimals in the config? a lot of + // instructions just take mint for the decimals + pub mint: InterfaceAccount<'info, token_interface::Mint>, + pub system_program: Program<'info, System>, } @@ -86,6 +105,7 @@ pub struct SetSibling<'info> { pub struct SetSiblingArgs { pub chain_id: ChainId, pub address: [u8; 32], + pub limit: u64, } pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> { @@ -93,6 +113,14 @@ pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> bump: ctx.bumps.sibling, address: args.address, }); + + ctx.accounts.rate_limit.set_inner(InboundRateLimit { + bump: ctx.bumps.rate_limit, + rate_limit: RateLimitState::new(NormalizedAmount::normalize( + args.limit, + ctx.accounts.mint.decimals, + )), + }); Ok(()) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 3752e2d64..270861a35 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -53,13 +53,14 @@ pub struct Initialize<'info> { pub struct InitializeArgs { pub chain_id: u16, pub limit: u64, + pub mode: crate::config::Mode, } pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> { ctx.accounts.config.set_inner(crate::config::Config { bump: ctx.bumps.config, mint: ctx.accounts.mint.key(), - mode: crate::config::Mode::Burning, + mode: args.mode, chain_id: ChainId { id: args.chain_id }, owner: ctx.accounts.owner.key(), pending_owner: None, diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 7b6fabd3c..b5ee03482 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; -use wormhole_anchor_sdk::wormhole::{self, PostedVaa, PostedVaaData}; +use wormhole_anchor_sdk::wormhole::PostedVaa; use crate::{ config::*, @@ -25,9 +25,6 @@ pub struct Redeem<'info> { pub sibling: Account<'info, Sibling>, #[account( - seeds = [PostedVaaData::SEED_PREFIX], - seeds::program = wormhole::program::ID, - bump, // check that the VAA's emitter agrees with what's in the message constraint = vaa.emitter_chain() == vaa.message().manager_payload.chain_id.id @ NTTError::InvalidChainId, // check that the messages is targeted to this chain diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 01f482b06..cfeebbc49 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; use core::fmt; -use std::{io, marker::PhantomData, collections::HashMap}; +use std::{collections::HashMap, io, marker::PhantomData}; use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; @@ -75,7 +75,7 @@ impl Writeable for ManagerMessage { } } -#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] +#[derive(Debug, Clone, PartialEq, Eq)] pub struct NativeTokenTransfer { pub amount: NormalizedAmount, // TODO: shouldn't we put this in the outer message? @@ -108,8 +108,8 @@ impl Readable for NativeTokenTransfer { } let amount = Readable::read(reader)?; - let to_chain = Readable::read(reader)?; let to = Readable::read(reader)?; + let to_chain = Readable::read(reader)?; Ok(Self { amount, @@ -157,7 +157,7 @@ impl Endpoint for WormholeEndpoint { const PREFIX: [u8; 4] = [0x99, 0x45, 0xFF, 0x10]; } -#[derive(PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] +#[derive(PartialEq, Eq)] pub struct EndpointMessage { _phantom: PhantomData, pub manager_payload: ManagerMessage, @@ -174,6 +174,18 @@ where } } +impl AnchorDeserialize for EndpointMessage { + fn deserialize_reader(reader: &mut R) -> io::Result { + Readable::read(reader) + } +} + +impl AnchorSerialize for EndpointMessage { + fn serialize(&self, writer: &mut W) -> io::Result<()> { + Writeable::write(self, writer) + } +} + impl Clone for EndpointMessage where E: Endpoint, diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index ced1ea462..ed117f644 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -117,7 +117,10 @@ mod tests { let immediately = rate_limit_state.consume_or_delay(NormalizedAmount::new(30_000, 8)); assert_eq!(immediately, current_timestamp()); - assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(70_000, 8)); + assert_eq!( + rate_limit_state.capacity(), + NormalizedAmount::new(70_000, 8) + ); assert_eq!(rate_limit_state.limit, NormalizedAmount::new(100_000, 8)); // unchanged assert_eq!(rate_limit_state.last_tx_timestamp, current_timestamp()); @@ -146,11 +149,17 @@ mod tests { rate_limit_state.set_limit(NormalizedAmount::new(50_000, 8)); // this decreases the capacity by 50k, to 45k - assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(45_000, 8)); + assert_eq!( + rate_limit_state.capacity(), + NormalizedAmount::new(45_000, 8) + ); // now set the limit to 100k rate_limit_state.set_limit(NormalizedAmount::new(100_000, 8)); - assert_eq!(rate_limit_state.capacity(), NormalizedAmount::new(95_000, 8)); + assert_eq!( + rate_limit_state.capacity(), + NormalizedAmount::new(95_000, 8) + ); } } From 05f5f5b1c95023d46e1105765a0220eb5ddcdca5 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sat, 10 Feb 2024 18:14:35 +0000 Subject: [PATCH 21/90] solana: init custody token account for lock/unlock and store the token program in the config --- .../src/config.rs | 4 ++++ .../src/instructions/initialize.rs | 22 ++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 86ab6465c..35b55b1a0 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -14,6 +14,10 @@ pub struct Config { pub pending_owner: Option, /// Mint address of the token managed by this program. pub mint: Pubkey, + /// Address of the token program (token or token22). This could always be queried + /// from the [`mint`] account's owner, but storing it here avoids an indirection + /// on the client side. + pub token_program: Pubkey, /// The mode that this program is running in. This is used to determine /// whether the program is burning tokens or locking tokens. pub mode: Mode, diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 270861a35..f32de1ece 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -1,5 +1,5 @@ use anchor_lang::prelude::*; -use anchor_spl::token_interface; +use anchor_spl::{token_interface, associated_token::AssociatedToken}; use crate::{ chain_id::ChainId, @@ -46,6 +46,25 @@ pub struct Initialize<'info> { )] pub rate_limit: Account<'info, OutboxRateLimit>, + #[account( + seeds = [b"custody_authority"], + bump, + )] + pub custody_authority: AccountInfo<'info>, + + #[account( + init, + payer = payer, + associated_token::mint = mint, + associated_token::authority = custody_authority, + )] + pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, + + /// CHECK: checked to be the appropriate token progrem when initialising the + /// associated token account for the given mint. + pub token_program: Interface<'info, token_interface::TokenInterface>, + pub associated_token_program: Program<'info, AssociatedToken>, + system_program: Program<'info, System>, } @@ -60,6 +79,7 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> ctx.accounts.config.set_inner(crate::config::Config { bump: ctx.bumps.config, mint: ctx.accounts.mint.key(), + token_program: ctx.accounts.token_program.key(), mode: args.mode, chain_id: ChainId { id: args.chain_id }, owner: ctx.accounts.owner.key(), From aff4c391f88434b60d0bcf2840ac65d1a2c0c5b2 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sat, 10 Feb 2024 20:12:48 +0000 Subject: [PATCH 22/90] solana: update serialisation code to be in line with evm impl --- solana/Cargo.lock | 7 ++ .../example-native-token-transfers/Cargo.toml | 3 + .../src/instructions/release_outbound.rs | 1 + .../src/messages.rs | 77 ++++++++++++++++++- 4 files changed, 86 insertions(+), 2 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index fab999eae..cfbe46953 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -907,6 +907,7 @@ dependencies = [ "ahash 0.8.6", "anchor-lang", "anchor-spl", + "hex", "wormhole-anchor-sdk", "wormhole-io", ] @@ -1002,6 +1003,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hmac" version = "0.8.1" diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index d1f14dbf7..a9c762765 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -26,3 +26,6 @@ anchor-lang = "0.29.0" anchor-spl = "0.29.0" wormhole-anchor-sdk = "0.29.0-alpha.1" wormhole-io = "0.1.3" + +[dev-dependencies] +hex = "0.4.3" diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 930bc6ac2..c9b870276 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -80,6 +80,7 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg sender: accs.emitter.key().to_bytes(), payload: NativeTokenTransfer { amount: accs.outbox_item.amount, + source_token: accs.config.mint.to_bytes(), to: accs.outbox_item.recipient_address.clone(), to_chain: accs.outbox_item.recipient_chain, }, diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index cfeebbc49..baa954076 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -34,6 +34,8 @@ impl Readable for ManagerMessage { let sequence = Readable::read(reader)?; let source_manager = Readable::read(reader)?; let sender = Readable::read(reader)?; + // TODO: same as below for manager payload + let _payload_len: u16 = Readable::read(reader)?; let payload = A::read_payload(reader)?; Ok(Self { @@ -52,6 +54,7 @@ impl Writeable for ManagerMessage { + u64::SIZE.unwrap() + self.source_manager.len() + self.sender.len() + + u16::SIZE.unwrap() // payload length + self.payload.written_size() } @@ -71,6 +74,9 @@ impl Writeable for ManagerMessage { sequence.write(writer)?; writer.write_all(source_manager)?; writer.write_all(sender)?; + let len: u16 = u16::try_from(payload.written_size()).expect("u16 overflow"); + len.write(writer)?; + // TODO: same as above A::write_payload(payload, writer) } } @@ -78,6 +84,8 @@ impl Writeable for ManagerMessage { #[derive(Debug, Clone, PartialEq, Eq)] pub struct NativeTokenTransfer { pub amount: NormalizedAmount, + // TODO: is this needed? + pub source_token: [u8; 32], // TODO: shouldn't we put this in the outer message? pub to_chain: ChainId, pub to: [u8; 32], @@ -108,11 +116,13 @@ impl Readable for NativeTokenTransfer { } let amount = Readable::read(reader)?; + let source_token = Readable::read(reader)?; let to = Readable::read(reader)?; let to_chain = Readable::read(reader)?; Ok(Self { amount, + source_token, to, to_chain, }) @@ -123,7 +133,7 @@ impl Writeable for NativeTokenTransfer { fn written_size(&self) -> usize { Self::PREFIX.len() + NormalizedAmount::SIZE.unwrap() - + u16::SIZE.unwrap() // payload length + + self.source_token.len() + self.to.len() + ChainId::SIZE.unwrap() } @@ -134,13 +144,15 @@ impl Writeable for NativeTokenTransfer { { let NativeTokenTransfer { amount, + source_token, to, to_chain, } = self; Self::PREFIX.write(writer)?; amount.write(writer)?; - writer.write_all(to)?; + source_token.write(writer)?; + to.write(writer)?; to_chain.write(writer)?; Ok(()) @@ -151,6 +163,7 @@ pub trait Endpoint { const PREFIX: [u8; 4]; } +#[derive(PartialEq, Eq)] pub struct WormholeEndpoint {} impl Endpoint for WormholeEndpoint { @@ -226,6 +239,9 @@ impl Readable for EndpointMessag "Invalid prefix for EndpointMessage", )); } + // TODO: we need a way to easily check that decoding the payload + // consumes the expected amount of bytes + let _manager_payload_len: u16 = Readable::read(reader)?; let manager_payload = ManagerMessage::read(reader)?; Ok(EndpointMessage::new(manager_payload)) @@ -234,6 +250,8 @@ impl Readable for EndpointMessag impl Writeable for EndpointMessage { fn written_size(&self) -> usize { + 4 + // prefix + u16::SIZE.unwrap() + // length prefix self.manager_payload.written_size() } @@ -247,6 +265,12 @@ impl Writeable for EndpointMess } = self; E::PREFIX.write(writer)?; + let len: u16 = u16::try_from(manager_payload.written_size()).expect("u16 overflow"); + len.write(writer)?; + // TODO: review this in wormhole-io. The written_size logic is error prone. Instead, + // a better API would be + // foo.write_with_prefix_be::(writer) + // which writes the length as a big endian u16. manager_payload.write(writer) } } @@ -273,3 +297,52 @@ impl Hack for PhantomData { None } } + +#[cfg(test)] +mod test { + use super::*; + // + #[test] + fn test_deserialize_endpoint_message() { + let data = hex::decode("9945ff10009b0013000000367999a101042942fafabe00000000000000000000000000000000000000000000000000004667921341234300000000000000000000000000000000000000000000000000004f994e545408000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe000000000000000000000000000000000000000000000000000000000011").unwrap(); + let mut vec = &data[..]; + let message: EndpointMessage = + TypePrefixedPayload::read_payload(&mut vec).unwrap(); + + let expected = EndpointMessage { + _phantom: PhantomData::, + manager_payload: ManagerMessage { + chain_id: ChainId { id: 19 }, + sequence: 233968345345, + source_manager: [ + 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + sender: [ + 0x46, 0x67, 0x92, 0x13, 0x41, 0x23, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount: 1234567, + decimals: 8, + }, + source_token: [ + 0xBE, 0xEF, 0xFA, 0xCE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + to_chain: ChainId { id: 17 }, + to: [ + 0xFE, 0xEB, 0xCA, 0xFE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }, + }, + }; + assert_eq!(message, expected); + assert_eq!(vec.len(), 0); + + let encoded = TypePrefixedPayload::to_vec_payload(&expected); + assert_eq!(encoded, data); + } +} From 6d3cec42156fd98854565f2ead707cd747eb89c2 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sun, 11 Feb 2024 13:32:27 +0400 Subject: [PATCH 23/90] solana: check mint authority is NTT manager in burning mode --- .../src/config.rs | 2 +- .../example-native-token-transfers/src/error.rs | 2 ++ .../src/instructions/initialize.rs | 17 +++++++++++++++-- .../src/instructions/release_inbound.rs | 7 ++++--- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 35b55b1a0..f691b654b 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -55,7 +55,7 @@ impl<'info> DerefMut for NotPausedConfig<'info> { } } -#[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone)] +#[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone, PartialEq, Eq)] pub enum Mode { Burning, Locking, diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index 5e8b6024a..f2e6dc887 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -17,4 +17,6 @@ pub enum NTTError { MessageAlreadySent, #[msg("InvalidMode")] InvalidMode, + #[msg("InvalidMintAuthority")] + InvalidMintAuthority, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index f32de1ece..1bc254f08 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -1,8 +1,9 @@ use anchor_lang::prelude::*; -use anchor_spl::{token_interface, associated_token::AssociatedToken}; +use anchor_spl::{associated_token::AssociatedToken, token_interface}; use crate::{ chain_id::ChainId, + error::NTTError, normalized_amount::NormalizedAmount, queue::{outbox::OutboxRateLimit, rate_limit::RateLimitState}, sequence::Sequence, @@ -10,6 +11,7 @@ use crate::{ // TODO: upgradeability #[derive(Accounts)] +#[instruction(mode: crate::config::Mode)] pub struct Initialize<'info> { #[account(mut)] pub payer: Signer<'info>, @@ -25,7 +27,12 @@ pub struct Initialize<'info> { )] pub config: Account<'info, crate::config::Config>, - #[account()] + #[account( + constraint = + mode == crate::config::Mode::Burning + || mint.mint_authority.unwrap() == mint_authority.key() + @ NTTError::InvalidMintAuthority, + )] pub mint: InterfaceAccount<'info, token_interface::Mint>, #[account( @@ -60,6 +67,12 @@ pub struct Initialize<'info> { )] pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, + #[account( + seeds = [b"token_minter"], + bump, + )] + pub mint_authority: AccountInfo<'info>, + /// CHECK: checked to be the appropriate token progrem when initialising the /// associated token account for the given mint. pub token_program: Interface<'info, token_interface::TokenInterface>, diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 569ff590e..6c922cbc4 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -22,7 +22,8 @@ pub struct ReleaseInbound<'info> { )] /// CHECK: the address is checked to match the recipient address in the /// inbox item - pub recipient: AccountInfo<'info>, + /// TODO: send to ATA? + pub recipient: InterfaceAccount<'info, token_interface::TokenAccount>, #[account( mut, @@ -59,7 +60,7 @@ pub fn release_inbound_mint(ctx: Context) -> Result<()> { ctx.accounts.common.token_program.to_account_info(), token_interface::MintTo { mint: ctx.accounts.common.mint.to_account_info(), - to: ctx.accounts.common.recipient.clone(), + to: ctx.accounts.common.recipient.to_account_info(), authority: ctx.accounts.mint_authority.clone(), }, &[&[b"token_minter", &[ctx.bumps.mint_authority]]], @@ -100,7 +101,7 @@ pub fn release_inbound_unlock(ctx: Context) -> Result<()> ctx.accounts.common.token_program.to_account_info(), token_interface::TransferChecked { from: ctx.accounts.custody.to_account_info(), - to: ctx.accounts.common.recipient.clone(), + to: ctx.accounts.common.recipient.to_account_info(), authority: ctx.accounts.custody_authority.clone(), mint: ctx.accounts.common.mint.to_account_info(), }, From e70c016c15c7426c3a8936cf921bf806d65c2338 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 18:00:27 +0400 Subject: [PATCH 24/90] solana: fix custody PDA --- .../src/instructions/release_inbound.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 6c922cbc4..1b7da8a88 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -80,12 +80,13 @@ pub struct ReleaseInboundUnlock<'info> { common: ReleaseInbound<'info>, #[account( - seeds = [b"custody_authoity"], + seeds = [b"custody_authority"], bump, )] pub custody_authority: AccountInfo<'info>, /// CHECK: the token program checks if this indeed the right authority for the mint + #[account(mut)] pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, } From e69d82bbf9249c4b18c8cdcdfbd46bce941dd5d3 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 18:01:03 +0400 Subject: [PATCH 25/90] solana: add test fixtures (mainnet wh binaries & accounts) --- solana/Anchor.toml | 26 +++++++++++++++++- .../accounts/mainnet/core_bridge_config.json | 14 ++++++++++ .../mainnet/core_bridge_fee_collector.json | 14 ++++++++++ .../accounts/mainnet/guardian_set_0.json | 14 ++++++++++ .../accounts/mainnet/mainnet_core_bridge.so | Bin 0 -> 973360 bytes .../accounts/testnet/testnet_core_bridge.so | Bin 0 -> 904976 bytes 6 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 solana/tests/accounts/mainnet/core_bridge_config.json create mode 100644 solana/tests/accounts/mainnet/core_bridge_fee_collector.json create mode 100644 solana/tests/accounts/mainnet/guardian_set_0.json create mode 100644 solana/tests/accounts/mainnet/mainnet_core_bridge.so create mode 100644 solana/tests/accounts/testnet/testnet_core_bridge.so diff --git a/solana/Anchor.toml b/solana/Anchor.toml index 170bd1000..a66a11926 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -2,7 +2,7 @@ seeds = false skip-lint = false [programs.localnet] -solana_multi_endpoint = "CjjU6T8ZowfYmK3bDrb5k8TdTSQxCMnhZz1xFXUwUYsn" +solana_multi_endpoint = "J61k8wq3PMLWmpR8meNxuQWfjHdzf8W1TZrFHoock9ou" [registry] url = "https://api.apr.dev" @@ -13,3 +13,27 @@ wallet = "keys/test.json" [scripts] test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" + + +[test.validator] +url = "https://api.mainnet-beta.solana.com" + +### Wormhole Core Bridge (Mainnet) -- Program +[[test.genesis]] +address = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth" +program = "tests/accounts/mainnet/mainnet_core_bridge.so" + +### Wormhole Core Bridge (Mainnet) -- Config +[[test.validator.account]] +address = "2yVjuQwpsvdsrywzsJJVs9Ueh4zayyo5DYJbBNc3DDpn" +filename = "tests/accounts/mainnet/core_bridge_config.json" + +### Wormhole Core Bridge (Mainnet) -- Fee Collector +[[test.validator.account]] +address = "9bFNrXNb2WTx8fMHXCheaZqkLZ3YCCaiqTftHxeintHy" +filename = "tests/accounts/mainnet/core_bridge_fee_collector.json" + +### Wormhole Core Bridge (Mainnet) -- Guardian set 0 (overridden with devnet private key) +[[test.validator.account]] +address = "DS7qfSAgYsonPpKoAjcGhX9VFjXdGkiHjEDkTidf8H2P" +filename = "tests/accounts/mainnet/guardian_set_0.json" diff --git a/solana/tests/accounts/mainnet/core_bridge_config.json b/solana/tests/accounts/mainnet/core_bridge_config.json new file mode 100644 index 000000000..faf9bf2a3 --- /dev/null +++ b/solana/tests/accounts/mainnet/core_bridge_config.json @@ -0,0 +1,14 @@ +{ + "pubkey": "2yVjuQwpsvdsrywzsJJVs9Ueh4zayyo5DYJbBNc3DDpn", + "account": { + "lamports": 1057920, + "data": [ + "AAAAAJ2tEggAAAAAgFEBAGQAAAAAAAAA", + "base64" + ], + "owner": "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth", + "executable": false, + "rentEpoch": 18446744073709551615, + "space": 24 + } +} diff --git a/solana/tests/accounts/mainnet/core_bridge_fee_collector.json b/solana/tests/accounts/mainnet/core_bridge_fee_collector.json new file mode 100644 index 000000000..edcfff03d --- /dev/null +++ b/solana/tests/accounts/mainnet/core_bridge_fee_collector.json @@ -0,0 +1,14 @@ +{ + "pubkey": "9bFNrXNb2WTx8fMHXCheaZqkLZ3YCCaiqTftHxeintHy", + "account": { + "lamports": 2350640070, + "data": [ + "", + "base64" + ], + "owner": "11111111111111111111111111111111", + "executable": false, + "rentEpoch": 18446744073709551615, + "space": 0 + } +} diff --git a/solana/tests/accounts/mainnet/guardian_set_0.json b/solana/tests/accounts/mainnet/guardian_set_0.json new file mode 100644 index 000000000..9d26f362d --- /dev/null +++ b/solana/tests/accounts/mainnet/guardian_set_0.json @@ -0,0 +1,14 @@ +{ + "pubkey": "DS7qfSAgYsonPpKoAjcGhX9VFjXdGkiHjEDkTidf8H2P", + "account": { + "lamports": 21141440, + "data": [ + "AAAAAAEAAAC++kKdV80Yt/ik2RotqatK8F0PvkPJm2EAAAAA", + "base64" + ], + "owner": "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth", + "executable": false, + "rentEpoch": 18446744073709551615, + "space": 36 + } +} diff --git a/solana/tests/accounts/mainnet/mainnet_core_bridge.so b/solana/tests/accounts/mainnet/mainnet_core_bridge.so new file mode 100644 index 0000000000000000000000000000000000000000..ef0a0bd62469326e41165a9ff42198c8da208031 GIT binary patch literal 973360 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�eizx=-PzXe4p==1OQqdeJ!7^z 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ά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%0DhI=qLE`-{c4B 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 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ z1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009IL zKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~ z0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY** z5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0 z009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{1Q0*~0R#|0009ILKmY**5I_I{ K1Q0+#1^x#(^{es# literal 0 HcmV?d00001 From d01daf32c9b90361af5b3879c460214776786b87 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 18:01:54 +0400 Subject: [PATCH 26/90] solana: add js packages (for test & sdk) --- solana/.eslintrc.json | 19 + solana/package-lock.json | 8458 ++++++++++++++++++++++++++++++++++++++ solana/package.json | 23 +- solana/tsconfig.json | 4 +- solana/yarn.lock | 4461 ++++++++++++++++++-- 5 files changed, 12708 insertions(+), 257 deletions(-) create mode 100644 solana/.eslintrc.json create mode 100644 solana/package-lock.json diff --git a/solana/.eslintrc.json b/solana/.eslintrc.json new file mode 100644 index 000000000..1d98782d2 --- /dev/null +++ b/solana/.eslintrc.json @@ -0,0 +1,19 @@ +{ + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "extends": "standard-with-typescript", + "parserOptions": { + "ecmaVersion": "latest", + "sourceType": "module" + }, + plugins: [ + '@stylistic' + ], + "rules": { + '@stylistic/indent': ['error', 2], + '@stylistic/max-len': ['error', 80], + } +} diff --git a/solana/package-lock.json b/solana/package-lock.json new file mode 100644 index 000000000..aac44c512 --- /dev/null +++ b/solana/package-lock.json @@ -0,0 +1,8458 @@ +{ + "name": "solana-multi-endpoint", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "license": "Apache-2.0", + "dependencies": { + "@certusone/wormhole-sdk": "^0.10.10", + "@coral-xyz/anchor": "^0.29.0", + "@solana/spl-token": "^0.4.0" + }, + "devDependencies": { + "@stylistic/eslint-plugin": "^1.6.1", + "@stylistic/eslint-plugin-js": "^1.6.1", + "@stylistic/eslint-plugin-ts": "^1.6.1", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "@typescript-eslint/eslint-plugin": "^6.21.0", + "chai": "^4.3.4", + "eslint": "^8.56.0", + "eslint-config-standard-with-typescript": "^43.0.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-promise": "^6.1.1", + "mocha": "^9.0.3", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^4.9.5" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@apollo/client": { + "version": "3.9.4", + "resolved": "https://registry.npmjs.org/@apollo/client/-/client-3.9.4.tgz", + "integrity": "sha512-Ip6dxjshDT2Dp6foLASTnKBW45Fytew/5JZutZwgc78hVrrGpO9UtZA9xteHXYdap0wIgCxCfeIQwbSu1ZdQpw==", + "optional": true, + "dependencies": { + "@graphql-typed-document-node/core": "^3.1.1", + "@wry/caches": "^1.0.0", + "@wry/equality": "^0.5.6", + "@wry/trie": "^0.5.0", + "graphql-tag": "^2.12.6", + "hoist-non-react-statics": "^3.3.2", + "optimism": "^0.18.0", + "prop-types": "^15.7.2", + "rehackt": "0.0.4", + "response-iterator": "^0.2.6", + "symbol-observable": "^4.0.0", + "ts-invariant": "^0.10.3", + "tslib": "^2.3.0", + "zen-observable-ts": "^1.2.5" + }, + "peerDependencies": { + "graphql": "^15.0.0 || ^16.0.0", + "graphql-ws": "^5.5.5", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0", + "react-dom": "^16.8.0 || ^17.0.0 || ^18.0.0", + "subscriptions-transport-ws": "^0.9.0 || ^0.11.0" + }, + "peerDependenciesMeta": { + "graphql-ws": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + }, + "subscriptions-transport-ws": { + "optional": true + } + } + }, + "node_modules/@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@certusone/wormhole-sdk": { + "version": "0.10.10", + "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.10.10.tgz", + "integrity": "sha512-2pYQ2/+cSfh/LVtOTXQDrTeZdXHgzq/hjkTevzW5+rEqITE54qUlnMhcVtSJQe+Yvgg3awrP2mIfDW3nvwPIPA==", + "dependencies": { + "@certusone/wormhole-sdk-proto-web": "0.0.7", + "@certusone/wormhole-sdk-wasm": "^0.0.1", + "@coral-xyz/borsh": "0.2.6", + "@mysten/sui.js": "0.32.2", + "@project-serum/anchor": "^0.25.0", + "@solana/spl-token": "^0.3.5", + "@solana/web3.js": "^1.66.2", + "@terra-money/terra.js": "3.1.9", + "@xpla/xpla.js": "^0.2.1", + "algosdk": "^2.4.0", + "aptos": "1.5.0", + "axios": "^0.24.0", + "bech32": "^2.0.0", + "binary-parser": "^2.2.1", + "bs58": "^4.0.1", + "elliptic": "^6.5.4", + "js-base64": "^3.6.1", + "near-api-js": "^1.0.0" + }, + "optionalDependencies": { + "@injectivelabs/networks": "1.10.12", + "@injectivelabs/sdk-ts": "1.10.72", + "@injectivelabs/utils": "1.10.12" + } + }, + "node_modules/@certusone/wormhole-sdk-proto-web": { + "version": "0.0.7", + "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk-proto-web/-/wormhole-sdk-proto-web-0.0.7.tgz", + "integrity": "sha512-GCe1/bcqMS0Mt+hsWp4SE4NLL59pWmK0lhQXO0oqAKl0G9AuuTdudySMDF/sLc7z5H2w34bSuSrIEKvPuuSC+w==", + "dependencies": { + "@improbable-eng/grpc-web": "^0.15.0", + "protobufjs": "^7.0.0", + "rxjs": "^7.5.6" + } + }, + "node_modules/@certusone/wormhole-sdk-wasm": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@certusone/wormhole-sdk-wasm/-/wormhole-sdk-wasm-0.0.1.tgz", + "integrity": "sha512-LdIwLhOyr4pPs2jqYubqC7d4UkqYBX0EG/ppspQlW3qlVE0LZRMrH6oVzzLMyHtV0Rw7O9sIKzORW/T3mrJv2w==", + "dependencies": { + "@types/long": "^4.0.2", + "@types/node": "^18.0.3" + } + }, + "node_modules/@certusone/wormhole-sdk-wasm/node_modules/@types/node": { + "version": "18.19.15", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.15.tgz", + "integrity": "sha512-AMZ2UWx+woHNfM11PyAEQmfSxi05jm9OlkxczuHeEqmvwPkYj6MWv44gbzDPefYOLysTOFyI3ziiy2ONmUZfpA==", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@certusone/wormhole-sdk/node_modules/@coral-xyz/borsh": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.2.6.tgz", + "integrity": "sha512-y6nmHw1bFcJib7sMHsQPpC8r47xhqDZVvhUdna7NUPzpSbOZG6f46N21+aXsQ2w/tG8Ggls488J/ZmwbgVmyjg==", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.2.0" + } + }, + "node_modules/@certusone/wormhole-sdk/node_modules/@solana/spl-token": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.11.tgz", + "integrity": "sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ==", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "@solana/spl-token-metadata": "^0.1.2", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.88.0" + } + }, + "node_modules/@classic-terra/terra.proto": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@classic-terra/terra.proto/-/terra.proto-1.1.0.tgz", + "integrity": "sha512-bYhQG5LUaGF0KPRY9hYT/HEcd1QExZPQd6zLV/rQkCe/eDxfwFRLzZHpaaAdfWoAAZjsRWqJbUCqCg7gXBbJpw==", + "dependencies": { + "@improbable-eng/grpc-web": "^0.14.1", + "google-protobuf": "^3.17.3", + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/@classic-terra/terra.proto/node_modules/@improbable-eng/grpc-web": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.14.1.tgz", + "integrity": "sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw==", + "dependencies": { + "browser-headers": "^0.4.1" + }, + "peerDependencies": { + "google-protobuf": "^3.14.0" + } + }, + "node_modules/@classic-terra/terra.proto/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/@confio/ics23": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.8.tgz", + "integrity": "sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w==", + "optional": true, + "dependencies": { + "@noble/hashes": "^1.0.0", + "protobufjs": "^6.8.8" + } + }, + "node_modules/@confio/ics23/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/@coral-xyz/anchor": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.29.0.tgz", + "integrity": "sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA==", + "dependencies": { + "@coral-xyz/borsh": "^0.29.0", + "@noble/hashes": "^1.3.1", + "@solana/web3.js": "^1.68.0", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^6.3.0", + "cross-fetch": "^3.1.5", + "crypto-hash": "^1.3.0", + "eventemitter3": "^4.0.7", + "pako": "^2.0.3", + "snake-case": "^3.0.4", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=11" + } + }, + "node_modules/@coral-xyz/borsh": { + "version": "0.29.0", + "resolved": "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.29.0.tgz", + "integrity": "sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ==", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.68.0" + } + }, + "node_modules/@cosmjs/amino": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz", + "integrity": "sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w==", + "optional": true, + "dependencies": { + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1" + } + }, + "node_modules/@cosmjs/crypto": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz", + "integrity": "sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ==", + "optional": true, + "dependencies": { + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "@noble/hashes": "^1", + "bn.js": "^5.2.0", + "elliptic": "^6.5.4", + "libsodium-wrappers": "^0.7.6" + } + }, + "node_modules/@cosmjs/encoding": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.30.1.tgz", + "integrity": "sha512-rXmrTbgqwihORwJ3xYhIgQFfMSrwLu1s43RIK9I8EBudPx3KmnmyAKzMOVsRDo9edLFNuZ9GIvysUCwQfq3WlQ==", + "optional": true, + "dependencies": { + "base64-js": "^1.3.0", + "bech32": "^1.1.4", + "readonly-date": "^1.0.0" + } + }, + "node_modules/@cosmjs/encoding/node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "optional": true + }, + "node_modules/@cosmjs/json-rpc": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.30.1.tgz", + "integrity": "sha512-pitfC/2YN9t+kXZCbNuyrZ6M8abnCC2n62m+JtU9vQUfaEtVsgy+1Fk4TRQ175+pIWSdBMFi2wT8FWVEE4RhxQ==", + "optional": true, + "dependencies": { + "@cosmjs/stream": "^0.30.1", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/math": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/math/-/math-0.30.1.tgz", + "integrity": "sha512-yaoeI23pin9ZiPHIisa6qqLngfnBR/25tSaWpkTm8Cy10MX70UF5oN4+/t1heLaM6SSmRrhk3psRkV4+7mH51Q==", + "optional": true, + "dependencies": { + "bn.js": "^5.2.0" + } + }, + "node_modules/@cosmjs/proto-signing": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz", + "integrity": "sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ==", + "optional": true, + "dependencies": { + "@cosmjs/amino": "^0.30.1", + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "cosmjs-types": "^0.7.1", + "long": "^4.0.0" + } + }, + "node_modules/@cosmjs/socket": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.30.1.tgz", + "integrity": "sha512-r6MpDL+9N+qOS/D5VaxnPaMJ3flwQ36G+vPvYJsXArj93BjgyFB7BwWwXCQDzZ+23cfChPUfhbINOenr8N2Kow==", + "optional": true, + "dependencies": { + "@cosmjs/stream": "^0.30.1", + "isomorphic-ws": "^4.0.1", + "ws": "^7", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/stargate": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.30.1.tgz", + "integrity": "sha512-RdbYKZCGOH8gWebO7r6WvNnQMxHrNXInY/gPHPzMjbQF6UatA6fNM2G2tdgS5j5u7FTqlCI10stNXrknaNdzog==", + "optional": true, + "dependencies": { + "@confio/ics23": "^0.6.8", + "@cosmjs/amino": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/proto-signing": "^0.30.1", + "@cosmjs/stream": "^0.30.1", + "@cosmjs/tendermint-rpc": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "cosmjs-types": "^0.7.1", + "long": "^4.0.0", + "protobufjs": "~6.11.3", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/stargate/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/@cosmjs/stream": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.30.1.tgz", + "integrity": "sha512-Fg0pWz1zXQdoxQZpdHRMGvUH5RqS6tPv+j9Eh7Q953UjMlrwZVo0YFLC8OTf/HKVf10E4i0u6aM8D69Q6cNkgQ==", + "optional": true, + "dependencies": { + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/tendermint-rpc": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.30.1.tgz", + "integrity": "sha512-Z3nCwhXSbPZJ++v85zHObeUggrEHVfm1u18ZRwXxFE9ZMl5mXTybnwYhczuYOl7KRskgwlB+rID0WYACxj4wdQ==", + "optional": true, + "dependencies": { + "@cosmjs/crypto": "^0.30.1", + "@cosmjs/encoding": "^0.30.1", + "@cosmjs/json-rpc": "^0.30.1", + "@cosmjs/math": "^0.30.1", + "@cosmjs/socket": "^0.30.1", + "@cosmjs/stream": "^0.30.1", + "@cosmjs/utils": "^0.30.1", + "axios": "^0.21.2", + "readonly-date": "^1.0.0", + "xstream": "^11.14.0" + } + }, + "node_modules/@cosmjs/tendermint-rpc/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "optional": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/@cosmjs/utils": { + "version": "0.30.1", + "resolved": "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz", + "integrity": "sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g==", + "optional": true + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@eslint/js": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz", + "integrity": "sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@ethereumjs/common": { + "version": "2.6.5", + "resolved": "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz", + "integrity": "sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA==", + "optional": true, + "dependencies": { + "crc-32": "^1.2.0", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethereumjs/tx": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz", + "integrity": "sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw==", + "optional": true, + "dependencies": { + "@ethereumjs/common": "^2.6.4", + "ethereumjs-util": "^7.1.5" + } + }, + "node_modules/@ethersproject/abi": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz", + "integrity": "sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-provider": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz", + "integrity": "sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0" + } + }, + "node_modules/@ethersproject/abstract-signer": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz", + "integrity": "sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/address": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz", + "integrity": "sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/rlp": "^5.7.0" + } + }, + "node_modules/@ethersproject/base64": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz", + "integrity": "sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0" + } + }, + "node_modules/@ethersproject/basex": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz", + "integrity": "sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/properties": "^5.7.0" + } + }, + "node_modules/@ethersproject/bignumber": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz", + "integrity": "sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "bn.js": "^5.2.1" + } + }, + "node_modules/@ethersproject/bytes": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz", + "integrity": "sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/constants": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz", + "integrity": "sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0" + } + }, + "node_modules/@ethersproject/contracts": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz", + "integrity": "sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abi": "^5.7.0", + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/transactions": "^5.7.0" + } + }, + "node_modules/@ethersproject/hash": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz", + "integrity": "sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/hdnode": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz", + "integrity": "sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/json-wallets": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz", + "integrity": "sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/pbkdf2": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "aes-js": "3.0.0", + "scrypt-js": "3.0.1" + } + }, + "node_modules/@ethersproject/keccak256": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz", + "integrity": "sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "js-sha3": "0.8.0" + } + }, + "node_modules/@ethersproject/logger": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz", + "integrity": "sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ] + }, + "node_modules/@ethersproject/networks": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz", + "integrity": "sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/pbkdf2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz", + "integrity": "sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/sha2": "^5.7.0" + } + }, + "node_modules/@ethersproject/properties": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz", + "integrity": "sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/providers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz", + "integrity": "sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/base64": "^5.7.0", + "@ethersproject/basex": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/networks": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/web": "^5.7.0", + "bech32": "1.1.4", + "ws": "7.4.6" + } + }, + "node_modules/@ethersproject/providers/node_modules/bech32": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz", + "integrity": "sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ==", + "optional": true + }, + "node_modules/@ethersproject/providers/node_modules/ws": { + "version": "7.4.6", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", + "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==", + "optional": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ethersproject/random": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz", + "integrity": "sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/rlp": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz", + "integrity": "sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/sha2": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz", + "integrity": "sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/signing-key": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz", + "integrity": "sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "bn.js": "^5.2.1", + "elliptic": "6.5.4", + "hash.js": "1.1.7" + } + }, + "node_modules/@ethersproject/solidity": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz", + "integrity": "sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/sha2": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/strings": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz", + "integrity": "sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/transactions": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz", + "integrity": "sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/rlp": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0" + } + }, + "node_modules/@ethersproject/units": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz", + "integrity": "sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/constants": "^5.7.0", + "@ethersproject/logger": "^5.7.0" + } + }, + "node_modules/@ethersproject/wallet": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz", + "integrity": "sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abstract-provider": "^5.7.0", + "@ethersproject/abstract-signer": "^5.7.0", + "@ethersproject/address": "^5.7.0", + "@ethersproject/bignumber": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/hdnode": "^5.7.0", + "@ethersproject/json-wallets": "^5.7.0", + "@ethersproject/keccak256": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/random": "^5.7.0", + "@ethersproject/signing-key": "^5.7.0", + "@ethersproject/transactions": "^5.7.0", + "@ethersproject/wordlists": "^5.7.0" + } + }, + "node_modules/@ethersproject/web": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz", + "integrity": "sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/base64": "^5.7.0", + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@ethersproject/wordlists": { + "version": "5.7.0", + "resolved": "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz", + "integrity": "sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/bytes": "^5.7.0", + "@ethersproject/hash": "^5.7.0", + "@ethersproject/logger": "^5.7.0", + "@ethersproject/properties": "^5.7.0", + "@ethersproject/strings": "^5.7.0" + } + }, + "node_modules/@graphql-typed-document-node/core": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz", + "integrity": "sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==", + "optional": true, + "peerDependencies": { + "graphql": "^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@improbable-eng/grpc-web": { + "version": "0.15.0", + "resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz", + "integrity": "sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg==", + "dependencies": { + "browser-headers": "^0.4.1" + }, + "peerDependencies": { + "google-protobuf": "^3.14.0" + } + }, + "node_modules/@injectivelabs/core-proto-ts": { + "version": "0.0.14", + "resolved": "https://registry.npmjs.org/@injectivelabs/core-proto-ts/-/core-proto-ts-0.0.14.tgz", + "integrity": "sha512-NZWlgBzgVrXow9IknFQHvcYKX4QkUD25taRigoNYQK8PDn4+VXd9xM5WFUDRhzm2smTCguyl/+MghpEp4oTPWw==", + "optional": true, + "dependencies": { + "@injectivelabs/grpc-web": "^0.0.1", + "google-protobuf": "^3.14.0", + "protobufjs": "^7.0.0", + "rxjs": "^7.4.0" + } + }, + "node_modules/@injectivelabs/exceptions": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@injectivelabs/exceptions/-/exceptions-1.14.5.tgz", + "integrity": "sha512-WQ+hxpKz4g4+ZXNTXLFKpf9D9uosleZLqC++2+wK81IQ/lcwi5GrTLYdasOhJeu3c+LKWxHQRHJfSsvt8TQWbA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@injectivelabs/grpc-web": "^0.0.1", + "@injectivelabs/ts-types": "^1.14.5", + "http-status-codes": "^2.2.0", + "link-module-alias": "^1.2.0", + "shx": "^0.3.2" + } + }, + "node_modules/@injectivelabs/grpc-web": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/@injectivelabs/grpc-web/-/grpc-web-0.0.1.tgz", + "integrity": "sha512-Pu5YgaZp+OvR5UWfqbrPdHer3+gDf+b5fQoY+t2VZx1IAVHX8bzbN9EreYTvTYtFeDpYRWM8P7app2u4EX5wTw==", + "optional": true, + "dependencies": { + "browser-headers": "^0.4.1" + }, + "peerDependencies": { + "google-protobuf": "^3.14.0" + } + }, + "node_modules/@injectivelabs/grpc-web-node-http-transport": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@injectivelabs/grpc-web-node-http-transport/-/grpc-web-node-http-transport-0.0.2.tgz", + "integrity": "sha512-rpyhXLiGY/UMs6v6YmgWHJHiO9l0AgDyVNv+jcutNVt4tQrmNvnpvz2wCAGOFtq5LuX/E9ChtTVpk3gWGqXcGA==", + "optional": true, + "peerDependencies": { + "@injectivelabs/grpc-web": ">=0.0.1" + } + }, + "node_modules/@injectivelabs/grpc-web-react-native-transport": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@injectivelabs/grpc-web-react-native-transport/-/grpc-web-react-native-transport-0.0.2.tgz", + "integrity": "sha512-mk+aukQXnYNgPsPnu3KBi+FD0ZHQpazIlaBZ2jNZG7QAVmxTWtv3R66Zoq99Wx2dnE946NsZBYAoa0K5oSjnow==", + "optional": true, + "peerDependencies": { + "@injectivelabs/grpc-web": ">=0.0.1" + } + }, + "node_modules/@injectivelabs/indexer-proto-ts": { + "version": "1.10.8-rc.4", + "resolved": "https://registry.npmjs.org/@injectivelabs/indexer-proto-ts/-/indexer-proto-ts-1.10.8-rc.4.tgz", + "integrity": "sha512-IwbepTfsHHAv3Z36As6yH/+HIplOEpUu6SFHBCVgdSIaQ8GuvTib4HETiVnV4mjYqoyVgWs+zLSAfih46rdMJQ==", + "optional": true, + "dependencies": { + "@injectivelabs/grpc-web": "^0.0.1", + "google-protobuf": "^3.14.0", + "protobufjs": "^7.0.0", + "rxjs": "^7.4.0" + } + }, + "node_modules/@injectivelabs/mito-proto-ts": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@injectivelabs/mito-proto-ts/-/mito-proto-ts-1.0.9.tgz", + "integrity": "sha512-+TZMvJ4SHwcn6SFPdqaiQFZdNhjH7hyRFozY15nOTC2utdGij9jEsjz1NsyOejfYDA0s1z5Wm1SgrMYKaVpAmQ==", + "optional": true, + "dependencies": { + "@injectivelabs/grpc-web": "^0.0.1", + "google-protobuf": "^3.14.0", + "protobufjs": "^7.0.0", + "rxjs": "^7.4.0" + } + }, + "node_modules/@injectivelabs/networks": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@injectivelabs/networks/-/networks-1.10.12.tgz", + "integrity": "sha512-tTHyLls1Nik5QTs/S03qqG2y/ITvNwI8CJOQbMmmsr1CL2CdjJBtzRYn9Dyx2p8XgzRFf9hmlybpe20tq9O3SA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@injectivelabs/exceptions": "^1.10.12", + "@injectivelabs/ts-types": "^1.10.12", + "@injectivelabs/utils": "^1.10.12", + "link-module-alias": "^1.2.0", + "shx": "^0.3.2" + } + }, + "node_modules/@injectivelabs/sdk-ts": { + "version": "1.10.72", + "resolved": "https://registry.npmjs.org/@injectivelabs/sdk-ts/-/sdk-ts-1.10.72.tgz", + "integrity": "sha512-A5mHNNBgO4fI1c/7CZ0bGfVXliy8laP+VaYZ++aWh1YyudoZw4CTCEmLetZRy7AUU3XcfbHa8sAImRi7db+v6Q==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@apollo/client": "^3.5.8", + "@cosmjs/amino": "^0.30.1", + "@cosmjs/proto-signing": "^0.30.1", + "@cosmjs/stargate": "^0.30.1", + "@ethersproject/bytes": "^5.7.0", + "@injectivelabs/core-proto-ts": "^0.0.14", + "@injectivelabs/exceptions": "^1.10.12", + "@injectivelabs/grpc-web": "^0.0.1", + "@injectivelabs/grpc-web-node-http-transport": "^0.0.2", + "@injectivelabs/grpc-web-react-native-transport": "^0.0.2", + "@injectivelabs/indexer-proto-ts": "1.10.8-rc.4", + "@injectivelabs/mito-proto-ts": "1.0.9", + "@injectivelabs/networks": "^1.10.12", + "@injectivelabs/test-utils": "^1.10.12", + "@injectivelabs/token-metadata": "^1.10.42", + "@injectivelabs/ts-types": "^1.10.12", + "@injectivelabs/utils": "^1.10.12", + "@metamask/eth-sig-util": "^4.0.0", + "axios": "^0.27.2", + "bech32": "^2.0.0", + "bip39": "^3.0.4", + "cosmjs-types": "^0.7.1", + "eth-crypto": "^2.6.0", + "ethereumjs-util": "^7.1.4", + "ethers": "^5.7.2", + "google-protobuf": "^3.21.0", + "graphql": "^16.3.0", + "http-status-codes": "^2.2.0", + "js-sha3": "^0.8.0", + "jscrypto": "^1.0.3", + "keccak256": "^1.0.6", + "link-module-alias": "^1.2.0", + "rxjs": "^7.8.0", + "secp256k1": "^4.0.3", + "shx": "^0.3.2", + "snakecase-keys": "^5.4.1" + } + }, + "node_modules/@injectivelabs/sdk-ts/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "optional": true, + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/@injectivelabs/test-utils": { + "version": "1.14.3", + "resolved": "https://registry.npmjs.org/@injectivelabs/test-utils/-/test-utils-1.14.3.tgz", + "integrity": "sha512-dVe262sACa7YkRr7mfXx58yI/ieuQqm3IMGq7EMweFKI6Kh2gh8FAM2bsDgm1cGewEIhJ9tWh6OM5uNheeVamg==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "axios": "^0.21.1", + "bignumber.js": "^9.0.1", + "link-module-alias": "^1.2.0", + "shx": "^0.3.2", + "snakecase-keys": "^5.1.2", + "store2": "^2.12.0" + } + }, + "node_modules/@injectivelabs/test-utils/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "optional": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/@injectivelabs/token-metadata": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@injectivelabs/token-metadata/-/token-metadata-1.14.5.tgz", + "integrity": "sha512-GiIiNDixfvbfEjzZG7ixtGYmJllFIcA2Xl1LnsK5yawT8Q+/SoSIJig4tE+0CC/AaGHS1GxDKySrIdMse7PZ0w==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@injectivelabs/exceptions": "^1.14.5", + "@injectivelabs/networks": "^1.14.5", + "@injectivelabs/ts-types": "^1.14.5", + "@injectivelabs/utils": "^1.14.5", + "@types/lodash.values": "^4.3.6", + "copyfiles": "^2.4.1", + "jsonschema": "^1.4.0", + "link-module-alias": "^1.2.0", + "lodash": "^4.17.21", + "lodash.values": "^4.3.0", + "shx": "^0.3.2" + } + }, + "node_modules/@injectivelabs/token-metadata/node_modules/@injectivelabs/networks": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@injectivelabs/networks/-/networks-1.14.5.tgz", + "integrity": "sha512-9GINd/pPBX6Jyc26pmlLC54s7nLlXsBLZ/1fo8a0nvHkrrODRDE4IldP6KsA9OLVomMPk5TyBUgYLGgM3ST9GA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@injectivelabs/exceptions": "^1.14.5", + "@injectivelabs/ts-types": "^1.14.5", + "@injectivelabs/utils": "^1.14.5", + "link-module-alias": "^1.2.0", + "shx": "^0.3.2" + } + }, + "node_modules/@injectivelabs/token-metadata/node_modules/@injectivelabs/utils": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@injectivelabs/utils/-/utils-1.14.5.tgz", + "integrity": "sha512-L2ul/7rgop8RLJBhlXjt6Q/A6fXeRZ3hhCZFXGXmA63vz9RSqOFHILiRp6hAFsuZbiITjmVx0eubFPaQU0MymA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@injectivelabs/exceptions": "^1.14.5", + "@injectivelabs/ts-types": "^1.14.5", + "axios": "^0.21.1", + "bignumber.js": "^9.0.1", + "http-status-codes": "^2.2.0", + "link-module-alias": "^1.2.0", + "shx": "^0.3.2", + "snakecase-keys": "^5.1.2", + "store2": "^2.12.0" + } + }, + "node_modules/@injectivelabs/token-metadata/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "optional": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/@injectivelabs/ts-types": { + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@injectivelabs/ts-types/-/ts-types-1.14.5.tgz", + "integrity": "sha512-dwmEJE90vMr1zkQhz5lX2280sBMe2GvAj98vOHoL2RLTo0OQkJZrirUHwsTkexJf7sFZIT2PlmLCfix9Ulcp5A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "link-module-alias": "^1.2.0", + "shx": "^0.3.2" + } + }, + "node_modules/@injectivelabs/utils": { + "version": "1.10.12", + "resolved": "https://registry.npmjs.org/@injectivelabs/utils/-/utils-1.10.12.tgz", + "integrity": "sha512-c8al79nxIJgV1cBAdW2TPDGldj/8gm5k0h5TIN/AJs8/AeIjpTwwVGfLY3QvPOpRsxuQ9CjBkTXrAcSL1wwkcw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@injectivelabs/exceptions": "^1.10.12", + "@injectivelabs/ts-types": "^1.10.12", + "axios": "^0.21.1", + "bignumber.js": "^9.0.1", + "http-status-codes": "^2.2.0", + "link-module-alias": "^1.2.0", + "shx": "^0.3.2", + "snakecase-keys": "^5.1.2", + "store2": "^2.12.0" + } + }, + "node_modules/@injectivelabs/utils/node_modules/axios": { + "version": "0.21.4", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz", + "integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==", + "optional": true, + "dependencies": { + "follow-redirects": "^1.14.0" + } + }, + "node_modules/@metamask/eth-sig-util": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz", + "integrity": "sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ==", + "optional": true, + "dependencies": { + "ethereumjs-abi": "^0.6.8", + "ethereumjs-util": "^6.2.1", + "ethjs-util": "^0.1.6", + "tweetnacl": "^1.0.3", + "tweetnacl-util": "^0.15.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@metamask/eth-sig-util/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "optional": true + }, + "node_modules/@metamask/eth-sig-util/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "optional": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/@mysten/bcs": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/@mysten/bcs/-/bcs-0.7.1.tgz", + "integrity": "sha512-wFPb8bkhwrbiStfZMV5rFM7J+umpke59/dNjDp+UYJKykNlW23LCk2ePyEUvGdb62HGJM1jyOJ8g4egE3OmdKA==", + "dependencies": { + "bs58": "^5.0.0" + } + }, + "node_modules/@mysten/bcs/node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, + "node_modules/@mysten/bcs/node_modules/bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "dependencies": { + "base-x": "^4.0.0" + } + }, + "node_modules/@mysten/sui.js": { + "version": "0.32.2", + "resolved": "https://registry.npmjs.org/@mysten/sui.js/-/sui.js-0.32.2.tgz", + "integrity": "sha512-/Hm4xkGolJhqj8FvQr7QSHDTlxIvL52mtbOao9f75YjrBh7y1Uh9kbJSY7xiTF1NY9sv6p5hUVlYRJuM0Hvn9A==", + "dependencies": { + "@mysten/bcs": "0.7.1", + "@noble/curves": "^1.0.0", + "@noble/hashes": "^1.3.0", + "@scure/bip32": "^1.3.0", + "@scure/bip39": "^1.2.0", + "@suchipi/femver": "^1.0.0", + "jayson": "^4.0.0", + "rpc-websockets": "^7.5.1", + "superstruct": "^1.0.3", + "tweetnacl": "^1.0.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@mysten/sui.js/node_modules/superstruct": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-1.0.3.tgz", + "integrity": "sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg==", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@noble/curves": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz", + "integrity": "sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA==", + "dependencies": { + "@noble/hashes": "1.3.3" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz", + "integrity": "sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA==", + "engines": { + "node": ">= 16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@project-serum/anchor": { + "version": "0.25.0", + "resolved": "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.25.0.tgz", + "integrity": "sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A==", + "dependencies": { + "@project-serum/borsh": "^0.2.5", + "@solana/web3.js": "^1.36.0", + "base64-js": "^1.5.1", + "bn.js": "^5.1.2", + "bs58": "^4.0.1", + "buffer-layout": "^1.2.2", + "camelcase": "^5.3.1", + "cross-fetch": "^3.1.5", + "crypto-hash": "^1.3.0", + "eventemitter3": "^4.0.7", + "js-sha256": "^0.9.0", + "pako": "^2.0.3", + "snake-case": "^3.0.4", + "superstruct": "^0.15.4", + "toml": "^3.0.0" + }, + "engines": { + "node": ">=11" + } + }, + "node_modules/@project-serum/anchor/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@project-serum/borsh": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.5.tgz", + "integrity": "sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q==", + "dependencies": { + "bn.js": "^5.1.2", + "buffer-layout": "^1.2.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "@solana/web3.js": "^1.2.0" + } + }, + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" + }, + "node_modules/@scure/base": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz", + "integrity": "sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ==", + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip32": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz", + "integrity": "sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ==", + "dependencies": { + "@noble/curves": "~1.3.0", + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@scure/bip39": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz", + "integrity": "sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA==", + "dependencies": { + "@noble/hashes": "~1.3.2", + "@scure/base": "~1.1.4" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/buffer-layout-utils": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz", + "integrity": "sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g==", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/web3.js": "^1.32.0", + "bigint-buffer": "^1.1.5", + "bignumber.js": "^9.0.1" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/@solana/codecs-core": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA==" + }, + "node_modules/@solana/codecs-data-structures": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw==", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508" + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q==", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508" + } + }, + "node_modules/@solana/codecs-strings": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA==", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22" + } + }, + "node_modules/@solana/options": { + "version": "2.0.0-experimental.8618508", + "resolved": "https://registry.npmjs.org/@solana/options/-/options-2.0.0-experimental.8618508.tgz", + "integrity": "sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg==", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508" + } + }, + "node_modules/@solana/spl-token": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.0.tgz", + "integrity": "sha512-jjBIBG9IsclqQVl5Y82npGE6utdCh7Z9VFcF5qgJa5EUq2XgspW3Dt1wujWjH/vQDRnkp9zGO+BqQU/HhX/3wg==", + "dependencies": { + "@solana/buffer-layout": "^4.0.0", + "@solana/buffer-layout-utils": "^0.2.0", + "@solana/spl-token-metadata": "^0.1.2", + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.89.1" + } + }, + "node_modules/@solana/spl-token-metadata": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz", + "integrity": "sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw==", + "dependencies": { + "@solana/codecs-core": "2.0.0-experimental.8618508", + "@solana/codecs-data-structures": "2.0.0-experimental.8618508", + "@solana/codecs-numbers": "2.0.0-experimental.8618508", + "@solana/codecs-strings": "2.0.0-experimental.8618508", + "@solana/options": "2.0.0-experimental.8618508", + "@solana/spl-type-length-value": "0.1.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.87.6" + } + }, + "node_modules/@solana/spl-type-length-value": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz", + "integrity": "sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA==", + "dependencies": { + "buffer": "^6.0.3" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.90.0", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.90.0.tgz", + "integrity": "sha512-p0cb/COXb8NNVSMkGMPwqQ6NvObZgUitN80uOedMB+jbYWOKOeJBuPnzhenkIV9RX0krGwyuY1Ltn5O8MGFsEw==", + "dependencies": { + "@babel/runtime": "^7.23.4", + "@noble/curves": "^1.2.0", + "@noble/hashes": "^1.3.2", + "@solana/buffer-layout": "^4.0.1", + "agentkeepalive": "^4.5.0", + "bigint-buffer": "^1.1.5", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.0", + "node-fetch": "^2.7.0", + "rpc-websockets": "^7.5.1", + "superstruct": "^0.14.2" + } + }, + "node_modules/@solana/web3.js/node_modules/superstruct": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz", + "integrity": "sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==" + }, + "node_modules/@stylistic/eslint-plugin": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-1.6.1.tgz", + "integrity": "sha512-De7Sw86OtIf7SsMgjLCf4bTeI3085Plyh4l0Rg1V42BTFo/Q6Pz7Cbu31rEk/UHFiEna/YO8Hxj80jFP3ObrQw==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "1.6.1", + "@stylistic/eslint-plugin-jsx": "1.6.1", + "@stylistic/eslint-plugin-plus": "1.6.1", + "@stylistic/eslint-plugin-ts": "1.6.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.6.1.tgz", + "integrity": "sha512-gHRxkbA5p8S1fnChE7Yf5NFltRZCzbCuQOcoTe93PSKBC4GqVjZmlWUSLz9pJKHvDAUTjWkfttWHIOaFYPEhRQ==", + "dev": true, + "dependencies": { + "acorn": "^8.11.3", + "escape-string-regexp": "^4.0.0", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-js/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.6.1.tgz", + "integrity": "sha512-uJQcg3iqrhm3EH15ZjxmZ1YmXXexkLKFEgxkWA3RYjgAVTx8k7xGJwClK/JnjKDGdbFRiDQPjxt964R1vsaFaQ==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "^1.6.1", + "estraverse": "^5.3.0", + "picomatch": "^3.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@stylistic/eslint-plugin-jsx/node_modules/picomatch": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz", + "integrity": "sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@stylistic/eslint-plugin-plus": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.6.1.tgz", + "integrity": "sha512-nYIXfdYN+pBVmm0vPCKQFg/IK35tf3ZGz+0WENUL6ww1+jKM6/i36FalRFculiHzO+wOpJ3/yXWJC3PCbwGFZQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^6.20.0" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@stylistic/eslint-plugin-ts": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-1.6.1.tgz", + "integrity": "sha512-eZxrFaLhPJVUQmtsRXKiuzSou0nlHevKc1WsfhxUJ9p8juv3G3YlbbGeYg4AP1fNlEmWs/lZQAP2WfzQOdBNvQ==", + "dev": true, + "dependencies": { + "@stylistic/eslint-plugin-js": "1.6.1", + "@typescript-eslint/utils": "^6.20.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "peerDependencies": { + "eslint": ">=8.40.0" + } + }, + "node_modules/@suchipi/femver": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@suchipi/femver/-/femver-1.0.0.tgz", + "integrity": "sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg==" + }, + "node_modules/@terra-money/legacy.proto": { + "name": "@terra-money/terra.proto", + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-0.1.7.tgz", + "integrity": "sha512-NXD7f6pQCulvo6+mv6MAPzhOkUzRjgYVuHZE/apih+lVnPG5hDBU0rRYnOGGofwvKT5/jQoOENnFn/gioWWnyQ==", + "dependencies": { + "google-protobuf": "^3.17.3", + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/@terra-money/legacy.proto/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/@terra-money/terra.js": { + "version": "3.1.9", + "resolved": "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.1.9.tgz", + "integrity": "sha512-JulSvOHLM56fL7s+cIjIbZeWPBluq883X1soWxA4TG5rKkDythT/DHeLXr3jP5Ld/26VENPSg6lNvK7cEYKpiw==", + "dependencies": { + "@classic-terra/terra.proto": "^1.1.0", + "@terra-money/terra.proto": "^2.1.0", + "axios": "^0.27.2", + "bech32": "^2.0.0", + "bip32": "^2.0.6", + "bip39": "^3.0.3", + "bufferutil": "^4.0.3", + "decimal.js": "^10.2.1", + "jscrypto": "^1.0.1", + "readable-stream": "^3.6.0", + "secp256k1": "^4.0.2", + "tmp": "^0.2.1", + "utf-8-validate": "^5.0.5", + "ws": "^7.5.9" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@terra-money/terra.js/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/@terra-money/terra.proto": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-2.1.0.tgz", + "integrity": "sha512-rhaMslv3Rkr+QsTQEZs64FKA4QlfO0DfQHaR6yct/EovenMkibDEQ63dEL6yJA6LCaEQGYhyVB9JO9pTUA8ybw==", + "dependencies": { + "@improbable-eng/grpc-web": "^0.14.1", + "google-protobuf": "^3.17.3", + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/@terra-money/terra.proto/node_modules/@improbable-eng/grpc-web": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.14.1.tgz", + "integrity": "sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw==", + "dependencies": { + "browser-headers": "^0.4.1" + }, + "peerDependencies": { + "google-protobuf": "^3.14.0" + } + }, + "node_modules/@terra-money/terra.proto/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/@types/bn.js": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz", + "integrity": "sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A==", + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/chai": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz", + "integrity": "sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, + "node_modules/@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.14.202", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz", + "integrity": "sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ==", + "optional": true + }, + "node_modules/@types/lodash.values": { + "version": "4.3.9", + "resolved": "https://registry.npmjs.org/@types/lodash.values/-/lodash.values-4.3.9.tgz", + "integrity": "sha512-IJ20OEfqNwm3k8ENwoM3q0yOs4UMpgtD4GqxB4lwBHToGthHWqhyh5DdSgQjioocz0QK2SSBkJfCq95ZTV8BTw==", + "optional": true, + "dependencies": { + "@types/lodash": "*" + } + }, + "node_modules/@types/long": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz", + "integrity": "sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA==" + }, + "node_modules/@types/mocha": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz", + "integrity": "sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "20.11.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz", + "integrity": "sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/@types/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/secp256k1": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz", + "integrity": "sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/semver": { + "version": "7.5.6", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz", + "integrity": "sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz", + "integrity": "sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/type-utils": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha", + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", + "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz", + "integrity": "sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz", + "integrity": "sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "6.21.0", + "@typescript-eslint/utils": "6.21.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/type-utils/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/types": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz", + "integrity": "sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg==", + "dev": true, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz", + "integrity": "sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/visitor-keys": "6.21.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dev": true, + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz", + "integrity": "sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "6.21.0", + "@typescript-eslint/types": "6.21.0", + "@typescript-eslint/typescript-estree": "6.21.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "6.21.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz", + "integrity": "sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "6.21.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^16.0.0 || >=18.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/promise-all-settled": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz", + "integrity": "sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q==", + "dev": true, + "license": "ISC" + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@wry/caches": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz", + "integrity": "sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA==", + "optional": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/context": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz", + "integrity": "sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ==", + "optional": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/equality": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz", + "integrity": "sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw==", + "optional": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@wry/trie": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz", + "integrity": "sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA==", + "optional": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@xpla/xpla.js": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@xpla/xpla.js/-/xpla.js-0.2.3.tgz", + "integrity": "sha512-Tfk7hCGWXtwr08reY3Pi6dmzIqFbzri9jcyzJdfNmdo4cN0PMwpRJuZZcPmtxiIUnNef3AN1E/6nJUD5MKniuA==", + "dependencies": { + "@ethersproject/bytes": "^5.6.1", + "@ethersproject/keccak256": "^5.6.1", + "@ethersproject/signing-key": "^5.6.2", + "@terra-money/legacy.proto": "npm:@terra-money/terra.proto@^0.1.7", + "@terra-money/terra.proto": "^2.1.0", + "axios": "^0.26.1", + "bech32": "^2.0.0", + "bip32": "^2.0.6", + "bip39": "^3.0.3", + "bufferutil": "^4.0.3", + "crypto-addr-codec": "^0.1.7", + "decimal.js": "^10.2.1", + "elliptic": "^6.5.4", + "ethereumjs-util": "^7.1.5", + "jscrypto": "^1.0.1", + "readable-stream": "^3.6.0", + "secp256k1": "^4.0.2", + "tmp": "^0.2.1", + "utf-8-validate": "^5.0.5", + "ws": "^7.5.8" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@xpla/xpla.js/node_modules/axios": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz", + "integrity": "sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA==", + "dependencies": { + "follow-redirects": "^1.14.8" + } + }, + "node_modules/acorn": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz", + "integrity": "sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg==", + "devOptional": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/aes-js": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz", + "integrity": "sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw==", + "optional": true + }, + "node_modules/agentkeepalive": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz", + "integrity": "sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew==", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/algo-msgpack-with-bigint": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz", + "integrity": "sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/algosdk": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/algosdk/-/algosdk-2.7.0.tgz", + "integrity": "sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg==", + "dependencies": { + "algo-msgpack-with-bigint": "^2.1.1", + "buffer": "^6.0.3", + "hi-base32": "^0.5.1", + "js-sha256": "^0.9.0", + "js-sha3": "^0.8.0", + "js-sha512": "^0.8.0", + "json-bigint": "^1.0.0", + "tweetnacl": "^1.0.3", + "vlq": "^2.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "license": "ISC", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/aptos": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/aptos/-/aptos-1.5.0.tgz", + "integrity": "sha512-N7OuRtU7IYHkDkNx+4QS3g/QQGCp+36KzYn3oXPmT7Kttfuv+UKliQVdjy3cLmwd/DCQSh9ObTovwdxnHjUn0g==", + "dependencies": { + "@noble/hashes": "1.1.3", + "@scure/bip39": "1.1.0", + "axios": "0.27.2", + "form-data": "4.0.0", + "tweetnacl": "1.0.3" + }, + "engines": { + "node": ">=11.0.0" + } + }, + "node_modules/aptos/node_modules/@noble/hashes": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.3.tgz", + "integrity": "sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/aptos/node_modules/@scure/bip39": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz", + "integrity": "sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "@noble/hashes": "~1.1.1", + "@scure/base": "~1.1.0" + } + }, + "node_modules/aptos/node_modules/axios": { + "version": "0.27.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz", + "integrity": "sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ==", + "dependencies": { + "follow-redirects": "^1.14.9", + "form-data": "^4.0.0" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/array-buffer-byte-length": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", + "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "is-array-buffer": "^3.0.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-includes": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz", + "integrity": "sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "get-intrinsic": "^1.2.1", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/array.prototype.filter": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz", + "integrity": "sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-array-method-boxes-properly": "^1.0.0", + "is-string": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.findlastindex": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz", + "integrity": "sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.3.0", + "es-shim-unscopables": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flat": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz", + "integrity": "sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/array.prototype.flatmap": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz", + "integrity": "sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "es-shim-unscopables": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arraybuffer.prototype.slice": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", + "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.1", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.2.1", + "get-intrinsic": "^1.2.3", + "is-array-buffer": "^3.0.4", + "is-shared-array-buffer": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/arrify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz", + "integrity": "sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/available-typed-arrays": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz", + "integrity": "sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "dependencies": { + "follow-redirects": "^1.14.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "license": "MIT" + }, + "node_modules/base-x": { + "version": "3.0.9", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", + "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/big-integer": { + "version": "1.6.36", + "resolved": "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz", + "integrity": "sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/bigint-buffer": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz", + "integrity": "sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.3.0" + }, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/bignumber.js": { + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz", + "integrity": "sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz", + "integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/binary-parser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/binary-parser/-/binary-parser-2.2.1.tgz", + "integrity": "sha512-5ATpz/uPDgq5GgEDxTB4ouXCde7q2lqAQlSdBRQVl/AJnxmQmhIfyxJx+0MGu//D5rHQifkfGbWWlaysG0o9NA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/bindings": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz", + "integrity": "sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==", + "dependencies": { + "file-uri-to-path": "1.0.0" + } + }, + "node_modules/bip32": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/bip32/-/bip32-2.0.6.tgz", + "integrity": "sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA==", + "dependencies": { + "@types/node": "10.12.18", + "bs58check": "^2.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "tiny-secp256k1": "^1.1.3", + "typeforce": "^1.11.5", + "wif": "^2.0.6" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bip32/node_modules/@types/node": { + "version": "10.12.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz", + "integrity": "sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ==" + }, + "node_modules/bip39": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz", + "integrity": "sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A==", + "dependencies": { + "@noble/hashes": "^1.2.0" + } + }, + "node_modules/bip66": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz", + "integrity": "sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/blakejs": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz", + "integrity": "sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ==" + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==" + }, + "node_modules/browser-headers": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz", + "integrity": "sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg==" + }, + "node_modules/browser-stdout": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz", + "integrity": "sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw==", + "dev": true, + "license": "ISC" + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/bs58check": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", + "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "dependencies": { + "bs58": "^4.0.0", + "create-hash": "^1.1.0", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/buffer-layout": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz", + "integrity": "sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA==", + "engines": { + "node": ">=4.5" + } + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==" + }, + "node_modules/bufferutil": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz", + "integrity": "sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dev": true, + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/call-bind": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz", + "integrity": "sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "set-function-length": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/capability": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/capability/-/capability-0.2.5.tgz", + "integrity": "sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg==" + }, + "node_modules/chai": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", + "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "license": "MIT", + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "license": "MIT" + }, + "node_modules/copyfiles": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz", + "integrity": "sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg==", + "optional": true, + "dependencies": { + "glob": "^7.0.5", + "minimatch": "^3.0.3", + "mkdirp": "^1.0.4", + "noms": "0.0.0", + "through2": "^2.0.1", + "untildify": "^4.0.0", + "yargs": "^16.1.0" + }, + "bin": { + "copyfiles": "copyfiles", + "copyup": "copyfiles" + } + }, + "node_modules/copyfiles/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "optional": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/copyfiles/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "optional": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "optional": true + }, + "node_modules/cosmjs-types": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz", + "integrity": "sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA==", + "optional": true, + "dependencies": { + "long": "^4.0.0", + "protobufjs": "~6.11.2" + } + }, + "node_modules/cosmjs-types/node_modules/protobufjs": { + "version": "6.11.4", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz", + "integrity": "sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/long": "^4.0.1", + "@types/node": ">=13.7.0", + "long": "^4.0.0" + }, + "bin": { + "pbjs": "bin/pbjs", + "pbts": "bin/pbts" + } + }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "optional": true, + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/cross-fetch": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", + "integrity": "sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg==", + "license": "MIT", + "dependencies": { + "node-fetch": "^2.6.12" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-addr-codec": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz", + "integrity": "sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g==", + "dependencies": { + "base-x": "^3.0.8", + "big-integer": "1.6.36", + "blakejs": "^1.1.0", + "bs58": "^4.0.1", + "ripemd160-min": "0.0.6", + "safe-buffer": "^5.2.0", + "sha3": "^2.1.1" + } + }, + "node_modules/crypto-hash": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz", + "integrity": "sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/debug/node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/decamelize": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz", + "integrity": "sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/decimal.js": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz", + "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA==" + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/define-data-property": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz", + "integrity": "sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g==", + "devOptional": true, + "dependencies": { + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.2", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "devOptional": true, + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/diff": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz", + "integrity": "sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dot-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz", + "integrity": "sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w==", + "license": "MIT", + "dependencies": { + "no-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/drbg.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", + "integrity": "sha512-F4wZ06PvqxYLFEZKkFxTDcns9oFNk34hvmJSEwdzsxVQ8YI5YaxtACgQatkYgv2VI2CFkUd2Y+xosPQnHv809g==", + "optional": true, + "dependencies": { + "browserify-aes": "^1.0.6", + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/eccrypto": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/eccrypto/-/eccrypto-1.1.6.tgz", + "integrity": "sha512-d78ivVEzu7Tn0ZphUUaL43+jVPKTMPFGtmgtz1D0LrFn7cY3K8CdrvibuLz2AAkHBLKZtR8DMbB2ukRYFk987A==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "acorn": "7.1.1", + "elliptic": "6.5.4", + "es6-promise": "4.2.8", + "nan": "2.14.0" + }, + "optionalDependencies": { + "secp256k1": "3.7.1" + } + }, + "node_modules/eccrypto/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "optional": true + }, + "node_modules/eccrypto/node_modules/secp256k1": { + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz", + "integrity": "sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "bindings": "^1.5.0", + "bip66": "^1.1.5", + "bn.js": "^4.11.8", + "create-hash": "^1.2.0", + "drbg.js": "^1.0.1", + "elliptic": "^6.4.1", + "nan": "^2.14.0", + "safe-buffer": "^5.1.2" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/error-polyfill": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/error-polyfill/-/error-polyfill-0.1.3.tgz", + "integrity": "sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg==", + "dependencies": { + "capability": "^0.2.5", + "o3": "^1.0.3", + "u3": "^0.1.1" + } + }, + "node_modules/es-abstract": { + "version": "1.22.3", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz", + "integrity": "sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "arraybuffer.prototype.slice": "^1.0.2", + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.5", + "es-set-tostringtag": "^2.0.1", + "es-to-primitive": "^1.2.1", + "function.prototype.name": "^1.1.6", + "get-intrinsic": "^1.2.2", + "get-symbol-description": "^1.0.0", + "globalthis": "^1.0.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0", + "internal-slot": "^1.0.5", + "is-array-buffer": "^3.0.2", + "is-callable": "^1.2.7", + "is-negative-zero": "^2.0.2", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "is-string": "^1.0.7", + "is-typed-array": "^1.1.12", + "is-weakref": "^1.0.2", + "object-inspect": "^1.13.1", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "safe-array-concat": "^1.0.1", + "safe-regex-test": "^1.0.0", + "string.prototype.trim": "^1.2.8", + "string.prototype.trimend": "^1.0.7", + "string.prototype.trimstart": "^1.0.7", + "typed-array-buffer": "^1.0.0", + "typed-array-byte-length": "^1.0.0", + "typed-array-byte-offset": "^1.0.0", + "typed-array-length": "^1.0.4", + "unbox-primitive": "^1.0.2", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-array-method-boxes-properly": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz", + "integrity": "sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA==", + "dev": true + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-set-tostringtag": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz", + "integrity": "sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q==", + "dev": true, + "dependencies": { + "get-intrinsic": "^1.2.2", + "has-tostringtag": "^1.0.0", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-shim-unscopables": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz", + "integrity": "sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw==", + "dev": true, + "dependencies": { + "hasown": "^2.0.0" + } + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==" + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "dependencies": { + "es6-promise": "^4.0.3" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "8.56.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz", + "integrity": "sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.56.0", + "@humanwhocodes/config-array": "^0.11.13", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-compat-utils": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz", + "integrity": "sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg==", + "dev": true, + "engines": { + "node": ">=12" + }, + "peerDependencies": { + "eslint": ">=6.0.0" + } + }, + "node_modules/eslint-config-standard": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz", + "integrity": "sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0" + } + }, + "node_modules/eslint-config-standard-with-typescript": { + "version": "43.0.1", + "resolved": "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-43.0.1.tgz", + "integrity": "sha512-WfZ986+qzIzX6dcr4yGUyVb/l9N3Z8wPXCc5z/70fljs3UbWhhV+WxrfgsqMToRzuuyX9MqZ974pq2UPhDTOcA==", + "dev": true, + "dependencies": { + "@typescript-eslint/parser": "^6.4.0", + "eslint-config-standard": "17.1.0" + }, + "peerDependencies": { + "@typescript-eslint/eslint-plugin": "^6.4.0", + "eslint": "^8.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-n": "^15.0.0 || ^16.0.0 ", + "eslint-plugin-promise": "^6.0.0", + "typescript": "*" + } + }, + "node_modules/eslint-import-resolver-node": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz", + "integrity": "sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g==", + "dev": true, + "dependencies": { + "debug": "^3.2.7", + "is-core-module": "^2.13.0", + "resolve": "^1.22.4" + } + }, + "node_modules/eslint-import-resolver-node/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-module-utils": { + "version": "2.8.0", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz", + "integrity": "sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw==", + "dev": true, + "dependencies": { + "debug": "^3.2.7" + }, + "engines": { + "node": ">=4" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/eslint-module-utils/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-es-x": { + "version": "7.5.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz", + "integrity": "sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.1.2", + "@eslint-community/regexpp": "^4.6.0", + "eslint-compat-utils": "^0.1.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": ">=8" + } + }, + "node_modules/eslint-plugin-import": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz", + "integrity": "sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw==", + "dev": true, + "dependencies": { + "array-includes": "^3.1.7", + "array.prototype.findlastindex": "^1.2.3", + "array.prototype.flat": "^1.3.2", + "array.prototype.flatmap": "^1.3.2", + "debug": "^3.2.7", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.9", + "eslint-module-utils": "^2.8.0", + "hasown": "^2.0.0", + "is-core-module": "^2.13.1", + "is-glob": "^4.0.3", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.7", + "object.groupby": "^1.0.1", + "object.values": "^1.1.7", + "semver": "^6.3.1", + "tsconfig-paths": "^3.15.0" + }, + "engines": { + "node": ">=4" + }, + "peerDependencies": { + "eslint": "^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8" + } + }, + "node_modules/eslint-plugin-import/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/eslint-plugin-import/node_modules/doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eslint-plugin-import/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-import/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/eslint-plugin-n": { + "version": "16.6.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz", + "integrity": "sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "builtins": "^5.0.1", + "eslint-plugin-es-x": "^7.5.0", + "get-tsconfig": "^4.7.0", + "globals": "^13.24.0", + "ignore": "^5.2.4", + "is-builtin-module": "^3.2.1", + "is-core-module": "^2.12.1", + "minimatch": "^3.1.2", + "resolve": "^1.22.2", + "semver": "^7.5.3" + }, + "engines": { + "node": ">=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-n/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-promise": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz", + "integrity": "sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/eth-crypto": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eth-crypto/-/eth-crypto-2.6.0.tgz", + "integrity": "sha512-GCX4ffFYRUGgnuWR5qxcZIRQJ1KEqPFiyXU9yVy7s6dtXIMlUXZQ2h+5ID6rFaOHWbpJbjfkC6YdhwtwRYCnug==", + "optional": true, + "dependencies": { + "@babel/runtime": "7.20.13", + "@ethereumjs/tx": "3.5.2", + "@types/bn.js": "5.1.1", + "eccrypto": "1.1.6", + "ethereumjs-util": "7.1.5", + "ethers": "5.7.2", + "secp256k1": "5.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/pubkey" + } + }, + "node_modules/eth-crypto/node_modules/@babel/runtime": { + "version": "7.20.13", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz", + "integrity": "sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA==", + "optional": true, + "dependencies": { + "regenerator-runtime": "^0.13.11" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/eth-crypto/node_modules/@types/bn.js": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz", + "integrity": "sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/eth-crypto/node_modules/node-addon-api": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz", + "integrity": "sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA==", + "optional": true + }, + "node_modules/eth-crypto/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "optional": true + }, + "node_modules/eth-crypto/node_modules/secp256k1": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.0.tgz", + "integrity": "sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^5.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/ethereum-cryptography": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz", + "integrity": "sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ==", + "dependencies": { + "@types/pbkdf2": "^3.0.0", + "@types/secp256k1": "^4.0.1", + "blakejs": "^1.1.0", + "browserify-aes": "^1.2.0", + "bs58check": "^2.1.2", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash.js": "^1.1.7", + "keccak": "^3.0.0", + "pbkdf2": "^3.0.17", + "randombytes": "^2.1.0", + "safe-buffer": "^5.1.2", + "scrypt-js": "^3.0.0", + "secp256k1": "^4.0.1", + "setimmediate": "^1.0.5" + } + }, + "node_modules/ethereumjs-abi": { + "version": "0.6.8", + "resolved": "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz", + "integrity": "sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA==", + "optional": true, + "dependencies": { + "bn.js": "^4.11.8", + "ethereumjs-util": "^6.0.0" + } + }, + "node_modules/ethereumjs-abi/node_modules/@types/bn.js": { + "version": "4.11.6", + "resolved": "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz", + "integrity": "sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/ethereumjs-abi/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==", + "optional": true + }, + "node_modules/ethereumjs-abi/node_modules/ethereumjs-util": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz", + "integrity": "sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw==", + "optional": true, + "dependencies": { + "@types/bn.js": "^4.11.3", + "bn.js": "^4.11.0", + "create-hash": "^1.1.2", + "elliptic": "^6.5.2", + "ethereum-cryptography": "^0.1.3", + "ethjs-util": "0.1.6", + "rlp": "^2.2.3" + } + }, + "node_modules/ethereumjs-util": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz", + "integrity": "sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg==", + "dependencies": { + "@types/bn.js": "^5.1.0", + "bn.js": "^5.1.2", + "create-hash": "^1.1.2", + "ethereum-cryptography": "^0.1.3", + "rlp": "^2.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/ethers": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz", + "integrity": "sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg==", + "funding": [ + { + "type": "individual", + "url": "https://gitcoin.co/grants/13/ethersjs-complete-simple-and-tiny-2" + }, + { + "type": "individual", + "url": "https://www.buymeacoffee.com/ricmoo" + } + ], + "optional": true, + "dependencies": { + "@ethersproject/abi": "5.7.0", + "@ethersproject/abstract-provider": "5.7.0", + "@ethersproject/abstract-signer": "5.7.0", + "@ethersproject/address": "5.7.0", + "@ethersproject/base64": "5.7.0", + "@ethersproject/basex": "5.7.0", + "@ethersproject/bignumber": "5.7.0", + "@ethersproject/bytes": "5.7.0", + "@ethersproject/constants": "5.7.0", + "@ethersproject/contracts": "5.7.0", + "@ethersproject/hash": "5.7.0", + "@ethersproject/hdnode": "5.7.0", + "@ethersproject/json-wallets": "5.7.0", + "@ethersproject/keccak256": "5.7.0", + "@ethersproject/logger": "5.7.0", + "@ethersproject/networks": "5.7.1", + "@ethersproject/pbkdf2": "5.7.0", + "@ethersproject/properties": "5.7.0", + "@ethersproject/providers": "5.7.2", + "@ethersproject/random": "5.7.0", + "@ethersproject/rlp": "5.7.0", + "@ethersproject/sha2": "5.7.0", + "@ethersproject/signing-key": "5.7.0", + "@ethersproject/solidity": "5.7.0", + "@ethersproject/strings": "5.7.0", + "@ethersproject/transactions": "5.7.0", + "@ethersproject/units": "5.7.0", + "@ethersproject/wallet": "5.7.0", + "@ethersproject/web": "5.7.1", + "@ethersproject/wordlists": "5.7.0" + } + }, + "node_modules/ethjs-util": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz", + "integrity": "sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w==", + "optional": true, + "dependencies": { + "is-hex-prefixed": "1.0.0", + "strip-hex-prefix": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "engines": { + "node": "> 0.1.90" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==" + }, + "node_modules/fastestsmallesttextencoderdecoder": { + "version": "1.0.22", + "resolved": "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz", + "integrity": "sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw==", + "peer": true + }, + "node_modules/fastq": { + "version": "1.17.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", + "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/file-uri-to-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz", + "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==" + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "dev": true, + "license": "BSD-3-Clause", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.9", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz", + "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/for-each": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", + "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "dev": true, + "dependencies": { + "is-callable": "^1.1.3" + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "devOptional": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/function.prototype.name": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", + "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1", + "functions-have-names": "^1.2.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/functions-have-names": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", + "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "devOptional": true, + "license": "ISC", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "devOptional": true, + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-symbol-description": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", + "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-tsconfig": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz", + "integrity": "sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A==", + "dev": true, + "dependencies": { + "resolve-pkg-maps": "^1.0.0" + }, + "funding": { + "url": "https://github.com/privatenumber/get-tsconfig?sponsor=1" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globals/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globalthis": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz", + "integrity": "sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA==", + "devOptional": true, + "dependencies": { + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/google-protobuf": { + "version": "3.21.2", + "resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz", + "integrity": "sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA==" + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "devOptional": true, + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/graphql": { + "version": "16.8.1", + "resolved": "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz", + "integrity": "sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw==", + "optional": true, + "engines": { + "node": "^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0" + } + }, + "node_modules/graphql-tag": { + "version": "2.12.6", + "resolved": "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz", + "integrity": "sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg==", + "optional": true, + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=10" + }, + "peerDependencies": { + "graphql": "^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0" + } + }, + "node_modules/growl": { + "version": "1.10.5", + "resolved": "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz", + "integrity": "sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4.x" + } + }, + "node_modules/has-bigints": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", + "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz", + "integrity": "sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==", + "devOptional": true, + "dependencies": { + "get-intrinsic": "^1.2.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "devOptional": true, + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/he": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/he/-/he-1.2.0.tgz", + "integrity": "sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw==", + "dev": true, + "license": "MIT", + "bin": { + "he": "bin/he" + } + }, + "node_modules/hi-base32": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz", + "integrity": "sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA==" + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "optional": true, + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/http-errors": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", + "integrity": "sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": ">= 1.5.0 < 2", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-errors/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/http-status-codes": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz", + "integrity": "sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA==", + "optional": true + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "dependencies": { + "ms": "^2.0.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" + }, + "node_modules/internal-slot": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", + "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "dev": true, + "dependencies": { + "es-errors": "^1.3.0", + "hasown": "^2.0.0", + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", + "optional": true, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-array-buffer": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", + "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "dependencies": { + "has-bigints": "^1.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dev": true, + "license": "MIT", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-callable": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", + "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "devOptional": true, + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-hex-prefixed": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz", + "integrity": "sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA==", + "optional": true, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-object": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", + "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-shared-array-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz", + "integrity": "sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", + "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "dev": true, + "dependencies": { + "which-typed-array": "^1.1.14" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "optional": true + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/jayson": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz", + "integrity": "sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A==", + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "JSONStream": "^1.3.5", + "uuid": "^8.3.2", + "ws": "^7.4.5" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==" + }, + "node_modules/js-base64": { + "version": "3.7.6", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.6.tgz", + "integrity": "sha512-NPrWuHFxFUknr1KqJRDgUQPexQF0uIJWjeT+2KjEePhitQxQEx5EJBG1lVn5/hc8aLycTpXrDOgPQ6Zq+EDiTA==" + }, + "node_modules/js-sha256": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", + "integrity": "sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA==" + }, + "node_modules/js-sha3": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz", + "integrity": "sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q==" + }, + "node_modules/js-sha512": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz", + "integrity": "sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ==" + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "optional": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jscrypto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/jscrypto/-/jscrypto-1.0.3.tgz", + "integrity": "sha512-lryZl0flhodv4SZHOqyb1bx5sKcJxj0VBo0Kzb4QMAg3L021IC9uGpl0RCZa+9KJwlRGSK2C80ITcwbe19OKLQ==", + "bin": { + "jscrypto": "bin/cli.js" + } + }, + "node_modules/json-bigint": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz", + "integrity": "sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==", + "dependencies": { + "bignumber.js": "^9.0.0" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==" + }, + "node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==", + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/jsonschema": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz", + "integrity": "sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/keccak": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz", + "integrity": "sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q==", + "hasInstallScript": true, + "dependencies": { + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0", + "readable-stream": "^3.6.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/keccak256": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz", + "integrity": "sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw==", + "optional": true, + "dependencies": { + "bn.js": "^5.2.0", + "buffer": "^6.0.3", + "keccak": "^3.0.2" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/libsodium": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium/-/libsodium-0.7.13.tgz", + "integrity": "sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw==", + "optional": true + }, + "node_modules/libsodium-wrappers": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz", + "integrity": "sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw==", + "optional": true, + "dependencies": { + "libsodium": "^0.7.13" + } + }, + "node_modules/link-module-alias": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/link-module-alias/-/link-module-alias-1.2.0.tgz", + "integrity": "sha512-ahPjXepbSVKbahTB6LxR//VHm8HPfI+QQygCH+E82spBY4HR5VPJTvlhKBc9F7muVxnS6C1rRfoPOXAbWO/fyw==", + "optional": true, + "dependencies": { + "chalk": "^2.4.1" + }, + "bin": { + "link-module-alias": "index.js" + }, + "engines": { + "node": "> 8.0.0" + } + }, + "node_modules/link-module-alias/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "optional": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/link-module-alias/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "optional": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/link-module-alias/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "optional": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/link-module-alias/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "optional": true + }, + "node_modules/link-module-alias/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "optional": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/link-module-alias/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/link-module-alias/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "optional": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "optional": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.values": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz", + "integrity": "sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q==", + "optional": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/long": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/long/-/long-4.0.0.tgz", + "integrity": "sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA==" + }, + "node_modules/loose-envify": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", + "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", + "optional": true, + "dependencies": { + "js-tokens": "^3.0.0 || ^4.0.0" + }, + "bin": { + "loose-envify": "cli.js" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lower-case": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz", + "integrity": "sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.3" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, + "node_modules/map-obj": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz", + "integrity": "sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ==", + "optional": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==" + }, + "node_modules/minimatch": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz", + "integrity": "sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "devOptional": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/mkdirp": { + "version": "0.5.6", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz", + "integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.6" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mocha": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz", + "integrity": "sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ungap/promise-all-settled": "1.1.2", + "ansi-colors": "4.1.1", + "browser-stdout": "1.3.1", + "chokidar": "3.5.3", + "debug": "4.3.3", + "diff": "5.0.0", + "escape-string-regexp": "4.0.0", + "find-up": "5.0.0", + "glob": "7.2.0", + "growl": "1.10.5", + "he": "1.2.0", + "js-yaml": "4.1.0", + "log-symbols": "4.1.0", + "minimatch": "4.2.1", + "ms": "2.1.3", + "nanoid": "3.3.1", + "serialize-javascript": "6.0.0", + "strip-json-comments": "3.1.1", + "supports-color": "8.1.1", + "which": "2.0.2", + "workerpool": "6.2.0", + "yargs": "16.2.0", + "yargs-parser": "20.2.4", + "yargs-unparser": "2.0.0" + }, + "bin": { + "_mocha": "bin/_mocha", + "mocha": "bin/mocha" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/mochajs" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "license": "MIT" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "bin": { + "mustache": "bin/mustache" + } + }, + "node_modules/nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==" + }, + "node_modules/nanoid": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz", + "integrity": "sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw==", + "dev": true, + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/near-api-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/near-api-js/-/near-api-js-1.1.0.tgz", + "integrity": "sha512-qYKv1mYsaDZc2uYndhS+ttDhR9+60qFc+ZjD6lWsAxr3ZskMjRwPffDGQZYhC7BRDQMe1HEbk6d5mf+TVm0Lqg==", + "dependencies": { + "bn.js": "5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.0", + "depd": "^2.0.0", + "error-polyfill": "^0.1.3", + "http-errors": "^1.7.2", + "js-sha256": "^0.9.0", + "mustache": "^4.0.0", + "node-fetch": "^2.6.1", + "text-encoding-utf-8": "^1.0.2", + "tweetnacl": "^1.0.1" + } + }, + "node_modules/no-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz", + "integrity": "sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg==", + "license": "MIT", + "dependencies": { + "lower-case": "^2.0.2", + "tslib": "^2.0.3" + } + }, + "node_modules/node-addon-api": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz", + "integrity": "sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA==" + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/noms": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz", + "integrity": "sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow==", + "optional": true, + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "~1.0.31" + } + }, + "node_modules/noms/node_modules/readable-stream": { + "version": "1.0.34", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz", + "integrity": "sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.1", + "isarray": "0.0.1", + "string_decoder": "~0.10.x" + } + }, + "node_modules/noms/node_modules/string_decoder": { + "version": "0.10.31", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz", + "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==", + "optional": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/o3": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/o3/-/o3-1.0.3.tgz", + "integrity": "sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ==", + "dependencies": { + "capability": "^0.2.5" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "dev": true, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", + "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "has-symbols": "^1.0.3", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.fromentries": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz", + "integrity": "sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object.groupby": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz", + "integrity": "sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw==", + "dev": true, + "dependencies": { + "array.prototype.filter": "^1.0.3", + "call-bind": "^1.0.5", + "define-properties": "^1.2.1", + "es-abstract": "^1.22.3", + "es-errors": "^1.0.0" + } + }, + "node_modules/object.values": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz", + "integrity": "sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/optimism": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/optimism/-/optimism-0.18.0.tgz", + "integrity": "sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ==", + "optional": true, + "dependencies": { + "@wry/caches": "^1.0.0", + "@wry/context": "^0.7.0", + "@wry/trie": "^0.4.3", + "tslib": "^2.3.0" + } + }, + "node_modules/optimism/node_modules/@wry/trie": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz", + "integrity": "sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w==", + "optional": true, + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pako": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz", + "integrity": "sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug==", + "license": "(MIT AND Zlib)" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "devOptional": true + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "*" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz", + "integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "2.8.8", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz", + "integrity": "sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin-prettier.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "optional": true + }, + "node_modules/prop-types": { + "version": "15.8.1", + "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", + "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", + "optional": true, + "dependencies": { + "loose-envify": "^1.4.0", + "object-assign": "^4.1.1", + "react-is": "^16.13.1" + } + }, + "node_modules/protobufjs": { + "version": "7.2.6", + "resolved": "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz", + "integrity": "sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw==", + "hasInstallScript": true, + "dependencies": { + "@protobufjs/aspromise": "^1.1.2", + "@protobufjs/base64": "^1.1.2", + "@protobufjs/codegen": "^2.0.4", + "@protobufjs/eventemitter": "^1.1.0", + "@protobufjs/fetch": "^1.1.0", + "@protobufjs/float": "^1.0.2", + "@protobufjs/inquire": "^1.1.0", + "@protobufjs/path": "^1.1.2", + "@protobufjs/pool": "^1.1.0", + "@protobufjs/utf8": "^1.1.0", + "@types/node": ">=13.7.0", + "long": "^5.0.0" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/protobufjs/node_modules/long": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.3.tgz", + "integrity": "sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q==" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", + "optional": true + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/readonly-date": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz", + "integrity": "sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ==", + "optional": true + }, + "node_modules/rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw==", + "optional": true, + "dependencies": { + "resolve": "^1.1.6" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regexp.prototype.flags": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz", + "integrity": "sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "set-function-name": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/rehackt": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/rehackt/-/rehackt-0.0.4.tgz", + "integrity": "sha512-xFroSGCbMEK/cTJVhq+c8l/AzIeMeojVyLqtZmr2jmIAFvePjapkCSGg9MnrcNk68HPaMxGf+Ndqozotu78ITw==", + "optional": true, + "peerDependencies": { + "@types/react": "*", + "react": "*" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "react": { + "optional": true + } + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "devOptional": true, + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve-pkg-maps": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz", + "integrity": "sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==", + "dev": true, + "funding": { + "url": "https://github.com/privatenumber/resolve-pkg-maps?sponsor=1" + } + }, + "node_modules/response-iterator": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz", + "integrity": "sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/ripemd160-min": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz", + "integrity": "sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/rlp": { + "version": "2.2.7", + "resolved": "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz", + "integrity": "sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ==", + "dependencies": { + "bn.js": "^5.2.0" + }, + "bin": { + "rlp": "bin/rlp" + } + }, + "node_modules/rpc-websockets": { + "version": "7.9.0", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.9.0.tgz", + "integrity": "sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw==", + "dependencies": { + "@babel/runtime": "^7.17.2", + "eventemitter3": "^4.0.7", + "uuid": "^8.3.2", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + } + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-array-concat": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz", + "integrity": "sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.5", + "get-intrinsic": "^1.2.2", + "has-symbols": "^1.0.3", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">=0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/safe-array-concat/node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/safe-regex-test": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", + "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-regex": "^1.1.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/scrypt-js": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz", + "integrity": "sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA==" + }, + "node_modules/secp256k1": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz", + "integrity": "sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA==", + "hasInstallScript": true, + "dependencies": { + "elliptic": "^6.5.4", + "node-addon-api": "^2.0.0", + "node-gyp-build": "^4.2.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz", + "integrity": "sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz", + "integrity": "sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g==", + "dev": true, + "dependencies": { + "define-data-property": "^1.1.2", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.3", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/set-function-name": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz", + "integrity": "sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA==", + "dev": true, + "dependencies": { + "define-data-property": "^1.0.1", + "functions-have-names": "^1.2.3", + "has-property-descriptors": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==" + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/sha3": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz", + "integrity": "sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg==", + "dependencies": { + "buffer": "6.0.3" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/shelljs": { + "version": "0.8.5", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", + "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "optional": true, + "dependencies": { + "glob": "^7.0.0", + "interpret": "^1.0.0", + "rechoir": "^0.6.2" + }, + "bin": { + "shjs": "bin/shjs" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/shx": { + "version": "0.3.4", + "resolved": "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz", + "integrity": "sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g==", + "optional": true, + "dependencies": { + "minimist": "^1.2.3", + "shelljs": "^0.8.5" + }, + "bin": { + "shx": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/side-channel": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz", + "integrity": "sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/snake-case": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz", + "integrity": "sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg==", + "license": "MIT", + "dependencies": { + "dot-case": "^3.0.4", + "tslib": "^2.0.3" + } + }, + "node_modules/snakecase-keys": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-5.5.0.tgz", + "integrity": "sha512-r3kRtnoPu3FxGJ3fny6PKNnU3pteb29o6qAa0ugzhSseKNWRkw1dw8nIjXMyyKaU9vQxxVIE62Mb3bKbdrgpiw==", + "optional": true, + "dependencies": { + "map-obj": "^4.1.0", + "snake-case": "^3.0.4", + "type-fest": "^3.12.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/store2": { + "version": "2.14.2", + "resolved": "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz", + "integrity": "sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w==", + "optional": true + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trim": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz", + "integrity": "sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz", + "integrity": "sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz", + "integrity": "sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.2.0", + "es-abstract": "^1.22.1" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/strip-hex-prefix": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz", + "integrity": "sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A==", + "optional": true, + "dependencies": { + "is-hex-prefixed": "1.0.0" + }, + "engines": { + "node": ">=6.5.0", + "npm": ">=3" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/superstruct": { + "version": "0.15.5", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz", + "integrity": "sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ==", + "license": "MIT" + }, + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "devOptional": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "optional": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==" + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "optional": true, + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/through2/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "optional": true + }, + "node_modules/through2/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "optional": true, + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/through2/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "optional": true + }, + "node_modules/through2/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "optional": true, + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/tiny-secp256k1": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz", + "integrity": "sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA==", + "hasInstallScript": true, + "dependencies": { + "bindings": "^1.3.0", + "bn.js": "^4.11.8", + "create-hmac": "^1.1.7", + "elliptic": "^6.4.0", + "nan": "^2.13.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/tiny-secp256k1/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/toml": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz", + "integrity": "sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w==", + "license": "MIT" + }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/ts-api-utils": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz", + "integrity": "sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-invariant": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz", + "integrity": "sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ==", + "optional": true, + "dependencies": { + "tslib": "^2.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ts-mocha": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz", + "integrity": "sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "ts-node": "7.0.1" + }, + "bin": { + "ts-mocha": "bin/ts-mocha" + }, + "engines": { + "node": ">= 6.X.X" + }, + "optionalDependencies": { + "tsconfig-paths": "^3.5.0" + }, + "peerDependencies": { + "mocha": "^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X" + } + }, + "node_modules/ts-node": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz", + "integrity": "sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "arrify": "^1.0.0", + "buffer-from": "^1.1.0", + "diff": "^3.1.0", + "make-error": "^1.1.1", + "minimist": "^1.2.0", + "mkdirp": "^0.5.1", + "source-map-support": "^0.5.6", + "yn": "^2.0.0" + }, + "bin": { + "ts-node": "dist/bin.js" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/ts-node/node_modules/diff": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz", + "integrity": "sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "license": "0BSD" + }, + "node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==" + }, + "node_modules/tweetnacl-util": { + "version": "0.15.1", + "resolved": "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz", + "integrity": "sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw==", + "optional": true + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "3.13.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz", + "integrity": "sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g==", + "optional": true, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/typed-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz", + "integrity": "sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.6", + "es-errors": "^1.3.0", + "is-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/typed-array-byte-length": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz", + "integrity": "sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-byte-offset": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz", + "integrity": "sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.5", + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "has-proto": "^1.0.1", + "is-typed-array": "^1.1.10" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typed-array-length": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz", + "integrity": "sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "for-each": "^0.3.3", + "is-typed-array": "^1.1.9" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/typeforce": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "dev": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/u3": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/u3/-/u3-0.1.1.tgz", + "integrity": "sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w==" + }, + "node_modules/unbox-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", + "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-bigints": "^1.0.2", + "has-symbols": "^1.0.3", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utf-8-validate": { + "version": "5.0.10", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz", + "integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==", + "hasInstallScript": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/vlq": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz", + "integrity": "sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA==" + }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-typed-array": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz", + "integrity": "sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg==", + "dev": true, + "dependencies": { + "available-typed-arrays": "^1.0.6", + "call-bind": "^1.0.5", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "has-tostringtag": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wif": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", + "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", + "dependencies": { + "bs58check": "<3.0.0" + } + }, + "node_modules/workerpool": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz", + "integrity": "sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "license": "ISC" + }, + "node_modules/ws": { + "version": "7.5.9", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz", + "integrity": "sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q==", + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xstream": { + "version": "11.14.0", + "resolved": "https://registry.npmjs.org/xstream/-/xstream-11.14.0.tgz", + "integrity": "sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw==", + "optional": true, + "dependencies": { + "globalthis": "^1.0.1", + "symbol-observable": "^2.0.3" + } + }, + "node_modules/xstream/node_modules/symbol-observable": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz", + "integrity": "sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA==", + "optional": true, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "optional": true, + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "devOptional": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "20.2.4", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", + "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-unparser": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz", + "integrity": "sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "camelcase": "^6.0.0", + "decamelize": "^4.0.0", + "flat": "^5.0.2", + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "20.2.9", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz", + "integrity": "sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w==", + "devOptional": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yn": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz", + "integrity": "sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zen-observable": { + "version": "0.8.15", + "resolved": "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz", + "integrity": "sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==", + "optional": true + }, + "node_modules/zen-observable-ts": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz", + "integrity": "sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg==", + "optional": true, + "dependencies": { + "zen-observable": "0.8.15" + } + } + } +} diff --git a/solana/package.json b/solana/package.json index bde2858ad..5ababb583 100644 --- a/solana/package.json +++ b/solana/package.json @@ -5,16 +5,27 @@ "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" }, "dependencies": { - "@coral-xyz/anchor": "^0.28.0" + "@certusone/wormhole-sdk": "^0.10.10", + "@coral-xyz/anchor": "^0.29.0", + "@solana/spl-token": "^0.4.0" }, "devDependencies": { - "chai": "^4.3.4", - "mocha": "^9.0.3", - "ts-mocha": "^10.0.0", + "@stylistic/eslint-plugin": "^1.6.1", + "@stylistic/eslint-plugin-js": "^1.6.1", + "@stylistic/eslint-plugin-ts": "^1.6.1", "@types/bn.js": "^5.1.0", "@types/chai": "^4.3.0", "@types/mocha": "^9.0.0", - "typescript": "^4.3.5", - "prettier": "^2.6.2" + "@typescript-eslint/eslint-plugin": "^6.21.0", + "chai": "^4.3.4", + "eslint": "^8.56.0", + "eslint-config-standard-with-typescript": "^43.0.1", + "eslint-plugin-import": "^2.29.1", + "eslint-plugin-n": "^16.6.2", + "eslint-plugin-promise": "^6.1.1", + "mocha": "^9.0.3", + "prettier": "^2.6.2", + "ts-mocha": "^10.0.0", + "typescript": "^4.9.5" } } diff --git a/solana/tsconfig.json b/solana/tsconfig.json index 558b83e5e..f9914254d 100644 --- a/solana/tsconfig.json +++ b/solana/tsconfig.json @@ -5,7 +5,7 @@ "lib": ["es2015"], "module": "commonjs", "target": "es6", - "esModuleInterop": true + "esModuleInterop": true, + "strictNullChecks": true } } - \ No newline at end of file diff --git a/solana/yarn.lock b/solana/yarn.lock index b2834db0f..5b1b72d0d 100644 --- a/solana/yarn.lock +++ b/solana/yarn.lock @@ -2,21 +2,116 @@ # yarn lockfile v1 +"@aashutoshrathi/word-wrap@^1.2.3": + version "1.2.6" + resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" + integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== + +"@apollo/client@^3.5.8": + version "3.9.4" + resolved "https://registry.npmjs.org/@apollo/client/-/client-3.9.4.tgz" + integrity sha512-Ip6dxjshDT2Dp6foLASTnKBW45Fytew/5JZutZwgc78hVrrGpO9UtZA9xteHXYdap0wIgCxCfeIQwbSu1ZdQpw== + dependencies: + "@graphql-typed-document-node/core" "^3.1.1" + "@wry/caches" "^1.0.0" + "@wry/equality" "^0.5.6" + "@wry/trie" "^0.5.0" + graphql-tag "^2.12.6" + hoist-non-react-statics "^3.3.2" + optimism "^0.18.0" + prop-types "^15.7.2" + rehackt "0.0.4" + response-iterator "^0.2.6" + symbol-observable "^4.0.0" + ts-invariant "^0.10.3" + tslib "^2.3.0" + zen-observable-ts "^1.2.5" + "@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4": - version "7.23.8" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.23.8.tgz#8ee6fe1ac47add7122902f257b8ddf55c898f650" - integrity sha512-Y7KbAP984rn1VGMbGqKmBLio9V7y5Je9GvU4rQPCPinCyNfUcToxIXl06d59URp/F3LwinvODxab5N/G6qggkw== + version "7.23.9" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz" + integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== dependencies: regenerator-runtime "^0.14.0" -"@coral-xyz/anchor@^0.28.0": - version "0.28.0" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.28.0.tgz#8345c3c9186a91f095f704d7b90cd256f7e8b2dc" - integrity sha512-kQ02Hv2ZqxtWP30WN1d4xxT4QqlOXYDxmEd3k/bbneqhV3X5QMO4LAtoUFs7otxyivOgoqam5Il5qx81FuI4vw== +"@babel/runtime@7.20.13": + version "7.20.13" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz" + integrity sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA== + dependencies: + regenerator-runtime "^0.13.11" + +"@certusone/wormhole-sdk-proto-web@0.0.7": + version "0.0.7" + resolved "https://registry.npmjs.org/@certusone/wormhole-sdk-proto-web/-/wormhole-sdk-proto-web-0.0.7.tgz" + integrity sha512-GCe1/bcqMS0Mt+hsWp4SE4NLL59pWmK0lhQXO0oqAKl0G9AuuTdudySMDF/sLc7z5H2w34bSuSrIEKvPuuSC+w== + dependencies: + "@improbable-eng/grpc-web" "^0.15.0" + protobufjs "^7.0.0" + rxjs "^7.5.6" + +"@certusone/wormhole-sdk-wasm@^0.0.1": + version "0.0.1" + resolved "https://registry.npmjs.org/@certusone/wormhole-sdk-wasm/-/wormhole-sdk-wasm-0.0.1.tgz" + integrity sha512-LdIwLhOyr4pPs2jqYubqC7d4UkqYBX0EG/ppspQlW3qlVE0LZRMrH6oVzzLMyHtV0Rw7O9sIKzORW/T3mrJv2w== + dependencies: + "@types/long" "^4.0.2" + "@types/node" "^18.0.3" + +"@certusone/wormhole-sdk@^0.10.10": + version "0.10.10" + resolved "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.10.10.tgz" + integrity sha512-2pYQ2/+cSfh/LVtOTXQDrTeZdXHgzq/hjkTevzW5+rEqITE54qUlnMhcVtSJQe+Yvgg3awrP2mIfDW3nvwPIPA== + dependencies: + "@certusone/wormhole-sdk-proto-web" "0.0.7" + "@certusone/wormhole-sdk-wasm" "^0.0.1" + "@coral-xyz/borsh" "0.2.6" + "@mysten/sui.js" "0.32.2" + "@project-serum/anchor" "^0.25.0" + "@solana/spl-token" "^0.3.5" + "@solana/web3.js" "^1.66.2" + "@terra-money/terra.js" "3.1.9" + "@xpla/xpla.js" "^0.2.1" + algosdk "^2.4.0" + aptos "1.5.0" + axios "^0.24.0" + bech32 "^2.0.0" + binary-parser "^2.2.1" + bs58 "^4.0.1" + elliptic "^6.5.4" + js-base64 "^3.6.1" + near-api-js "^1.0.0" + optionalDependencies: + "@injectivelabs/networks" "1.10.12" + "@injectivelabs/sdk-ts" "1.10.72" + "@injectivelabs/utils" "1.10.12" + +"@classic-terra/terra.proto@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@classic-terra/terra.proto/-/terra.proto-1.1.0.tgz" + integrity sha512-bYhQG5LUaGF0KPRY9hYT/HEcd1QExZPQd6zLV/rQkCe/eDxfwFRLzZHpaaAdfWoAAZjsRWqJbUCqCg7gXBbJpw== + dependencies: + "@improbable-eng/grpc-web" "^0.14.1" + google-protobuf "^3.17.3" + long "^4.0.0" + protobufjs "~6.11.2" + +"@confio/ics23@^0.6.8": + version "0.6.8" + resolved "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.8.tgz" + integrity sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w== dependencies: - "@coral-xyz/borsh" "^0.28.0" + "@noble/hashes" "^1.0.0" + protobufjs "^6.8.8" + +"@coral-xyz/anchor@^0.29.0": + version "0.29.0" + resolved "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.29.0.tgz" + integrity sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA== + dependencies: + "@coral-xyz/borsh" "^0.29.0" + "@noble/hashes" "^1.3.1" "@solana/web3.js" "^1.68.0" - base64-js "^1.5.1" bn.js "^5.1.2" bs58 "^4.0.1" buffer-layout "^1.2.2" @@ -24,43 +119,1040 @@ cross-fetch "^3.1.5" crypto-hash "^1.3.0" eventemitter3 "^4.0.7" - js-sha256 "^0.9.0" pako "^2.0.3" snake-case "^3.0.4" superstruct "^0.15.4" toml "^3.0.0" -"@coral-xyz/borsh@^0.28.0": - version "0.28.0" - resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.28.0.tgz#fa368a2f2475bbf6f828f4657f40a52102e02b6d" - integrity sha512-/u1VTzw7XooK7rqeD7JLUSwOyRSesPUk0U37BV9zK0axJc1q0nRbKFGFLYCQ16OtdOJTTwGfGp11Lx9B45bRCQ== +"@coral-xyz/borsh@^0.29.0": + version "0.29.0" + resolved "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.29.0.tgz" + integrity sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@coral-xyz/borsh@0.2.6": + version "0.2.6" + resolved "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.2.6.tgz" + integrity sha512-y6nmHw1bFcJib7sMHsQPpC8r47xhqDZVvhUdna7NUPzpSbOZG6f46N21+aXsQ2w/tG8Ggls488J/ZmwbgVmyjg== dependencies: bn.js "^5.1.2" buffer-layout "^1.2.0" -"@noble/curves@^1.2.0": +"@cosmjs/amino@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz" + integrity sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w== + dependencies: + "@cosmjs/crypto" "^0.30.1" + "@cosmjs/encoding" "^0.30.1" + "@cosmjs/math" "^0.30.1" + "@cosmjs/utils" "^0.30.1" + +"@cosmjs/crypto@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz" + integrity sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ== + dependencies: + "@cosmjs/encoding" "^0.30.1" + "@cosmjs/math" "^0.30.1" + "@cosmjs/utils" "^0.30.1" + "@noble/hashes" "^1" + bn.js "^5.2.0" + elliptic "^6.5.4" + libsodium-wrappers "^0.7.6" + +"@cosmjs/encoding@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.30.1.tgz" + integrity sha512-rXmrTbgqwihORwJ3xYhIgQFfMSrwLu1s43RIK9I8EBudPx3KmnmyAKzMOVsRDo9edLFNuZ9GIvysUCwQfq3WlQ== + dependencies: + base64-js "^1.3.0" + bech32 "^1.1.4" + readonly-date "^1.0.0" + +"@cosmjs/json-rpc@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.30.1.tgz" + integrity sha512-pitfC/2YN9t+kXZCbNuyrZ6M8abnCC2n62m+JtU9vQUfaEtVsgy+1Fk4TRQ175+pIWSdBMFi2wT8FWVEE4RhxQ== + dependencies: + "@cosmjs/stream" "^0.30.1" + xstream "^11.14.0" + +"@cosmjs/math@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.30.1.tgz" + integrity sha512-yaoeI23pin9ZiPHIisa6qqLngfnBR/25tSaWpkTm8Cy10MX70UF5oN4+/t1heLaM6SSmRrhk3psRkV4+7mH51Q== + dependencies: + bn.js "^5.2.0" + +"@cosmjs/proto-signing@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz" + integrity sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ== + dependencies: + "@cosmjs/amino" "^0.30.1" + "@cosmjs/crypto" "^0.30.1" + "@cosmjs/encoding" "^0.30.1" + "@cosmjs/math" "^0.30.1" + "@cosmjs/utils" "^0.30.1" + cosmjs-types "^0.7.1" + long "^4.0.0" + +"@cosmjs/socket@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.30.1.tgz" + integrity sha512-r6MpDL+9N+qOS/D5VaxnPaMJ3flwQ36G+vPvYJsXArj93BjgyFB7BwWwXCQDzZ+23cfChPUfhbINOenr8N2Kow== + dependencies: + "@cosmjs/stream" "^0.30.1" + isomorphic-ws "^4.0.1" + ws "^7" + xstream "^11.14.0" + +"@cosmjs/stargate@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.30.1.tgz" + integrity sha512-RdbYKZCGOH8gWebO7r6WvNnQMxHrNXInY/gPHPzMjbQF6UatA6fNM2G2tdgS5j5u7FTqlCI10stNXrknaNdzog== + dependencies: + "@confio/ics23" "^0.6.8" + "@cosmjs/amino" "^0.30.1" + "@cosmjs/encoding" "^0.30.1" + "@cosmjs/math" "^0.30.1" + "@cosmjs/proto-signing" "^0.30.1" + "@cosmjs/stream" "^0.30.1" + "@cosmjs/tendermint-rpc" "^0.30.1" + "@cosmjs/utils" "^0.30.1" + cosmjs-types "^0.7.1" + long "^4.0.0" + protobufjs "~6.11.3" + xstream "^11.14.0" + +"@cosmjs/stream@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.30.1.tgz" + integrity sha512-Fg0pWz1zXQdoxQZpdHRMGvUH5RqS6tPv+j9Eh7Q953UjMlrwZVo0YFLC8OTf/HKVf10E4i0u6aM8D69Q6cNkgQ== + dependencies: + xstream "^11.14.0" + +"@cosmjs/tendermint-rpc@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.30.1.tgz" + integrity sha512-Z3nCwhXSbPZJ++v85zHObeUggrEHVfm1u18ZRwXxFE9ZMl5mXTybnwYhczuYOl7KRskgwlB+rID0WYACxj4wdQ== + dependencies: + "@cosmjs/crypto" "^0.30.1" + "@cosmjs/encoding" "^0.30.1" + "@cosmjs/json-rpc" "^0.30.1" + "@cosmjs/math" "^0.30.1" + "@cosmjs/socket" "^0.30.1" + "@cosmjs/stream" "^0.30.1" + "@cosmjs/utils" "^0.30.1" + axios "^0.21.2" + readonly-date "^1.0.0" + xstream "^11.14.0" + +"@cosmjs/utils@^0.30.1": + version "0.30.1" + resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz" + integrity sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g== + +"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": + version "4.4.0" + resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" + integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== + dependencies: + eslint-visitor-keys "^3.3.0" + +"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.0", "@eslint-community/regexpp@^4.6.1": + version "4.10.0" + resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz" + integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== + +"@eslint/eslintrc@^2.1.4": + version "2.1.4" + resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz" + integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== + dependencies: + ajv "^6.12.4" + debug "^4.3.2" + espree "^9.6.0" + globals "^13.19.0" + ignore "^5.2.0" + import-fresh "^3.2.1" + js-yaml "^4.1.0" + minimatch "^3.1.2" + strip-json-comments "^3.1.1" + +"@eslint/js@8.56.0": + version "8.56.0" + resolved "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz" + integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== + +"@ethereumjs/common@^2.6.4": + version "2.6.5" + resolved "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz" + integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== + dependencies: + crc-32 "^1.2.0" + ethereumjs-util "^7.1.5" + +"@ethereumjs/tx@3.5.2": + version "3.5.2" + resolved "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz" + integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== + dependencies: + "@ethereumjs/common" "^2.6.4" + ethereumjs-util "^7.1.5" + +"@ethersproject/abi@^5.7.0", "@ethersproject/abi@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" + integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" + integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + +"@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" + integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/address@^5.7.0", "@ethersproject/address@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" + integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + +"@ethersproject/base64@^5.7.0", "@ethersproject/base64@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" + integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + +"@ethersproject/basex@^5.7.0", "@ethersproject/basex@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" + integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + +"@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" + integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + bn.js "^5.2.1" + +"@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" + integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/constants@^5.7.0", "@ethersproject/constants@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" + integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + +"@ethersproject/contracts@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" + integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== + dependencies: + "@ethersproject/abi" "^5.7.0" + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + +"@ethersproject/hash@^5.7.0", "@ethersproject/hash@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" + integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/hdnode@^5.7.0", "@ethersproject/hdnode@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" + integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/json-wallets@^5.7.0", "@ethersproject/json-wallets@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" + integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== + dependencies: + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/pbkdf2" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + aes-js "3.0.0" + scrypt-js "3.0.1" + +"@ethersproject/keccak256@^5.6.1", "@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" + integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + js-sha3 "0.8.0" + +"@ethersproject/logger@^5.7.0", "@ethersproject/logger@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" + integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== + +"@ethersproject/networks@^5.7.0", "@ethersproject/networks@5.7.1": + version "5.7.1" + resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz" + integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/pbkdf2@^5.7.0", "@ethersproject/pbkdf2@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" + integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + +"@ethersproject/properties@^5.7.0", "@ethersproject/properties@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" + integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== + dependencies: + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/providers@5.7.2": + version "5.7.2" + resolved "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz" + integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/base64" "^5.7.0" + "@ethersproject/basex" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/networks" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/web" "^5.7.0" + bech32 "1.1.4" + ws "7.4.6" + +"@ethersproject/random@^5.7.0", "@ethersproject/random@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" + integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" + integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/sha2@^5.7.0", "@ethersproject/sha2@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" + integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + hash.js "1.1.7" + +"@ethersproject/signing-key@^5.6.2", "@ethersproject/signing-key@^5.7.0", "@ethersproject/signing-key@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" + integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + bn.js "^5.2.1" + elliptic "6.5.4" + hash.js "1.1.7" + +"@ethersproject/solidity@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" + integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/sha2" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/strings@^5.7.0", "@ethersproject/strings@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" + integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" + integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== + dependencies: + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/rlp" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + +"@ethersproject/units@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" + integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== + dependencies: + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/constants" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + +"@ethersproject/wallet@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" + integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== + dependencies: + "@ethersproject/abstract-provider" "^5.7.0" + "@ethersproject/abstract-signer" "^5.7.0" + "@ethersproject/address" "^5.7.0" + "@ethersproject/bignumber" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/hdnode" "^5.7.0" + "@ethersproject/json-wallets" "^5.7.0" + "@ethersproject/keccak256" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/random" "^5.7.0" + "@ethersproject/signing-key" "^5.7.0" + "@ethersproject/transactions" "^5.7.0" + "@ethersproject/wordlists" "^5.7.0" + +"@ethersproject/web@^5.7.0", "@ethersproject/web@5.7.1": + version "5.7.1" + resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz" + integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== + dependencies: + "@ethersproject/base64" "^5.7.0" + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@ethersproject/wordlists@^5.7.0", "@ethersproject/wordlists@5.7.0": + version "5.7.0" + resolved "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" + integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== + dependencies: + "@ethersproject/bytes" "^5.7.0" + "@ethersproject/hash" "^5.7.0" + "@ethersproject/logger" "^5.7.0" + "@ethersproject/properties" "^5.7.0" + "@ethersproject/strings" "^5.7.0" + +"@graphql-typed-document-node/core@^3.1.1": + version "3.2.0" + resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz" + integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== + +"@humanwhocodes/config-array@^0.11.13": + version "0.11.14" + resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz" + integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== + dependencies: + "@humanwhocodes/object-schema" "^2.0.2" + debug "^4.3.1" + minimatch "^3.0.5" + +"@humanwhocodes/module-importer@^1.0.1": + version "1.0.1" + resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" + integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== + +"@humanwhocodes/object-schema@^2.0.2": + version "2.0.2" + resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz" + integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== + +"@improbable-eng/grpc-web@^0.14.1": + version "0.14.1" + resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.14.1.tgz" + integrity sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw== + dependencies: + browser-headers "^0.4.1" + +"@improbable-eng/grpc-web@^0.15.0": + version "0.15.0" + resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz" + integrity sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg== + dependencies: + browser-headers "^0.4.1" + +"@injectivelabs/core-proto-ts@^0.0.14": + version "0.0.14" + resolved "https://registry.npmjs.org/@injectivelabs/core-proto-ts/-/core-proto-ts-0.0.14.tgz" + integrity sha512-NZWlgBzgVrXow9IknFQHvcYKX4QkUD25taRigoNYQK8PDn4+VXd9xM5WFUDRhzm2smTCguyl/+MghpEp4oTPWw== + dependencies: + "@injectivelabs/grpc-web" "^0.0.1" + google-protobuf "^3.14.0" + protobufjs "^7.0.0" + rxjs "^7.4.0" + +"@injectivelabs/exceptions@^1.10.12", "@injectivelabs/exceptions@^1.14.5": + version "1.14.5" + resolved "https://registry.npmjs.org/@injectivelabs/exceptions/-/exceptions-1.14.5.tgz" + integrity sha512-WQ+hxpKz4g4+ZXNTXLFKpf9D9uosleZLqC++2+wK81IQ/lcwi5GrTLYdasOhJeu3c+LKWxHQRHJfSsvt8TQWbA== + dependencies: + "@injectivelabs/grpc-web" "^0.0.1" + "@injectivelabs/ts-types" "^1.14.5" + http-status-codes "^2.2.0" + link-module-alias "^1.2.0" + shx "^0.3.2" + +"@injectivelabs/grpc-web-node-http-transport@^0.0.2": + version "0.0.2" + resolved "https://registry.npmjs.org/@injectivelabs/grpc-web-node-http-transport/-/grpc-web-node-http-transport-0.0.2.tgz" + integrity sha512-rpyhXLiGY/UMs6v6YmgWHJHiO9l0AgDyVNv+jcutNVt4tQrmNvnpvz2wCAGOFtq5LuX/E9ChtTVpk3gWGqXcGA== + +"@injectivelabs/grpc-web-react-native-transport@^0.0.2": + version "0.0.2" + resolved "https://registry.npmjs.org/@injectivelabs/grpc-web-react-native-transport/-/grpc-web-react-native-transport-0.0.2.tgz" + integrity sha512-mk+aukQXnYNgPsPnu3KBi+FD0ZHQpazIlaBZ2jNZG7QAVmxTWtv3R66Zoq99Wx2dnE946NsZBYAoa0K5oSjnow== + +"@injectivelabs/grpc-web@^0.0.1", "@injectivelabs/grpc-web@>=0.0.1": + version "0.0.1" + resolved "https://registry.npmjs.org/@injectivelabs/grpc-web/-/grpc-web-0.0.1.tgz" + integrity sha512-Pu5YgaZp+OvR5UWfqbrPdHer3+gDf+b5fQoY+t2VZx1IAVHX8bzbN9EreYTvTYtFeDpYRWM8P7app2u4EX5wTw== + dependencies: + browser-headers "^0.4.1" + +"@injectivelabs/indexer-proto-ts@1.10.8-rc.4": + version "1.10.8-rc.4" + resolved "https://registry.npmjs.org/@injectivelabs/indexer-proto-ts/-/indexer-proto-ts-1.10.8-rc.4.tgz" + integrity sha512-IwbepTfsHHAv3Z36As6yH/+HIplOEpUu6SFHBCVgdSIaQ8GuvTib4HETiVnV4mjYqoyVgWs+zLSAfih46rdMJQ== + dependencies: + "@injectivelabs/grpc-web" "^0.0.1" + google-protobuf "^3.14.0" + protobufjs "^7.0.0" + rxjs "^7.4.0" + +"@injectivelabs/mito-proto-ts@1.0.9": + version "1.0.9" + resolved "https://registry.npmjs.org/@injectivelabs/mito-proto-ts/-/mito-proto-ts-1.0.9.tgz" + integrity sha512-+TZMvJ4SHwcn6SFPdqaiQFZdNhjH7hyRFozY15nOTC2utdGij9jEsjz1NsyOejfYDA0s1z5Wm1SgrMYKaVpAmQ== + dependencies: + "@injectivelabs/grpc-web" "^0.0.1" + google-protobuf "^3.14.0" + protobufjs "^7.0.0" + rxjs "^7.4.0" + +"@injectivelabs/networks@^1.10.12", "@injectivelabs/networks@1.10.12": + version "1.10.12" + resolved "https://registry.npmjs.org/@injectivelabs/networks/-/networks-1.10.12.tgz" + integrity sha512-tTHyLls1Nik5QTs/S03qqG2y/ITvNwI8CJOQbMmmsr1CL2CdjJBtzRYn9Dyx2p8XgzRFf9hmlybpe20tq9O3SA== + dependencies: + "@injectivelabs/exceptions" "^1.10.12" + "@injectivelabs/ts-types" "^1.10.12" + "@injectivelabs/utils" "^1.10.12" + link-module-alias "^1.2.0" + shx "^0.3.2" + +"@injectivelabs/networks@^1.14.5": + version "1.14.5" + resolved "https://registry.npmjs.org/@injectivelabs/networks/-/networks-1.14.5.tgz" + integrity sha512-9GINd/pPBX6Jyc26pmlLC54s7nLlXsBLZ/1fo8a0nvHkrrODRDE4IldP6KsA9OLVomMPk5TyBUgYLGgM3ST9GA== + dependencies: + "@injectivelabs/exceptions" "^1.14.5" + "@injectivelabs/ts-types" "^1.14.5" + "@injectivelabs/utils" "^1.14.5" + link-module-alias "^1.2.0" + shx "^0.3.2" + +"@injectivelabs/sdk-ts@1.10.72": + version "1.10.72" + resolved "https://registry.npmjs.org/@injectivelabs/sdk-ts/-/sdk-ts-1.10.72.tgz" + integrity sha512-A5mHNNBgO4fI1c/7CZ0bGfVXliy8laP+VaYZ++aWh1YyudoZw4CTCEmLetZRy7AUU3XcfbHa8sAImRi7db+v6Q== + dependencies: + "@apollo/client" "^3.5.8" + "@cosmjs/amino" "^0.30.1" + "@cosmjs/proto-signing" "^0.30.1" + "@cosmjs/stargate" "^0.30.1" + "@ethersproject/bytes" "^5.7.0" + "@injectivelabs/core-proto-ts" "^0.0.14" + "@injectivelabs/exceptions" "^1.10.12" + "@injectivelabs/grpc-web" "^0.0.1" + "@injectivelabs/grpc-web-node-http-transport" "^0.0.2" + "@injectivelabs/grpc-web-react-native-transport" "^0.0.2" + "@injectivelabs/indexer-proto-ts" "1.10.8-rc.4" + "@injectivelabs/mito-proto-ts" "1.0.9" + "@injectivelabs/networks" "^1.10.12" + "@injectivelabs/test-utils" "^1.10.12" + "@injectivelabs/token-metadata" "^1.10.42" + "@injectivelabs/ts-types" "^1.10.12" + "@injectivelabs/utils" "^1.10.12" + "@metamask/eth-sig-util" "^4.0.0" + axios "^0.27.2" + bech32 "^2.0.0" + bip39 "^3.0.4" + cosmjs-types "^0.7.1" + eth-crypto "^2.6.0" + ethereumjs-util "^7.1.4" + ethers "^5.7.2" + google-protobuf "^3.21.0" + graphql "^16.3.0" + http-status-codes "^2.2.0" + js-sha3 "^0.8.0" + jscrypto "^1.0.3" + keccak256 "^1.0.6" + link-module-alias "^1.2.0" + rxjs "^7.8.0" + secp256k1 "^4.0.3" + shx "^0.3.2" + snakecase-keys "^5.4.1" + +"@injectivelabs/test-utils@^1.10.12": + version "1.14.3" + resolved "https://registry.npmjs.org/@injectivelabs/test-utils/-/test-utils-1.14.3.tgz" + integrity sha512-dVe262sACa7YkRr7mfXx58yI/ieuQqm3IMGq7EMweFKI6Kh2gh8FAM2bsDgm1cGewEIhJ9tWh6OM5uNheeVamg== + dependencies: + axios "^0.21.1" + bignumber.js "^9.0.1" + link-module-alias "^1.2.0" + shx "^0.3.2" + snakecase-keys "^5.1.2" + store2 "^2.12.0" + +"@injectivelabs/token-metadata@^1.10.42": + version "1.14.5" + resolved "https://registry.npmjs.org/@injectivelabs/token-metadata/-/token-metadata-1.14.5.tgz" + integrity sha512-GiIiNDixfvbfEjzZG7ixtGYmJllFIcA2Xl1LnsK5yawT8Q+/SoSIJig4tE+0CC/AaGHS1GxDKySrIdMse7PZ0w== + dependencies: + "@injectivelabs/exceptions" "^1.14.5" + "@injectivelabs/networks" "^1.14.5" + "@injectivelabs/ts-types" "^1.14.5" + "@injectivelabs/utils" "^1.14.5" + "@types/lodash.values" "^4.3.6" + copyfiles "^2.4.1" + jsonschema "^1.4.0" + link-module-alias "^1.2.0" + lodash "^4.17.21" + lodash.values "^4.3.0" + shx "^0.3.2" + +"@injectivelabs/ts-types@^1.10.12", "@injectivelabs/ts-types@^1.14.5": + version "1.14.5" + resolved "https://registry.npmjs.org/@injectivelabs/ts-types/-/ts-types-1.14.5.tgz" + integrity sha512-dwmEJE90vMr1zkQhz5lX2280sBMe2GvAj98vOHoL2RLTo0OQkJZrirUHwsTkexJf7sFZIT2PlmLCfix9Ulcp5A== + dependencies: + link-module-alias "^1.2.0" + shx "^0.3.2" + +"@injectivelabs/utils@^1.10.12", "@injectivelabs/utils@1.10.12": + version "1.10.12" + resolved "https://registry.npmjs.org/@injectivelabs/utils/-/utils-1.10.12.tgz" + integrity sha512-c8al79nxIJgV1cBAdW2TPDGldj/8gm5k0h5TIN/AJs8/AeIjpTwwVGfLY3QvPOpRsxuQ9CjBkTXrAcSL1wwkcw== + dependencies: + "@injectivelabs/exceptions" "^1.10.12" + "@injectivelabs/ts-types" "^1.10.12" + axios "^0.21.1" + bignumber.js "^9.0.1" + http-status-codes "^2.2.0" + link-module-alias "^1.2.0" + shx "^0.3.2" + snakecase-keys "^5.1.2" + store2 "^2.12.0" + +"@injectivelabs/utils@^1.14.5": + version "1.14.5" + resolved "https://registry.npmjs.org/@injectivelabs/utils/-/utils-1.14.5.tgz" + integrity sha512-L2ul/7rgop8RLJBhlXjt6Q/A6fXeRZ3hhCZFXGXmA63vz9RSqOFHILiRp6hAFsuZbiITjmVx0eubFPaQU0MymA== + dependencies: + "@injectivelabs/exceptions" "^1.14.5" + "@injectivelabs/ts-types" "^1.14.5" + axios "^0.21.1" + bignumber.js "^9.0.1" + http-status-codes "^2.2.0" + link-module-alias "^1.2.0" + shx "^0.3.2" + snakecase-keys "^5.1.2" + store2 "^2.12.0" + +"@metamask/eth-sig-util@^4.0.0": + version "4.0.1" + resolved "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz" + integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== + dependencies: + ethereumjs-abi "^0.6.8" + ethereumjs-util "^6.2.1" + ethjs-util "^0.1.6" + tweetnacl "^1.0.3" + tweetnacl-util "^0.15.1" + +"@mysten/bcs@0.7.1": + version "0.7.1" + resolved "https://registry.npmjs.org/@mysten/bcs/-/bcs-0.7.1.tgz" + integrity sha512-wFPb8bkhwrbiStfZMV5rFM7J+umpke59/dNjDp+UYJKykNlW23LCk2ePyEUvGdb62HGJM1jyOJ8g4egE3OmdKA== + dependencies: + bs58 "^5.0.0" + +"@mysten/sui.js@0.32.2": + version "0.32.2" + resolved "https://registry.npmjs.org/@mysten/sui.js/-/sui.js-0.32.2.tgz" + integrity sha512-/Hm4xkGolJhqj8FvQr7QSHDTlxIvL52mtbOao9f75YjrBh7y1Uh9kbJSY7xiTF1NY9sv6p5hUVlYRJuM0Hvn9A== + dependencies: + "@mysten/bcs" "0.7.1" + "@noble/curves" "^1.0.0" + "@noble/hashes" "^1.3.0" + "@scure/bip32" "^1.3.0" + "@scure/bip39" "^1.2.0" + "@suchipi/femver" "^1.0.0" + jayson "^4.0.0" + rpc-websockets "^7.5.1" + superstruct "^1.0.3" + tweetnacl "^1.0.3" + +"@noble/curves@^1.0.0", "@noble/curves@^1.2.0", "@noble/curves@~1.3.0": version "1.3.0" - resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.3.0.tgz#01be46da4fd195822dab821e72f71bf4aeec635e" + resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz" integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== dependencies: "@noble/hashes" "1.3.3" -"@noble/hashes@1.3.3", "@noble/hashes@^1.3.2": +"@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.2.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.2", "@noble/hashes@~1.3.2", "@noble/hashes@1.3.3": version "1.3.3" - resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.3.3.tgz#39908da56a4adc270147bb07968bf3b16cfe1699" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz" integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== -"@solana/buffer-layout@^4.0.1": +"@noble/hashes@~1.1.1", "@noble/hashes@1.1.3": + version "1.1.3" + resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.3.tgz" + integrity sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A== + +"@nodelib/fs.scandir@2.1.5": + version "2.1.5" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" + integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== + dependencies: + "@nodelib/fs.stat" "2.0.5" + run-parallel "^1.1.9" + +"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": + version "2.0.5" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" + integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== + +"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": + version "1.2.8" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" + integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== + dependencies: + "@nodelib/fs.scandir" "2.1.5" + fastq "^1.6.0" + +"@project-serum/anchor@^0.25.0": + version "0.25.0" + resolved "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.25.0.tgz" + integrity sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A== + dependencies: + "@project-serum/borsh" "^0.2.5" + "@solana/web3.js" "^1.36.0" + base64-js "^1.5.1" + bn.js "^5.1.2" + bs58 "^4.0.1" + buffer-layout "^1.2.2" + camelcase "^5.3.1" + cross-fetch "^3.1.5" + crypto-hash "^1.3.0" + eventemitter3 "^4.0.7" + js-sha256 "^0.9.0" + pako "^2.0.3" + snake-case "^3.0.4" + superstruct "^0.15.4" + toml "^3.0.0" + +"@project-serum/borsh@^0.2.5": + version "0.2.5" + resolved "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.5.tgz" + integrity sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + +"@scure/base@~1.1.0", "@scure/base@~1.1.4": + version "1.1.5" + resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz" + integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== + +"@scure/bip32@^1.3.0": + version "1.3.3" + resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz" + integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== + dependencies: + "@noble/curves" "~1.3.0" + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + +"@scure/bip39@^1.2.0": + version "1.2.2" + resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz" + integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== + dependencies: + "@noble/hashes" "~1.3.2" + "@scure/base" "~1.1.4" + +"@scure/bip39@1.1.0": + version "1.1.0" + resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz" + integrity sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w== + dependencies: + "@noble/hashes" "~1.1.1" + "@scure/base" "~1.1.0" + +"@solana/buffer-layout-utils@^0.2.0": + version "0.2.0" + resolved "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz" + integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/web3.js" "^1.32.0" + bigint-buffer "^1.1.5" + bignumber.js "^9.0.1" + +"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1": version "4.0.1" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + resolved "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz" integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== dependencies: buffer "~6.0.3" -"@solana/web3.js@^1.68.0": - version "1.89.1" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.89.1.tgz#52df6820f2d088c4558aa359af40580a03d10ec9" - integrity sha512-t9TTLtPQxtQB3SAf/5E8xPXfVDsC6WGOsgKY02l2cbe0HLymT7ynE8Hu48Lk5qynHCquj6nhISfEHcjMkYpu/A== +"@solana/codecs-core@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz" + integrity sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA== + +"@solana/codecs-data-structures@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz" + integrity sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + +"@solana/codecs-numbers@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz" + integrity sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + +"@solana/codecs-strings@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz" + integrity sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + +"@solana/options@2.0.0-experimental.8618508": + version "2.0.0-experimental.8618508" + resolved "https://registry.npmjs.org/@solana/options/-/options-2.0.0-experimental.8618508.tgz" + integrity sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + +"@solana/spl-token-metadata@^0.1.2": + version "0.1.2" + resolved "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz" + integrity sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw== + dependencies: + "@solana/codecs-core" "2.0.0-experimental.8618508" + "@solana/codecs-data-structures" "2.0.0-experimental.8618508" + "@solana/codecs-numbers" "2.0.0-experimental.8618508" + "@solana/codecs-strings" "2.0.0-experimental.8618508" + "@solana/options" "2.0.0-experimental.8618508" + "@solana/spl-type-length-value" "0.1.0" + +"@solana/spl-token@^0.3.5": + version "0.3.11" + resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.11.tgz" + integrity sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-metadata" "^0.1.2" + buffer "^6.0.3" + +"@solana/spl-token@^0.4.0": + version "0.4.0" + resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.0.tgz" + integrity sha512-jjBIBG9IsclqQVl5Y82npGE6utdCh7Z9VFcF5qgJa5EUq2XgspW3Dt1wujWjH/vQDRnkp9zGO+BqQU/HhX/3wg== + dependencies: + "@solana/buffer-layout" "^4.0.0" + "@solana/buffer-layout-utils" "^0.2.0" + "@solana/spl-token-metadata" "^0.1.2" + buffer "^6.0.3" + +"@solana/spl-type-length-value@0.1.0": + version "0.1.0" + resolved "https://registry.npmjs.org/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz" + integrity sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA== + dependencies: + buffer "^6.0.3" + +"@solana/web3.js@^1.2.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.87.6", "@solana/web3.js@^1.88.0", "@solana/web3.js@^1.89.1": + version "1.90.0" + resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.90.0.tgz" + integrity sha512-p0cb/COXb8NNVSMkGMPwqQ6NvObZgUitN80uOedMB+jbYWOKOeJBuPnzhenkIV9RX0krGwyuY1Ltn5O8MGFsEw== dependencies: "@babel/runtime" "^7.23.4" "@noble/curves" "^1.2.0" @@ -78,158 +1170,741 @@ rpc-websockets "^7.5.1" superstruct "^0.14.2" +"@stylistic/eslint-plugin-js@^1.6.1", "@stylistic/eslint-plugin-js@1.6.1": + version "1.6.1" + resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.6.1.tgz" + integrity sha512-gHRxkbA5p8S1fnChE7Yf5NFltRZCzbCuQOcoTe93PSKBC4GqVjZmlWUSLz9pJKHvDAUTjWkfttWHIOaFYPEhRQ== + dependencies: + acorn "^8.11.3" + escape-string-regexp "^4.0.0" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + +"@stylistic/eslint-plugin-jsx@1.6.1": + version "1.6.1" + resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.6.1.tgz" + integrity sha512-uJQcg3iqrhm3EH15ZjxmZ1YmXXexkLKFEgxkWA3RYjgAVTx8k7xGJwClK/JnjKDGdbFRiDQPjxt964R1vsaFaQ== + dependencies: + "@stylistic/eslint-plugin-js" "^1.6.1" + estraverse "^5.3.0" + picomatch "^3.0.1" + +"@stylistic/eslint-plugin-plus@1.6.1": + version "1.6.1" + resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.6.1.tgz" + integrity sha512-nYIXfdYN+pBVmm0vPCKQFg/IK35tf3ZGz+0WENUL6ww1+jKM6/i36FalRFculiHzO+wOpJ3/yXWJC3PCbwGFZQ== + dependencies: + "@typescript-eslint/utils" "^6.20.0" + +"@stylistic/eslint-plugin-ts@^1.6.1", "@stylistic/eslint-plugin-ts@1.6.1": + version "1.6.1" + resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-1.6.1.tgz" + integrity sha512-eZxrFaLhPJVUQmtsRXKiuzSou0nlHevKc1WsfhxUJ9p8juv3G3YlbbGeYg4AP1fNlEmWs/lZQAP2WfzQOdBNvQ== + dependencies: + "@stylistic/eslint-plugin-js" "1.6.1" + "@typescript-eslint/utils" "^6.20.0" + +"@stylistic/eslint-plugin@^1.6.1": + version "1.6.1" + resolved "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-1.6.1.tgz" + integrity sha512-De7Sw86OtIf7SsMgjLCf4bTeI3085Plyh4l0Rg1V42BTFo/Q6Pz7Cbu31rEk/UHFiEna/YO8Hxj80jFP3ObrQw== + dependencies: + "@stylistic/eslint-plugin-js" "1.6.1" + "@stylistic/eslint-plugin-jsx" "1.6.1" + "@stylistic/eslint-plugin-plus" "1.6.1" + "@stylistic/eslint-plugin-ts" "1.6.1" + +"@suchipi/femver@^1.0.0": + version "1.0.0" + resolved "https://registry.npmjs.org/@suchipi/femver/-/femver-1.0.0.tgz" + integrity sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg== + +"@terra-money/legacy.proto@npm:@terra-money/terra.proto@^0.1.7": + version "0.1.7" + resolved "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-0.1.7.tgz" + integrity sha512-NXD7f6pQCulvo6+mv6MAPzhOkUzRjgYVuHZE/apih+lVnPG5hDBU0rRYnOGGofwvKT5/jQoOENnFn/gioWWnyQ== + dependencies: + google-protobuf "^3.17.3" + long "^4.0.0" + protobufjs "~6.11.2" + +"@terra-money/terra.js@3.1.9": + version "3.1.9" + resolved "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.1.9.tgz" + integrity sha512-JulSvOHLM56fL7s+cIjIbZeWPBluq883X1soWxA4TG5rKkDythT/DHeLXr3jP5Ld/26VENPSg6lNvK7cEYKpiw== + dependencies: + "@classic-terra/terra.proto" "^1.1.0" + "@terra-money/terra.proto" "^2.1.0" + axios "^0.27.2" + bech32 "^2.0.0" + bip32 "^2.0.6" + bip39 "^3.0.3" + bufferutil "^4.0.3" + decimal.js "^10.2.1" + jscrypto "^1.0.1" + readable-stream "^3.6.0" + secp256k1 "^4.0.2" + tmp "^0.2.1" + utf-8-validate "^5.0.5" + ws "^7.5.9" + +"@terra-money/terra.proto@^2.1.0": + version "2.1.0" + resolved "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-2.1.0.tgz" + integrity sha512-rhaMslv3Rkr+QsTQEZs64FKA4QlfO0DfQHaR6yct/EovenMkibDEQ63dEL6yJA6LCaEQGYhyVB9JO9pTUA8ybw== + dependencies: + "@improbable-eng/grpc-web" "^0.14.1" + google-protobuf "^3.17.3" + long "^4.0.0" + protobufjs "~6.11.2" + +"@types/bn.js@^4.11.3": + version "4.11.6" + resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz" + integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + dependencies: + "@types/node" "*" + "@types/bn.js@^5.1.0": version "5.1.5" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-5.1.5.tgz#2e0dacdcce2c0f16b905d20ff87aedbc6f7b4bf0" + resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz" integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== dependencies: "@types/node" "*" +"@types/bn.js@5.1.1": + version "5.1.1" + resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz" + integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== + dependencies: + "@types/node" "*" + "@types/chai@^4.3.0": version "4.3.11" - resolved "https://registry.yarnpkg.com/@types/chai/-/chai-4.3.11.tgz#e95050bf79a932cb7305dd130254ccdf9bde671c" + resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz" integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== "@types/connect@^3.4.33": version "3.4.38" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.38.tgz#5ba7f3bc4fbbdeaff8dded952e5ff2cc53f8d858" + resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== dependencies: "@types/node" "*" +"@types/json-schema@^7.0.12": + version "7.0.15" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" + integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== + "@types/json5@^0.0.29": version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" + resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== +"@types/lodash.values@^4.3.6": + version "4.3.9" + resolved "https://registry.npmjs.org/@types/lodash.values/-/lodash.values-4.3.9.tgz" + integrity sha512-IJ20OEfqNwm3k8ENwoM3q0yOs4UMpgtD4GqxB4lwBHToGthHWqhyh5DdSgQjioocz0QK2SSBkJfCq95ZTV8BTw== + dependencies: + "@types/lodash" "*" + +"@types/lodash@*": + version "4.14.202" + resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz" + integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== + +"@types/long@^4.0.1", "@types/long@^4.0.2": + version "4.0.2" + resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" + integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== + "@types/mocha@^9.0.0": version "9.1.1" - resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.1.1.tgz#e7c4f1001eefa4b8afbd1eee27a237fee3bf29c4" + resolved "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz" integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== -"@types/node@*": +"@types/node@*", "@types/node@>=13.7.0": version "20.11.5" - resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.5.tgz#be10c622ca7fcaa3cf226cf80166abc31389d86e" + resolved "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz" integrity sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w== dependencies: undici-types "~5.26.4" "@types/node@^12.12.54": version "12.20.55" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.55.tgz#c329cbd434c42164f846b909bd6f85b5537f6240" + resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz" integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== +"@types/node@^18.0.3": + version "18.19.15" + resolved "https://registry.npmjs.org/@types/node/-/node-18.19.15.tgz" + integrity sha512-AMZ2UWx+woHNfM11PyAEQmfSxi05jm9OlkxczuHeEqmvwPkYj6MWv44gbzDPefYOLysTOFyI3ziiy2ONmUZfpA== + dependencies: + undici-types "~5.26.4" + +"@types/node@10.12.18": + version "10.12.18" + resolved "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz" + integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== + +"@types/pbkdf2@^3.0.0": + version "3.1.2" + resolved "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz" + integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== + dependencies: + "@types/node" "*" + +"@types/secp256k1@^4.0.1": + version "4.0.6" + resolved "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz" + integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== + dependencies: + "@types/node" "*" + +"@types/semver@^7.5.0": + version "7.5.6" + resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz" + integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== + "@types/ws@^7.4.4": version "7.4.7" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.4.7.tgz#f7c390a36f7a0679aa69de2d501319f4f8d9b702" + resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz" integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== dependencies: "@types/node" "*" +"@typescript-eslint/eslint-plugin@^6.21.0", "@typescript-eslint/eslint-plugin@^6.4.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz" + integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== + dependencies: + "@eslint-community/regexpp" "^4.5.1" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/type-utils" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + graphemer "^1.4.0" + ignore "^5.2.4" + natural-compare "^1.4.0" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/parser@^6.0.0 || ^6.0.0-alpha", "@typescript-eslint/parser@^6.4.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz" + integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== + dependencies: + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + +"@typescript-eslint/scope-manager@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz" + integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + +"@typescript-eslint/type-utils@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz" + integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== + dependencies: + "@typescript-eslint/typescript-estree" "6.21.0" + "@typescript-eslint/utils" "6.21.0" + debug "^4.3.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/types@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz" + integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== + +"@typescript-eslint/typescript-estree@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz" + integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== + dependencies: + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/visitor-keys" "6.21.0" + debug "^4.3.4" + globby "^11.1.0" + is-glob "^4.0.3" + minimatch "9.0.3" + semver "^7.5.4" + ts-api-utils "^1.0.1" + +"@typescript-eslint/utils@^6.20.0", "@typescript-eslint/utils@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz" + integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + "@types/json-schema" "^7.0.12" + "@types/semver" "^7.5.0" + "@typescript-eslint/scope-manager" "6.21.0" + "@typescript-eslint/types" "6.21.0" + "@typescript-eslint/typescript-estree" "6.21.0" + semver "^7.5.4" + +"@typescript-eslint/visitor-keys@6.21.0": + version "6.21.0" + resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz" + integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== + dependencies: + "@typescript-eslint/types" "6.21.0" + eslint-visitor-keys "^3.4.1" + "@ungap/promise-all-settled@1.1.2": version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" + resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz" integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== +"@ungap/structured-clone@^1.2.0": + version "1.2.0" + resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz" + integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== + +"@wry/caches@^1.0.0": + version "1.0.1" + resolved "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz" + integrity sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA== dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" + tslib "^2.3.0" + +"@wry/context@^0.7.0": + version "0.7.4" + resolved "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz" + integrity sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ== + dependencies: + tslib "^2.3.0" + +"@wry/equality@^0.5.6": + version "0.5.7" + resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz" + integrity sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.4.3": + version "0.4.3" + resolved "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz" + integrity sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w== + dependencies: + tslib "^2.3.0" + +"@wry/trie@^0.5.0": + version "0.5.0" + resolved "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz" + integrity sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA== + dependencies: + tslib "^2.3.0" + +"@xpla/xpla.js@^0.2.1": + version "0.2.3" + resolved "https://registry.npmjs.org/@xpla/xpla.js/-/xpla.js-0.2.3.tgz" + integrity sha512-Tfk7hCGWXtwr08reY3Pi6dmzIqFbzri9jcyzJdfNmdo4cN0PMwpRJuZZcPmtxiIUnNef3AN1E/6nJUD5MKniuA== + dependencies: + "@ethersproject/bytes" "^5.6.1" + "@ethersproject/keccak256" "^5.6.1" + "@ethersproject/signing-key" "^5.6.2" + "@terra-money/legacy.proto" "npm:@terra-money/terra.proto@^0.1.7" + "@terra-money/terra.proto" "^2.1.0" + axios "^0.26.1" + bech32 "^2.0.0" + bip32 "^2.0.6" + bip39 "^3.0.3" + bufferutil "^4.0.3" + crypto-addr-codec "^0.1.7" + decimal.js "^10.2.1" + elliptic "^6.5.4" + ethereumjs-util "^7.1.5" + jscrypto "^1.0.1" + readable-stream "^3.6.0" + secp256k1 "^4.0.2" + tmp "^0.2.1" + utf-8-validate "^5.0.5" + ws "^7.5.8" + +acorn-jsx@^5.3.2: + version "5.3.2" + resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" + integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== + +"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@7.1.1: + version "7.1.1" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz" + integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== + +acorn@^8.11.3: + version "8.11.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +acorn@^8.9.0: + version "8.11.3" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" + integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== + +aes-js@3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" + integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== agentkeepalive@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz" integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== dependencies: humanize-ms "^1.2.1" +ajv@^6.12.4: + version "6.12.6" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" + integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== + dependencies: + fast-deep-equal "^3.1.1" + fast-json-stable-stringify "^2.0.0" + json-schema-traverse "^0.4.1" + uri-js "^4.2.2" + +algo-msgpack-with-bigint@^2.1.1: + version "2.1.1" + resolved "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz" + integrity sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ== + +algosdk@^2.4.0: + version "2.7.0" + resolved "https://registry.npmjs.org/algosdk/-/algosdk-2.7.0.tgz" + integrity sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg== + dependencies: + algo-msgpack-with-bigint "^2.1.1" + buffer "^6.0.3" + hi-base32 "^0.5.1" + js-sha256 "^0.9.0" + js-sha3 "^0.8.0" + js-sha512 "^0.8.0" + json-bigint "^1.0.0" + tweetnacl "^1.0.3" + vlq "^2.0.4" + ansi-colors@4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== ansi-regex@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.1.tgz#082cb2c89c9fe8659a311a53bd6a4dc5301db304" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== +ansi-styles@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" + integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== + dependencies: + color-convert "^1.9.0" + ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.3.0.tgz#edd803628ae71c04c85ae7a0906edad34b648937" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== dependencies: color-convert "^2.0.1" anymatch@~3.1.2: version "3.1.3" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" +aptos@1.5.0: + version "1.5.0" + resolved "https://registry.npmjs.org/aptos/-/aptos-1.5.0.tgz" + integrity sha512-N7OuRtU7IYHkDkNx+4QS3g/QQGCp+36KzYn3oXPmT7Kttfuv+UKliQVdjy3cLmwd/DCQSh9ObTovwdxnHjUn0g== + dependencies: + "@noble/hashes" "1.1.3" + "@scure/bip39" "1.1.0" + axios "0.27.2" + form-data "4.0.0" + tweetnacl "1.0.3" + argparse@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" + resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== +array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz" + integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== + dependencies: + call-bind "^1.0.5" + is-array-buffer "^3.0.4" + +array-includes@^3.1.7: + version "3.1.7" + resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz" + integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + get-intrinsic "^1.2.1" + is-string "^1.0.7" + +array-union@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" + integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== + +array.prototype.filter@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz" + integrity sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-array-method-boxes-properly "^1.0.0" + is-string "^1.0.7" + +array.prototype.findlastindex@^1.2.3: + version "1.2.4" + resolved "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz" + integrity sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.3.0" + es-shim-unscopables "^1.0.2" + +array.prototype.flat@^1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz" + integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +array.prototype.flatmap@^1.3.2: + version "1.3.2" + resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz" + integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + es-shim-unscopables "^1.0.0" + +arraybuffer.prototype.slice@^1.0.2: + version "1.0.3" + resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz" + integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== + dependencies: + array-buffer-byte-length "^1.0.1" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.2.1" + get-intrinsic "^1.2.3" + is-array-buffer "^3.0.4" + is-shared-array-buffer "^1.0.2" + arrify@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" + resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== assertion-error@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" + resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +asynckit@^0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" + integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== + +available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz" + integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== + +axios@^0.21.1: + version "0.21.4" + resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +axios@^0.21.2: + version "0.21.4" + resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" + integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== + dependencies: + follow-redirects "^1.14.0" + +axios@^0.24.0: + version "0.24.0" + resolved "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz" + integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== + dependencies: + follow-redirects "^1.14.4" + +axios@^0.26.1: + version "0.26.1" + resolved "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz" + integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== + dependencies: + follow-redirects "^1.14.8" + +axios@^0.27.2: + version "0.27.2" + resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + +axios@0.27.2: + version "0.27.2" + resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz" + integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== + dependencies: + follow-redirects "^1.14.9" + form-data "^4.0.0" + balanced-match@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== -base-x@^3.0.2: +base-x@^3.0.2, base-x@^3.0.8: version "3.0.9" - resolved "https://registry.yarnpkg.com/base-x/-/base-x-3.0.9.tgz#6349aaabb58526332de9f60995e548a53fe21320" + resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz" integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== dependencies: safe-buffer "^5.0.1" -base64-js@^1.3.1, base64-js@^1.5.1: +base-x@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz" + integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== + +base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bech32@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +bech32@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz" + integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== + +bech32@1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" + integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== + +big-integer@1.6.36: + version "1.6.36" + resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz" + integrity sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg== + bigint-buffer@^1.1.5: version "1.1.5" - resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + resolved "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz" integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== dependencies: bindings "^1.3.0" +bignumber.js@^9.0.0, bignumber.js@^9.0.1: + version "9.1.2" + resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz" + integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== + binary-extensions@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -bindings@^1.3.0: +binary-parser@^2.2.1: + version "2.2.1" + resolved "https://registry.npmjs.org/binary-parser/-/binary-parser-2.2.1.tgz" + integrity sha512-5ATpz/uPDgq5GgEDxTB4ouXCde7q2lqAQlSdBRQVl/AJnxmQmhIfyxJx+0MGu//D5rHQifkfGbWWlaysG0o9NA== + +bindings@^1.3.0, bindings@^1.5.0: version "1.5.0" - resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== dependencies: file-uri-to-path "1.0.0" -bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1: +bip32@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/bip32/-/bip32-2.0.6.tgz" + integrity sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA== + dependencies: + "@types/node" "10.12.18" + bs58check "^2.1.1" + create-hash "^1.2.0" + create-hmac "^1.1.7" + tiny-secp256k1 "^1.1.3" + typeforce "^1.11.5" + wif "^2.0.6" + +bip39@^3.0.3, bip39@^3.0.4: + version "3.1.0" + resolved "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz" + integrity sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A== + dependencies: + "@noble/hashes" "^1.2.0" + +bip66@^1.1.5: + version "1.1.5" + resolved "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz" + integrity sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw== + dependencies: + safe-buffer "^5.0.1" + +blakejs@^1.1.0: + version "1.2.1" + resolved "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz" + integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== + +bn.js@^4.11.0, bn.js@^4.11.8: + version "4.12.0" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^4.11.9: + version "4.12.0" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" + integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== + +bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1, bn.js@5.2.1: version "5.2.1" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== borsh@^0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + resolved "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz" integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== dependencies: bn.js "^5.2.0" @@ -238,64 +1913,151 @@ borsh@^0.7.0: brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" concat-map "0.0.1" -braces@~3.0.2: +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.2, braces@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" +brorand@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" + integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== + +browser-headers@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz" + integrity sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg== + browser-stdout@1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" + resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browserify-aes@^1.0.6, browserify-aes@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" + integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== + dependencies: + buffer-xor "^1.0.3" + cipher-base "^1.0.0" + create-hash "^1.1.0" + evp_bytestokey "^1.0.3" + inherits "^2.0.1" + safe-buffer "^5.0.1" + bs58@^4.0.0, bs58@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/bs58/-/bs58-4.0.1.tgz#be161e76c354f6f788ae4071f63f34e8c4f0a42a" + resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== dependencies: base-x "^3.0.2" +bs58@^5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz" + integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== + dependencies: + base-x "^4.0.0" + +bs58check@^2.1.1, bs58check@^2.1.2, bs58check@<3.0.0: + version "2.1.2" + resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz" + integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== + dependencies: + bs58 "^4.0.0" + create-hash "^1.1.0" + safe-buffer "^5.1.2" + buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== buffer-layout@^1.2.0, buffer-layout@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" + resolved "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz" integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== -buffer@6.0.3, buffer@~6.0.3: +buffer-xor@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" + integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== + +buffer@^6.0.3, buffer@~6.0.3, buffer@6.0.3: version "6.0.3" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" + resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== dependencies: base64-js "^1.3.1" ieee754 "^1.2.1" -bufferutil@^4.0.1: +bufferutil@^4.0.1, bufferutil@^4.0.3: version "4.0.8" - resolved "https://registry.yarnpkg.com/bufferutil/-/bufferutil-4.0.8.tgz#1de6a71092d65d7766c4d8a522b261a6e787e8ea" + resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz" integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== dependencies: node-gyp-build "^4.3.0" +builtin-modules@^3.3.0: + version "3.3.0" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz" + integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== + +builtins@^5.0.1: + version "5.0.1" + resolved "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz" + integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== + dependencies: + semver "^7.0.0" + +call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz" + integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.3" + set-function-length "^1.2.0" + +callsites@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" + integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== + +camelcase@^5.3.1: + version "5.3.1" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" + integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== + camelcase@^6.0.0, camelcase@^6.3.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== +capability@^0.2.5: + version "0.2.5" + resolved "https://registry.npmjs.org/capability/-/capability-0.2.5.tgz" + integrity sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg== + chai@^4.3.4: version "4.4.1" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.4.1.tgz#3603fa6eba35425b0f2ac91a009fe924106e50d1" + resolved "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz" integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== dependencies: assertion-error "^1.1.0" @@ -306,9 +2068,18 @@ chai@^4.3.4: pathval "^1.1.1" type-detect "^4.0.8" -chalk@^4.1.0: +chalk@^2.4.1: + version "2.4.2" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" + integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== + dependencies: + ansi-styles "^3.2.1" + escape-string-regexp "^1.0.5" + supports-color "^5.3.0" + +chalk@^4.0.0, chalk@^4.1.0: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -316,14 +2087,14 @@ chalk@^4.1.0: check-error@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.3.tgz#a6502e4312a7ee969f646e83bb3ddd56281bd694" + resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz" integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== dependencies: get-func-name "^2.0.2" chokidar@3.5.3: version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== dependencies: anymatch "~3.1.2" @@ -336,188 +2107,941 @@ chokidar@3.5.3: optionalDependencies: fsevents "~2.3.2" +cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" + integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + cliui@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +color-convert@^1.9.0: + version "1.9.3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" + integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== + dependencies: + color-name "1.1.3" + color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== +color-name@1.1.3: + version "1.1.3" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" + integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== + +combined-stream@^1.0.8: + version "1.0.8" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" + integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== + dependencies: + delayed-stream "~1.0.0" + commander@^2.20.3: version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== +copyfiles@^2.4.1: + version "2.4.1" + resolved "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz" + integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== + dependencies: + glob "^7.0.5" + minimatch "^3.0.3" + mkdirp "^1.0.4" + noms "0.0.0" + through2 "^2.0.1" + untildify "^4.0.0" + yargs "^16.1.0" + +core-util-is@~1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" + integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== + +cosmjs-types@^0.7.1: + version "0.7.2" + resolved "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz" + integrity sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA== + dependencies: + long "^4.0.0" + protobufjs "~6.11.2" + +crc-32@^1.2.0: + version "1.2.2" + resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" + integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== + +create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" + integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== + dependencies: + cipher-base "^1.0.1" + inherits "^2.0.1" + md5.js "^1.3.4" + ripemd160 "^2.0.1" + sha.js "^2.4.0" + +create-hmac@^1.1.4, create-hmac@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" + integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== + dependencies: + cipher-base "^1.0.3" + create-hash "^1.1.0" + inherits "^2.0.1" + ripemd160 "^2.0.0" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + cross-fetch@^3.1.5: version "3.1.8" - resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.8.tgz#0327eba65fd68a7d119f8fb2bf9334a1a7956f82" + resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz" integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== dependencies: node-fetch "^2.6.12" +cross-spawn@^7.0.2: + version "7.0.3" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" + integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + +crypto-addr-codec@^0.1.7: + version "0.1.8" + resolved "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz" + integrity sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g== + dependencies: + base-x "^3.0.8" + big-integer "1.6.36" + blakejs "^1.1.0" + bs58 "^4.0.1" + ripemd160-min "0.0.6" + safe-buffer "^5.2.0" + sha3 "^2.1.1" + crypto-hash@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247" + resolved "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz" integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== -debug@4.3.3: +debug@^3.2.7: + version "3.2.7" + resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + +debug@^4.3.1, debug@^4.3.2, debug@4.3.3: version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== dependencies: ms "2.1.2" +debug@^4.3.4: + version "4.3.4" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" + integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== + dependencies: + ms "2.1.2" + decamelize@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== +decimal.js@^10.2.1: + version "10.4.3" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz" + integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== + deep-eql@^4.1.3: version "4.1.3" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-4.1.3.tgz#7c7775513092f7df98d8df9996dd085eb668cc6d" + resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz" integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== dependencies: type-detect "^4.0.0" +deep-is@^0.1.3: + version "0.1.4" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" + integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== + +define-data-property@^1.0.1, define-data-property@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz" + integrity sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g== + dependencies: + es-errors "^1.3.0" + get-intrinsic "^1.2.2" + gopd "^1.0.1" + has-property-descriptors "^1.0.1" + +define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" + integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== + dependencies: + define-data-property "^1.0.1" + has-property-descriptors "^1.0.0" + object-keys "^1.1.1" + delay@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" + resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== +delayed-stream@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" + integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== + +depd@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" + integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== + +depd@~1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" + integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== diff@^3.1.0: version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" + resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz" integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +diff@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" + integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== + +dir-glob@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" + integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== + dependencies: + path-type "^4.0.0" + +doctrine@^2.1.0: + version "2.1.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" + integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== + dependencies: + esutils "^2.0.2" + +doctrine@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" + integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== + dependencies: + esutils "^2.0.2" + dot-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/dot-case/-/dot-case-3.0.4.tgz#9b2b670d00a431667a8a75ba29cd1b98809ce751" + resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== dependencies: no-case "^3.0.4" tslib "^2.0.3" -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +drbg.js@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz" + integrity sha512-F4wZ06PvqxYLFEZKkFxTDcns9oFNk34hvmJSEwdzsxVQ8YI5YaxtACgQatkYgv2VI2CFkUd2Y+xosPQnHv809g== + dependencies: + browserify-aes "^1.0.6" + create-hash "^1.1.2" + create-hmac "^1.1.4" + +eccrypto@1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/eccrypto/-/eccrypto-1.1.6.tgz" + integrity sha512-d78ivVEzu7Tn0ZphUUaL43+jVPKTMPFGtmgtz1D0LrFn7cY3K8CdrvibuLz2AAkHBLKZtR8DMbB2ukRYFk987A== + dependencies: + acorn "7.1.1" + elliptic "6.5.4" + es6-promise "4.2.8" + nan "2.14.0" + optionalDependencies: + secp256k1 "3.7.1" + +elliptic@^6.4.0, elliptic@^6.4.1, elliptic@^6.5.2, elliptic@^6.5.4, elliptic@6.5.4: + version "6.5.4" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" + integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== + dependencies: + bn.js "^4.11.9" + brorand "^1.1.0" + hash.js "^1.0.0" + hmac-drbg "^1.0.1" + inherits "^2.0.4" + minimalistic-assert "^1.0.1" + minimalistic-crypto-utils "^1.0.1" + +emoji-regex@^8.0.0: + version "8.0.0" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" + integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== + +error-polyfill@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/error-polyfill/-/error-polyfill-0.1.3.tgz" + integrity sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg== + dependencies: + capability "^0.2.5" + o3 "^1.0.3" + u3 "^0.1.1" + +es-abstract@^1.22.1, es-abstract@^1.22.3: + version "1.22.3" + resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz" + integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== + dependencies: + array-buffer-byte-length "^1.0.0" + arraybuffer.prototype.slice "^1.0.2" + available-typed-arrays "^1.0.5" + call-bind "^1.0.5" + es-set-tostringtag "^2.0.1" + es-to-primitive "^1.2.1" + function.prototype.name "^1.1.6" + get-intrinsic "^1.2.2" + get-symbol-description "^1.0.0" + globalthis "^1.0.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.0" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + internal-slot "^1.0.5" + is-array-buffer "^3.0.2" + is-callable "^1.2.7" + is-negative-zero "^2.0.2" + is-regex "^1.1.4" + is-shared-array-buffer "^1.0.2" + is-string "^1.0.7" + is-typed-array "^1.1.12" + is-weakref "^1.0.2" + object-inspect "^1.13.1" + object-keys "^1.1.1" + object.assign "^4.1.4" + regexp.prototype.flags "^1.5.1" + safe-array-concat "^1.0.1" + safe-regex-test "^1.0.0" + string.prototype.trim "^1.2.8" + string.prototype.trimend "^1.0.7" + string.prototype.trimstart "^1.0.7" + typed-array-buffer "^1.0.0" + typed-array-byte-length "^1.0.0" + typed-array-byte-offset "^1.0.0" + typed-array-length "^1.0.4" + unbox-primitive "^1.0.2" + which-typed-array "^1.1.13" + +es-array-method-boxes-properly@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz" + integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== + +es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-set-tostringtag@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz" + integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== + dependencies: + get-intrinsic "^1.2.2" + has-tostringtag "^1.0.0" + hasown "^2.0.0" + +es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz" + integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== + dependencies: + hasown "^2.0.0" + +es-to-primitive@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" + integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== + dependencies: + is-callable "^1.1.4" + is-date-object "^1.0.1" + is-symbol "^1.0.2" -es6-promise@^4.0.3: +es6-promise@^4.0.3, es6-promise@4.2.8: version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" + resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== es6-promisify@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" + resolved "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz" integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== dependencies: es6-promise "^4.0.3" escalade@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== -escape-string-regexp@4.0.0: +escape-string-regexp@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" + integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== + +escape-string-regexp@^4.0.0, escape-string-regexp@4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== +eslint-compat-utils@^0.1.2: + version "0.1.2" + resolved "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz" + integrity sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg== + +eslint-config-standard-with-typescript@^43.0.1: + version "43.0.1" + resolved "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-43.0.1.tgz" + integrity sha512-WfZ986+qzIzX6dcr4yGUyVb/l9N3Z8wPXCc5z/70fljs3UbWhhV+WxrfgsqMToRzuuyX9MqZ974pq2UPhDTOcA== + dependencies: + "@typescript-eslint/parser" "^6.4.0" + eslint-config-standard "17.1.0" + +eslint-config-standard@17.1.0: + version "17.1.0" + resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz" + integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== + +eslint-import-resolver-node@^0.3.9: + version "0.3.9" + resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz" + integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== + dependencies: + debug "^3.2.7" + is-core-module "^2.13.0" + resolve "^1.22.4" + +eslint-module-utils@^2.8.0: + version "2.8.0" + resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz" + integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== + dependencies: + debug "^3.2.7" + +eslint-plugin-es-x@^7.5.0: + version "7.5.0" + resolved "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz" + integrity sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ== + dependencies: + "@eslint-community/eslint-utils" "^4.1.2" + "@eslint-community/regexpp" "^4.6.0" + eslint-compat-utils "^0.1.2" + +eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.29.1: + version "2.29.1" + resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz" + integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== + dependencies: + array-includes "^3.1.7" + array.prototype.findlastindex "^1.2.3" + array.prototype.flat "^1.3.2" + array.prototype.flatmap "^1.3.2" + debug "^3.2.7" + doctrine "^2.1.0" + eslint-import-resolver-node "^0.3.9" + eslint-module-utils "^2.8.0" + hasown "^2.0.0" + is-core-module "^2.13.1" + is-glob "^4.0.3" + minimatch "^3.1.2" + object.fromentries "^2.0.7" + object.groupby "^1.0.1" + object.values "^1.1.7" + semver "^6.3.1" + tsconfig-paths "^3.15.0" + +"eslint-plugin-n@^15.0.0 || ^16.0.0 ", eslint-plugin-n@^16.6.2: + version "16.6.2" + resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz" + integrity sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ== + dependencies: + "@eslint-community/eslint-utils" "^4.4.0" + builtins "^5.0.1" + eslint-plugin-es-x "^7.5.0" + get-tsconfig "^4.7.0" + globals "^13.24.0" + ignore "^5.2.4" + is-builtin-module "^3.2.1" + is-core-module "^2.12.1" + minimatch "^3.1.2" + resolve "^1.22.2" + semver "^7.5.3" + +eslint-plugin-promise@^6.0.0, eslint-plugin-promise@^6.1.1: + version "6.1.1" + resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz" + integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== + +eslint-scope@^7.2.2: + version "7.2.2" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" + integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== + dependencies: + esrecurse "^4.3.0" + estraverse "^5.2.0" + +eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: + version "3.4.3" + resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" + integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== + +eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.0.1, eslint@^8.56.0, eslint@>=6.0.0, eslint@>=7.0.0, eslint@>=8, eslint@>=8.40.0: + version "8.56.0" + resolved "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz" + integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== + dependencies: + "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/regexpp" "^4.6.1" + "@eslint/eslintrc" "^2.1.4" + "@eslint/js" "8.56.0" + "@humanwhocodes/config-array" "^0.11.13" + "@humanwhocodes/module-importer" "^1.0.1" + "@nodelib/fs.walk" "^1.2.8" + "@ungap/structured-clone" "^1.2.0" + ajv "^6.12.4" + chalk "^4.0.0" + cross-spawn "^7.0.2" + debug "^4.3.2" + doctrine "^3.0.0" + escape-string-regexp "^4.0.0" + eslint-scope "^7.2.2" + eslint-visitor-keys "^3.4.3" + espree "^9.6.1" + esquery "^1.4.2" + esutils "^2.0.2" + fast-deep-equal "^3.1.3" + file-entry-cache "^6.0.1" + find-up "^5.0.0" + glob-parent "^6.0.2" + globals "^13.19.0" + graphemer "^1.4.0" + ignore "^5.2.0" + imurmurhash "^0.1.4" + is-glob "^4.0.0" + is-path-inside "^3.0.3" + js-yaml "^4.1.0" + json-stable-stringify-without-jsonify "^1.0.1" + levn "^0.4.1" + lodash.merge "^4.6.2" + minimatch "^3.1.2" + natural-compare "^1.4.0" + optionator "^0.9.3" + strip-ansi "^6.0.1" + text-table "^0.2.0" + +espree@^9.6.0, espree@^9.6.1: + version "9.6.1" + resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" + integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== + dependencies: + acorn "^8.9.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^3.4.1" + +esquery@^1.4.2: + version "1.5.0" + resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" + integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== + dependencies: + estraverse "^5.1.0" + +esrecurse@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" + integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== + dependencies: + estraverse "^5.2.0" + +estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" + integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== + +esutils@^2.0.2: + version "2.0.3" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" + integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== + +eth-crypto@^2.6.0: + version "2.6.0" + resolved "https://registry.npmjs.org/eth-crypto/-/eth-crypto-2.6.0.tgz" + integrity sha512-GCX4ffFYRUGgnuWR5qxcZIRQJ1KEqPFiyXU9yVy7s6dtXIMlUXZQ2h+5ID6rFaOHWbpJbjfkC6YdhwtwRYCnug== + dependencies: + "@babel/runtime" "7.20.13" + "@ethereumjs/tx" "3.5.2" + "@types/bn.js" "5.1.1" + eccrypto "1.1.6" + ethereumjs-util "7.1.5" + ethers "5.7.2" + secp256k1 "5.0.0" + +ethereum-cryptography@^0.1.3: + version "0.1.3" + resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz" + integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== + dependencies: + "@types/pbkdf2" "^3.0.0" + "@types/secp256k1" "^4.0.1" + blakejs "^1.1.0" + browserify-aes "^1.2.0" + bs58check "^2.1.2" + create-hash "^1.2.0" + create-hmac "^1.1.7" + hash.js "^1.1.7" + keccak "^3.0.0" + pbkdf2 "^3.0.17" + randombytes "^2.1.0" + safe-buffer "^5.1.2" + scrypt-js "^3.0.0" + secp256k1 "^4.0.1" + setimmediate "^1.0.5" + +ethereumjs-abi@^0.6.8: + version "0.6.8" + resolved "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz" + integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== + dependencies: + bn.js "^4.11.8" + ethereumjs-util "^6.0.0" + +ethereumjs-util@^6.0.0: + version "6.2.1" + resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz" + integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.3" + +ethereumjs-util@^6.2.1: + version "6.2.1" + resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz" + integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== + dependencies: + "@types/bn.js" "^4.11.3" + bn.js "^4.11.0" + create-hash "^1.1.2" + elliptic "^6.5.2" + ethereum-cryptography "^0.1.3" + ethjs-util "0.1.6" + rlp "^2.2.3" + +ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5, ethereumjs-util@7.1.5: + version "7.1.5" + resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz" + integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== + dependencies: + "@types/bn.js" "^5.1.0" + bn.js "^5.1.2" + create-hash "^1.1.2" + ethereum-cryptography "^0.1.3" + rlp "^2.2.4" + +ethers@^5.7.2, ethers@5.7.2: + version "5.7.2" + resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" + integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== + dependencies: + "@ethersproject/abi" "5.7.0" + "@ethersproject/abstract-provider" "5.7.0" + "@ethersproject/abstract-signer" "5.7.0" + "@ethersproject/address" "5.7.0" + "@ethersproject/base64" "5.7.0" + "@ethersproject/basex" "5.7.0" + "@ethersproject/bignumber" "5.7.0" + "@ethersproject/bytes" "5.7.0" + "@ethersproject/constants" "5.7.0" + "@ethersproject/contracts" "5.7.0" + "@ethersproject/hash" "5.7.0" + "@ethersproject/hdnode" "5.7.0" + "@ethersproject/json-wallets" "5.7.0" + "@ethersproject/keccak256" "5.7.0" + "@ethersproject/logger" "5.7.0" + "@ethersproject/networks" "5.7.1" + "@ethersproject/pbkdf2" "5.7.0" + "@ethersproject/properties" "5.7.0" + "@ethersproject/providers" "5.7.2" + "@ethersproject/random" "5.7.0" + "@ethersproject/rlp" "5.7.0" + "@ethersproject/sha2" "5.7.0" + "@ethersproject/signing-key" "5.7.0" + "@ethersproject/solidity" "5.7.0" + "@ethersproject/strings" "5.7.0" + "@ethersproject/transactions" "5.7.0" + "@ethersproject/units" "5.7.0" + "@ethersproject/wallet" "5.7.0" + "@ethersproject/web" "5.7.1" + "@ethersproject/wordlists" "5.7.0" + +ethjs-util@^0.1.6, ethjs-util@0.1.6: + version "0.1.6" + resolved "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz" + integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== + dependencies: + is-hex-prefixed "1.0.0" + strip-hex-prefix "1.0.0" + eventemitter3@^4.0.7: version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" + resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +evp_bytestokey@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" + integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== + dependencies: + md5.js "^1.3.4" + safe-buffer "^5.1.1" + eyes@^0.1.8: version "0.1.8" - resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" + resolved "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz" integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== +fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + +fast-glob@^3.2.9: + version "3.3.2" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" + integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== + dependencies: + "@nodelib/fs.stat" "^2.0.2" + "@nodelib/fs.walk" "^1.2.3" + glob-parent "^5.1.2" + merge2 "^1.3.0" + micromatch "^4.0.4" + +fast-json-stable-stringify@^2.0.0: + version "2.1.0" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" + integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== + +fast-levenshtein@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" + integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== + fast-stable-stringify@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + resolved "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz" integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== +fastestsmallesttextencoderdecoder@^1.0.22: + version "1.0.22" + resolved "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz" + integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== + +fastq@^1.6.0: + version "1.17.1" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz" + integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== + dependencies: + reusify "^1.0.4" + +file-entry-cache@^6.0.1: + version "6.0.1" + resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" + integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== + dependencies: + flat-cache "^3.0.4" + file-uri-to-path@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" -find-up@5.0.0: +find-up@^5.0.0, find-up@5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" + resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== dependencies: locate-path "^6.0.0" path-exists "^4.0.0" +flat-cache@^3.0.4: + version "3.2.0" + resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" + integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== + dependencies: + flatted "^3.2.9" + keyv "^4.5.3" + rimraf "^3.0.2" + flat@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/flat/-/flat-5.0.2.tgz#8ca6fe332069ffa9d324c327198c598259ceb241" + resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== +flatted@^3.2.9: + version "3.2.9" + resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz" + integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== + +follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.14.8, follow-redirects@^1.14.9: + version "1.15.5" + resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz" + integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== + +for-each@^0.3.3: + version "0.3.3" + resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" + integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== + dependencies: + is-callable "^1.1.3" + +form-data@^4.0.0, form-data@4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" + integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== + dependencies: + asynckit "^0.4.0" + combined-stream "^1.0.8" + mime-types "^2.1.12" + fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== fsevents@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + +function.prototype.name@^1.1.6: + version "1.1.6" + resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz" + integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + functions-have-names "^1.2.3" + +functions-have-names@^1.2.3: + version "1.2.3" + resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" + integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== + get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-func-name@^2.0.1, get-func-name@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== -glob-parent@~5.1.2: +get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: + version "1.2.4" + resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" + integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + has-proto "^1.0.1" + has-symbols "^1.0.3" + hasown "^2.0.0" + +get-symbol-description@^1.0.0: + version "1.0.2" + resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz" + integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== + dependencies: + call-bind "^1.0.5" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + +get-tsconfig@^4.7.0: + version "4.7.2" + resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz" + integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== + dependencies: + resolve-pkg-maps "^1.0.0" + +glob-parent@^5.1.2, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" -glob@7.2.0: +glob-parent@^6.0.2: + version "6.0.2" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" + integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== + dependencies: + is-glob "^4.0.3" + +glob@^7.0.0, glob@^7.0.5, glob@^7.1.3, glob@7.2.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" + resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== dependencies: fs.realpath "^1.0.0" @@ -527,205 +3051,749 @@ glob@7.2.0: once "^1.3.0" path-is-absolute "^1.0.0" +globals@^13.19.0, globals@^13.24.0: + version "13.24.0" + resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" + integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== + dependencies: + type-fest "^0.20.2" + +globalthis@^1.0.1, globalthis@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" + integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== + dependencies: + define-properties "^1.1.3" + +globby@^11.1.0: + version "11.1.0" + resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" + integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== + dependencies: + array-union "^2.1.0" + dir-glob "^3.0.1" + fast-glob "^3.2.9" + ignore "^5.2.0" + merge2 "^1.4.1" + slash "^3.0.0" + +google-protobuf@^3.14.0, google-protobuf@^3.17.3, google-protobuf@^3.21.0: + version "3.21.2" + resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz" + integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== + +gopd@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" + integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== + dependencies: + get-intrinsic "^1.1.3" + +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +graphql-tag@^2.12.6: + version "2.12.6" + resolved "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz" + integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== + dependencies: + tslib "^2.1.0" + +"graphql@^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "graphql@^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^15.0.0 || ^16.0.0", graphql@^16.3.0: + version "16.8.1" + resolved "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz" + integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== + growl@1.10.5: version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" + resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz" integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== +has-bigints@^1.0.1, has-bigints@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" + integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== + +has-flag@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" + integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== + has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz" + integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== + dependencies: + get-intrinsic "^1.2.2" + +has-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" + integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== + +has-symbols@^1.0.2, has-symbols@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" + integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== + +has-tostringtag@^1.0.0, has-tostringtag@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" + integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== + dependencies: + has-symbols "^1.0.3" + +hash-base@^3.0.0: + version "3.1.0" + resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz" + integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== + dependencies: + inherits "^2.0.4" + readable-stream "^3.6.0" + safe-buffer "^5.2.0" + +hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7, hash.js@1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" + integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== + dependencies: + inherits "^2.0.3" + minimalistic-assert "^1.0.1" + +hasown@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" + integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== + dependencies: + function-bind "^1.1.2" + he@1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" + resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== +hi-base32@^0.5.1: + version "0.5.1" + resolved "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz" + integrity sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA== + +hmac-drbg@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" + integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== + dependencies: + hash.js "^1.0.3" + minimalistic-assert "^1.0.0" + minimalistic-crypto-utils "^1.0.1" + +hoist-non-react-statics@^3.3.2: + version "3.3.2" + resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" + integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== + dependencies: + react-is "^16.7.0" + +http-errors@^1.7.2: + version "1.8.1" + resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz" + integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== + dependencies: + depd "~1.1.2" + inherits "2.0.4" + setprototypeof "1.2.0" + statuses ">= 1.5.0 < 2" + toidentifier "1.0.1" + +http-status-codes@^2.2.0: + version "2.3.0" + resolved "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz" + integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== + humanize-ms@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== dependencies: ms "^2.0.0" ieee754@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== +ignore@^5.2.0, ignore@^5.2.4: + version "5.3.1" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" + integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== + +import-fresh@^3.2.1: + version "3.3.0" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" + integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== + dependencies: + parent-module "^1.0.0" + resolve-from "^4.0.0" + +imurmurhash@^0.1.4: + version "0.1.4" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" + integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== + inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2: +inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@2, inherits@2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== +internal-slot@^1.0.5: + version "1.0.7" + resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz" + integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== + dependencies: + es-errors "^1.3.0" + hasown "^2.0.0" + side-channel "^1.0.4" + +interpret@^1.0.0: + version "1.4.0" + resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz" + integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== + +is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: + version "3.0.4" + resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz" + integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== + dependencies: + call-bind "^1.0.2" + get-intrinsic "^1.2.1" + +is-bigint@^1.0.1: + version "1.0.4" + resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" + integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== + dependencies: + has-bigints "^1.0.1" + is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" +is-boolean-object@^1.1.0: + version "1.1.2" + resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" + integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-builtin-module@^3.2.1: + version "3.2.1" + resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz" + integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== + dependencies: + builtin-modules "^3.3.0" + +is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: + version "1.2.7" + resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" + integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== + +is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.13.1: + version "2.13.1" + resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" + integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== + dependencies: + hasown "^2.0.0" + +is-date-object@^1.0.1: + version "1.0.5" + resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" + integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== + dependencies: + has-tostringtag "^1.0.0" + is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== -is-glob@^4.0.1, is-glob@~4.0.1: +is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: version "4.0.3" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== dependencies: is-extglob "^2.1.1" +is-hex-prefixed@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz" + integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== + +is-negative-zero@^2.0.2: + version "2.0.2" + resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" + integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== + +is-number-object@^1.0.4: + version "1.0.7" + resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" + integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== + dependencies: + has-tostringtag "^1.0.0" + is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-path-inside@^3.0.3: + version "3.0.3" + resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" + integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== + is-plain-obj@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" + resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== +is-regex@^1.1.4: + version "1.1.4" + resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" + integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== + dependencies: + call-bind "^1.0.2" + has-tostringtag "^1.0.0" + +is-shared-array-buffer@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" + integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== + dependencies: + call-bind "^1.0.2" + +is-string@^1.0.5, is-string@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" + integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== + dependencies: + has-tostringtag "^1.0.0" + +is-symbol@^1.0.2, is-symbol@^1.0.3: + version "1.0.4" + resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" + integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== + dependencies: + has-symbols "^1.0.2" + +is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.13, is-typed-array@^1.1.9: + version "1.1.13" + resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz" + integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== + dependencies: + which-typed-array "^1.1.14" + is-unicode-supported@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== +is-weakref@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" + integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== + dependencies: + call-bind "^1.0.2" + +isarray@^2.0.5: + version "2.0.5" + resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" + integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== + +isarray@~1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" + integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== + +isarray@0.0.1: + version "0.0.1" + resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" + integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== + isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== isomorphic-ws@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" + resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -jayson@^4.1.0: +jayson@^4.0.0, jayson@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.0.tgz#60dc946a85197317f2b1439d672a8b0a99cea2f9" + resolved "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz" integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A== dependencies: "@types/connect" "^3.4.33" "@types/node" "^12.12.54" "@types/ws" "^7.4.4" - JSONStream "^1.3.5" commander "^2.20.3" delay "^5.0.0" es6-promisify "^5.0.0" eyes "^0.1.8" isomorphic-ws "^4.0.1" json-stringify-safe "^5.0.1" + JSONStream "^1.3.5" uuid "^8.3.2" ws "^7.4.5" +js-base64@^3.6.1: + version "3.7.6" + resolved "https://registry.npmjs.org/js-base64/-/js-base64-3.7.6.tgz" + integrity sha512-NPrWuHFxFUknr1KqJRDgUQPexQF0uIJWjeT+2KjEePhitQxQEx5EJBG1lVn5/hc8aLycTpXrDOgPQ6Zq+EDiTA== + js-sha256@^0.9.0: version "0.9.0" - resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" + resolved "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz" integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== -js-yaml@4.1.0: +js-sha3@^0.8.0, js-sha3@0.8.0: + version "0.8.0" + resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" + integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== + +js-sha512@^0.8.0: + version "0.8.0" + resolved "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz" + integrity sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ== + +"js-tokens@^3.0.0 || ^4.0.0": + version "4.0.0" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" + integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== + +js-yaml@^4.1.0, js-yaml@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== dependencies: argparse "^2.0.1" +jscrypto@^1.0.1, jscrypto@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/jscrypto/-/jscrypto-1.0.3.tgz" + integrity sha512-lryZl0flhodv4SZHOqyb1bx5sKcJxj0VBo0Kzb4QMAg3L021IC9uGpl0RCZa+9KJwlRGSK2C80ITcwbe19OKLQ== + +json-bigint@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz" + integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== + dependencies: + bignumber.js "^9.0.0" + +json-buffer@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" + integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== + +json-schema-traverse@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" + integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== + +json-stable-stringify-without-jsonify@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" + integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== + json-stringify-safe@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== json5@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== dependencies: minimist "^1.2.0" jsonparse@^1.2.0: version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz" integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== +jsonschema@^1.4.0: + version "1.4.1" + resolved "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz" + integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== + +JSONStream@^1.3.5: + version "1.3.5" + resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz" + integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== + dependencies: + jsonparse "^1.2.0" + through ">=2.2.7 <3" + +keccak@^3.0.0, keccak@^3.0.2: + version "3.0.4" + resolved "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz" + integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== + dependencies: + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + readable-stream "^3.6.0" + +keccak256@^1.0.6: + version "1.0.6" + resolved "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz" + integrity sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw== + dependencies: + bn.js "^5.2.0" + buffer "^6.0.3" + keccak "^3.0.2" + +keyv@^4.5.3: + version "4.5.4" + resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" + integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== + dependencies: + json-buffer "3.0.1" + +levn@^0.4.1: + version "0.4.1" + resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" + integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== + dependencies: + prelude-ls "^1.2.1" + type-check "~0.4.0" + +libsodium-wrappers@^0.7.6: + version "0.7.13" + resolved "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz" + integrity sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw== + dependencies: + libsodium "^0.7.13" + +libsodium@^0.7.13: + version "0.7.13" + resolved "https://registry.npmjs.org/libsodium/-/libsodium-0.7.13.tgz" + integrity sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw== + +link-module-alias@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/link-module-alias/-/link-module-alias-1.2.0.tgz" + integrity sha512-ahPjXepbSVKbahTB6LxR//VHm8HPfI+QQygCH+E82spBY4HR5VPJTvlhKBc9F7muVxnS6C1rRfoPOXAbWO/fyw== + dependencies: + chalk "^2.4.1" + locate-path@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-6.0.0.tgz#55321eb309febbc59c4801d931a72452a681d286" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== dependencies: p-locate "^5.0.0" +lodash.merge@^4.6.2: + version "4.6.2" + resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" + integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== + +lodash.values@^4.3.0: + version "4.3.0" + resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz" + integrity sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q== + +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + log-symbols@4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: chalk "^4.1.0" is-unicode-supported "^0.1.0" +long@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + +long@^5.0.0: + version "5.2.3" + resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + +loose-envify@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" + integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== + dependencies: + js-tokens "^3.0.0 || ^4.0.0" + loupe@^2.3.6: version "2.3.7" - resolved "https://registry.yarnpkg.com/loupe/-/loupe-2.3.7.tgz#6e69b7d4db7d3ab436328013d37d1c8c3540c697" + resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz" integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== dependencies: get-func-name "^2.0.1" lower-case@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" + resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz" integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== dependencies: tslib "^2.0.3" +lru-cache@^6.0.0: + version "6.0.0" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" + integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== + dependencies: + yallist "^4.0.0" + make-error@^1.1.1: version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +map-obj@^4.1.0: + version "4.3.0" + resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz" + integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== + +md5.js@^1.3.4: + version "1.3.5" + resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" + integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + safe-buffer "^5.1.2" + +merge2@^1.3.0, merge2@^1.4.1: + version "1.4.1" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" + integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== + +micromatch@^4.0.4: + version "4.0.5" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" + integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== + dependencies: + braces "^3.0.2" + picomatch "^2.3.1" + +mime-db@1.52.0: + version "1.52.0" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" + integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== + +mime-types@^2.1.12: + version "2.1.35" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" + integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== + dependencies: + mime-db "1.52.0" + +minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + +minimalistic-crypto-utils@^1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" + integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== + +minimatch@^3.0.3: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.4: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.0.5: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + +minimatch@^3.1.2: + version "3.1.2" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" + integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== + dependencies: + brace-expansion "^1.1.7" + minimatch@4.2.1: version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz" integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== dependencies: brace-expansion "^1.1.7" -minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== +minimatch@9.0.3: + version "9.0.3" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" + integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== dependencies: - brace-expansion "^1.1.7" + brace-expansion "^2.0.1" -minimist@^1.2.0, minimist@^1.2.6: +minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: version "1.2.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.8.tgz#c1a464e7693302e082a075cee0c057741ac4772c" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== mkdirp@^0.5.1: version "0.5.6" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.6.tgz#7def03d2432dcae4ba1d611445c48396062255f6" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== dependencies: minimist "^1.2.6" -mocha@^9.0.3: +mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== + +"mocha@^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", mocha@^9.0.3: version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" + resolved "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz" integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== dependencies: "@ungap/promise-all-settled" "1.1.2" @@ -753,124 +3821,523 @@ mocha@^9.0.3: yargs-parser "20.2.4" yargs-unparser "2.0.0" +ms@^2.0.0, ms@^2.1.1, ms@2.1.3: + version "2.1.3" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + ms@2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3, ms@^2.0.0: - version "2.1.3" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +mustache@^4.0.0: + version "4.2.0" + resolved "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz" + integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== + +nan@^2.13.2, nan@^2.14.0, nan@2.14.0: + version "2.14.0" + resolved "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== nanoid@3.3.1: version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== +natural-compare@^1.4.0: + version "1.4.0" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" + integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== + +near-api-js@^1.0.0: + version "1.1.0" + resolved "https://registry.npmjs.org/near-api-js/-/near-api-js-1.1.0.tgz" + integrity sha512-qYKv1mYsaDZc2uYndhS+ttDhR9+60qFc+ZjD6lWsAxr3ZskMjRwPffDGQZYhC7BRDQMe1HEbk6d5mf+TVm0Lqg== + dependencies: + bn.js "5.2.1" + borsh "^0.7.0" + bs58 "^4.0.0" + depd "^2.0.0" + error-polyfill "^0.1.3" + http-errors "^1.7.2" + js-sha256 "^0.9.0" + mustache "^4.0.0" + node-fetch "^2.6.1" + text-encoding-utf-8 "^1.0.2" + tweetnacl "^1.0.1" + no-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" + resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== dependencies: lower-case "^2.0.2" tslib "^2.0.3" -node-fetch@^2.6.12, node-fetch@^2.7.0: +node-addon-api@^2.0.0: + version "2.0.2" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz" + integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== + +node-addon-api@^5.0.0: + version "5.1.0" + resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz" + integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== + +node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0: version "2.7.0" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== dependencies: whatwg-url "^5.0.0" -node-gyp-build@^4.3.0: +node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: version "4.8.0" - resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.8.0.tgz#3fee9c1731df4581a3f9ead74664369ff00d26dd" + resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz" integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== +noms@0.0.0: + version "0.0.0" + resolved "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz" + integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== + dependencies: + inherits "^2.0.1" + readable-stream "~1.0.31" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== +o3@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/o3/-/o3-1.0.3.tgz" + integrity sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ== + dependencies: + capability "^0.2.5" + +object-assign@^4.1.1: + version "4.1.1" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" + integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== + +object-inspect@^1.13.1: + version "1.13.1" + resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" + integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== + +object-keys@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" + integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== + +object.assign@^4.1.4: + version "4.1.5" + resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz" + integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== + dependencies: + call-bind "^1.0.5" + define-properties "^1.2.1" + has-symbols "^1.0.3" + object-keys "^1.1.1" + +object.fromentries@^2.0.7: + version "2.0.7" + resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz" + integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +object.groupby@^1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz" + integrity sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw== + dependencies: + array.prototype.filter "^1.0.3" + call-bind "^1.0.5" + define-properties "^1.2.1" + es-abstract "^1.22.3" + es-errors "^1.0.0" + +object.values@^1.1.7: + version "1.1.7" + resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz" + integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + once@^1.3.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" +optimism@^0.18.0: + version "0.18.0" + resolved "https://registry.npmjs.org/optimism/-/optimism-0.18.0.tgz" + integrity sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ== + dependencies: + "@wry/caches" "^1.0.0" + "@wry/context" "^0.7.0" + "@wry/trie" "^0.4.3" + tslib "^2.3.0" + +optionator@^0.9.3: + version "0.9.3" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" + integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== + dependencies: + "@aashutoshrathi/word-wrap" "^1.2.3" + deep-is "^0.1.3" + fast-levenshtein "^2.0.6" + levn "^0.4.1" + prelude-ls "^1.2.1" + type-check "^0.4.0" + p-limit@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-3.1.0.tgz#e1daccbe78d0d1388ca18c64fea38e3e57e3706b" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== dependencies: yocto-queue "^0.1.0" p-locate@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-5.0.0.tgz#83c8315c6785005e3bd021839411c9e110e6d834" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== dependencies: p-limit "^3.0.2" pako@^2.0.3: version "2.1.0" - resolved "https://registry.yarnpkg.com/pako/-/pako-2.1.0.tgz#266cc37f98c7d883545d11335c00fbd4062c9a86" + resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz" integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== +parent-module@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" + integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== + dependencies: + callsites "^3.0.0" + path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== +path-key@^3.1.0: + version "3.1.1" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" + integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== + +path-parse@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" + integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== + +path-type@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" + integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== + pathval@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" + resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== -picomatch@^2.0.4, picomatch@^2.2.1: +pbkdf2@^3.0.17: + version "3.1.2" + resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" + integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== + dependencies: + create-hash "^1.1.2" + create-hmac "^1.1.4" + ripemd160 "^2.0.1" + safe-buffer "^5.0.1" + sha.js "^2.4.8" + +picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: version "2.3.1" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz" + integrity sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag== + +prelude-ls@^1.2.1: + version "1.2.1" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" + integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== + prettier@^2.6.2: version "2.8.8" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +process-nextick-args@~2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" + integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== + +prop-types@^15.7.2: + version "15.8.1" + resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" + integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== + dependencies: + loose-envify "^1.4.0" + object-assign "^4.1.1" + react-is "^16.13.1" + +protobufjs@^6.8.8: + version "6.11.4" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" + integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + +protobufjs@^7.0.0: + version "7.2.6" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz" + integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + +protobufjs@~6.11.2: + version "6.11.4" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" + integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + +protobufjs@~6.11.3: + version "6.11.4" + resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" + integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + +punycode@^2.1.0: + version "2.3.1" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" + integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== + +queue-microtask@^1.2.2: + version "1.2.3" + resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" + integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== + randombytes@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" +react-is@^16.13.1, react-is@^16.7.0: + version "16.13.1" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" + integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== + +readable-stream@^3.6.0: + version "3.6.2" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" + integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== + dependencies: + inherits "^2.0.3" + string_decoder "^1.1.1" + util-deprecate "^1.0.1" + +readable-stream@~1.0.31: + version "1.0.34" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" + integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.1" + isarray "0.0.1" + string_decoder "~0.10.x" + +readable-stream@~2.3.6: + version "2.3.8" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" + integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== + dependencies: + core-util-is "~1.0.0" + inherits "~2.0.3" + isarray "~1.0.0" + process-nextick-args "~2.0.0" + safe-buffer "~5.1.1" + string_decoder "~1.1.1" + util-deprecate "~1.0.1" + readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" +readonly-date@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz" + integrity sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ== + +rechoir@^0.6.2: + version "0.6.2" + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" + integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== + dependencies: + resolve "^1.1.6" + +regenerator-runtime@^0.13.11: + version "0.13.11" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" + integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== + regenerator-runtime@^0.14.0: version "0.14.1" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== +regexp.prototype.flags@^1.5.1: + version "1.5.1" + resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz" + integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + set-function-name "^2.0.0" + +rehackt@0.0.4: + version "0.0.4" + resolved "https://registry.npmjs.org/rehackt/-/rehackt-0.0.4.tgz" + integrity sha512-xFroSGCbMEK/cTJVhq+c8l/AzIeMeojVyLqtZmr2jmIAFvePjapkCSGg9MnrcNk68HPaMxGf+Ndqozotu78ITw== + require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +resolve-from@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" + integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== + +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +resolve@^1.1.6, resolve@^1.22.2, resolve@^1.22.4: + version "1.22.8" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" + integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== + dependencies: + is-core-module "^2.13.0" + path-parse "^1.0.7" + supports-preserve-symlinks-flag "^1.0.0" + +response-iterator@^0.2.6: + version "0.2.6" + resolved "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz" + integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== + +reusify@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" + integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== + +rimraf@^3.0.0, rimraf@^3.0.2: + version "3.0.2" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" + integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== + dependencies: + glob "^7.1.3" + +ripemd160-min@0.0.6: + version "0.0.6" + resolved "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz" + integrity sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A== + +ripemd160@^2.0.0, ripemd160@^2.0.1: + version "2.0.2" + resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" + integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== + dependencies: + hash-base "^3.0.0" + inherits "^2.0.1" + +rlp@^2.2.3, rlp@^2.2.4: + version "2.2.7" + resolved "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz" + integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== + dependencies: + bn.js "^5.2.0" + rpc-websockets@^7.5.1: version "7.9.0" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.9.0.tgz#a3938e16d6f134a3999fdfac422a503731bf8973" + resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.9.0.tgz" integrity sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw== dependencies: "@babel/runtime" "^7.17.2" @@ -881,29 +4348,215 @@ rpc-websockets@^7.5.1: bufferutil "^4.0.1" utf-8-validate "^5.0.2" -safe-buffer@^5.0.1, safe-buffer@^5.1.0: +run-parallel@^1.1.9: + version "1.2.0" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" + integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== + dependencies: + queue-microtask "^1.2.2" + +rxjs@^7.4.0, rxjs@^7.5.6, rxjs@^7.8.0: + version "7.8.1" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz" + integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== + dependencies: + tslib "^2.1.0" + +safe-array-concat@^1.0.1: + version "1.1.0" + resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz" + integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== + dependencies: + call-bind "^1.0.5" + get-intrinsic "^1.2.2" + has-symbols "^1.0.3" + isarray "^2.0.5" + +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== +safe-buffer@~5.1.0, safe-buffer@~5.1.1: + version "5.1.2" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" + integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== + +safe-regex-test@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz" + integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-regex "^1.1.4" + +scrypt-js@^3.0.0, scrypt-js@3.0.1: + version "3.0.1" + resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" + integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== + +secp256k1@^4.0.1, secp256k1@^4.0.2, secp256k1@^4.0.3: + version "4.0.3" + resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz" + integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^2.0.0" + node-gyp-build "^4.2.0" + +secp256k1@3.7.1: + version "3.7.1" + resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz" + integrity sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g== + dependencies: + bindings "^1.5.0" + bip66 "^1.1.5" + bn.js "^4.11.8" + create-hash "^1.2.0" + drbg.js "^1.0.1" + elliptic "^6.4.1" + nan "^2.14.0" + safe-buffer "^5.1.2" + +secp256k1@5.0.0: + version "5.0.0" + resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.0.tgz" + integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA== + dependencies: + elliptic "^6.5.4" + node-addon-api "^5.0.0" + node-gyp-build "^4.2.0" + +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.0.0, semver@^7.5.3, semver@^7.5.4: + version "7.6.0" + resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz" + integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== + dependencies: + lru-cache "^6.0.0" + serialize-javascript@6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== dependencies: randombytes "^2.1.0" +set-function-length@^1.2.0: + version "1.2.1" + resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz" + integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== + dependencies: + define-data-property "^1.1.2" + es-errors "^1.3.0" + function-bind "^1.1.2" + get-intrinsic "^1.2.3" + gopd "^1.0.1" + has-property-descriptors "^1.0.1" + +set-function-name@^2.0.0: + version "2.0.1" + resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz" + integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== + dependencies: + define-data-property "^1.0.1" + functions-have-names "^1.2.3" + has-property-descriptors "^1.0.0" + +setimmediate@^1.0.5: + version "1.0.5" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" + integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== + +setprototypeof@1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" + integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== + +sha.js@^2.4.0, sha.js@^2.4.8: + version "2.4.11" + resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" + integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== + dependencies: + inherits "^2.0.1" + safe-buffer "^5.0.1" + +sha3@^2.1.1: + version "2.1.4" + resolved "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz" + integrity sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg== + dependencies: + buffer "6.0.3" + +shebang-command@^2.0.0: + version "2.0.0" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" + integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== + dependencies: + shebang-regex "^3.0.0" + +shebang-regex@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" + integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== + +shelljs@^0.8.5: + version "0.8.5" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz" + integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== + dependencies: + glob "^7.0.0" + interpret "^1.0.0" + rechoir "^0.6.2" + +shx@^0.3.2: + version "0.3.4" + resolved "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz" + integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g== + dependencies: + minimist "^1.2.3" + shelljs "^0.8.5" + +side-channel@^1.0.4: + version "1.0.5" + resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz" + integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + get-intrinsic "^1.2.4" + object-inspect "^1.13.1" + +slash@^3.0.0: + version "3.0.0" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" + integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== + snake-case@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/snake-case/-/snake-case-3.0.4.tgz#4f2bbd568e9935abdfd593f34c691dadb49c452c" + resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz" integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== dependencies: dot-case "^3.0.4" tslib "^2.0.3" +snakecase-keys@^5.1.2, snakecase-keys@^5.4.1: + version "5.5.0" + resolved "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-5.5.0.tgz" + integrity sha512-r3kRtnoPu3FxGJ3fny6PKNnU3pteb29o6qAa0ugzhSseKNWRkw1dw8nIjXMyyKaU9vQxxVIE62Mb3bKbdrgpiw== + dependencies: + map-obj "^4.1.0" + snake-case "^3.0.4" + type-fest "^3.12.0" + source-map-support@^0.5.6: version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== dependencies: buffer-from "^1.0.0" @@ -911,89 +4564,227 @@ source-map-support@^0.5.6: source-map@^0.6.0: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +"statuses@>= 1.5.0 < 2": + version "1.5.0" + resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" + integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== + +store2@^2.12.0: + version "2.14.2" + resolved "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz" + integrity sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w== + +string_decoder@^1.1.1: + version "1.3.0" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" + integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== + dependencies: + safe-buffer "~5.2.0" + +string_decoder@~0.10.x: + version "0.10.31" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" + integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== + +string_decoder@~1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" + integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== + dependencies: + safe-buffer "~5.1.0" + string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.1" +string.prototype.trim@^1.2.8: + version "1.2.8" + resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz" + integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimend@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz" + integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + +string.prototype.trimstart@^1.0.7: + version "1.0.7" + resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz" + integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== + dependencies: + call-bind "^1.0.2" + define-properties "^1.2.0" + es-abstract "^1.22.1" + strip-ansi@^6.0.0, strip-ansi@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.1.tgz#9e26c63d30f53443e9489495b2105d37b67a85d9" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== dependencies: ansi-regex "^5.0.1" strip-bom@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== -strip-json-comments@3.1.1: +strip-hex-prefix@1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz" + integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== + dependencies: + is-hex-prefixed "1.0.0" + +strip-json-comments@^3.1.1, strip-json-comments@3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== superstruct@^0.14.2: version "0.14.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" + resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz" integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== superstruct@^0.15.4: version "0.15.5" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab" + resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz" integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== +superstruct@^1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/superstruct/-/superstruct-1.0.3.tgz" + integrity sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg== + +supports-color@^5.3.0: + version "5.5.0" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" + integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: - has-flag "^4.0.0" + has-flag "^3.0.0" supports-color@^7.1.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.2.0.tgz#1b7dcdcb32b8138801b3e478ba6a51caa89648da" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== dependencies: has-flag "^4.0.0" +supports-color@8.1.1: + version "8.1.1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + +supports-preserve-symlinks-flag@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" + integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== + +symbol-observable@^2.0.3: + version "2.0.3" + resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz" + integrity sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA== + +symbol-observable@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz" + integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== + text-encoding-utf-8@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" + resolved "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz" integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== +text-table@^0.2.0: + version "0.2.0" + resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" + integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== + "through@>=2.2.7 <3": version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== +through2@^2.0.1: + version "2.0.5" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" + integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== + dependencies: + readable-stream "~2.3.6" + xtend "~4.0.1" + +tiny-secp256k1@^1.1.3: + version "1.1.6" + resolved "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz" + integrity sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA== + dependencies: + bindings "^1.3.0" + bn.js "^4.11.8" + create-hmac "^1.1.7" + elliptic "^6.4.0" + nan "^2.13.2" + +tmp@^0.2.1: + version "0.2.1" + resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz" + integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== + dependencies: + rimraf "^3.0.0" + to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" +toidentifier@1.0.1: + version "1.0.1" + resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" + integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== + toml@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/toml/-/toml-3.0.0.tgz#342160f1af1904ec9d204d03a5d61222d762c5ee" + resolved "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz" integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== tr46@~0.0.3: version "0.0.3" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" + resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== +ts-api-utils@^1.0.1: + version "1.2.1" + resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz" + integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== + +ts-invariant@^0.10.3: + version "0.10.3" + resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz" + integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== + dependencies: + tslib "^2.1.0" + ts-mocha@^10.0.0: version "10.0.0" - resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-10.0.0.tgz#41a8d099ac90dbbc64b06976c5025ffaebc53cb9" + resolved "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz" integrity sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw== dependencies: ts-node "7.0.1" @@ -1002,7 +4793,7 @@ ts-mocha@^10.0.0: ts-node@7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz" integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== dependencies: arrify "^1.0.0" @@ -1014,9 +4805,9 @@ ts-node@7.0.1: source-map-support "^0.5.6" yn "^2.0.0" -tsconfig-paths@^3.5.0: +tsconfig-paths@^3.15.0, tsconfig-paths@^3.5.0: version "3.15.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz#5299ec605e55b1abb23ec939ef15edaf483070d4" + resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz" integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== dependencies: "@types/json5" "^0.0.29" @@ -1024,66 +4815,203 @@ tsconfig-paths@^3.5.0: minimist "^1.2.6" strip-bom "^3.0.0" -tslib@^2.0.3: +tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0: version "2.6.2" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== +tweetnacl-util@^0.15.1: + version "0.15.1" + resolved "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz" + integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== + +tweetnacl@^1.0.1, tweetnacl@^1.0.3, tweetnacl@1.0.3: + version "1.0.3" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz" + integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== + +type-check@^0.4.0, type-check@~0.4.0: + version "0.4.0" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" + integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== + dependencies: + prelude-ls "^1.2.1" + type-detect@^4.0.0, type-detect@^4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== -typescript@^4.3.5: +type-fest@^0.20.2: + version "0.20.2" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" + integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== + +type-fest@^3.12.0: + version "3.13.1" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz" + integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== + +typed-array-buffer@^1.0.0: + version "1.0.1" + resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz" + integrity sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ== + dependencies: + call-bind "^1.0.6" + es-errors "^1.3.0" + is-typed-array "^1.1.13" + +typed-array-byte-length@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz" + integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-byte-offset@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz" + integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== + dependencies: + available-typed-arrays "^1.0.5" + call-bind "^1.0.2" + for-each "^0.3.3" + has-proto "^1.0.1" + is-typed-array "^1.1.10" + +typed-array-length@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" + integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== + dependencies: + call-bind "^1.0.2" + for-each "^0.3.3" + is-typed-array "^1.1.9" + +typeforce@^1.11.5: + version "1.18.0" + resolved "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz" + integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== + +typescript@*, typescript@^4.9.5, typescript@>=4.2.0: version "4.9.5" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" + resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== +u3@^0.1.1: + version "0.1.1" + resolved "https://registry.npmjs.org/u3/-/u3-0.1.1.tgz" + integrity sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w== + +unbox-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" + integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== + dependencies: + call-bind "^1.0.2" + has-bigints "^1.0.2" + has-symbols "^1.0.3" + which-boxed-primitive "^1.0.2" + undici-types@~5.26.4: version "5.26.5" - resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-5.26.5.tgz#bcd539893d00b56e964fd2657a4866b221a65617" + resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== -utf-8-validate@^5.0.2: +untildify@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz" + integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== + +uri-js@^4.2.2: + version "4.4.1" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" + integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== + dependencies: + punycode "^2.1.0" + +utf-8-validate@^5.0.2, utf-8-validate@^5.0.5, utf-8-validate@>=5.0.2: version "5.0.10" - resolved "https://registry.yarnpkg.com/utf-8-validate/-/utf-8-validate-5.0.10.tgz#d7d10ea39318171ca982718b6b96a8d2442571a2" + resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz" integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== dependencies: node-gyp-build "^4.3.0" +util-deprecate@^1.0.1, util-deprecate@~1.0.1: + version "1.0.2" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" + integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== + uuid@^8.3.2: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== +vlq@^2.0.4: + version "2.0.4" + resolved "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz" + integrity sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA== + webidl-conversions@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== whatwg-url@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== dependencies: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which@2.0.2: +which-boxed-primitive@^1.0.2: + version "1.0.2" + resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" + integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== + dependencies: + is-bigint "^1.0.1" + is-boolean-object "^1.1.0" + is-number-object "^1.0.4" + is-string "^1.0.5" + is-symbol "^1.0.3" + +which-typed-array@^1.1.13, which-typed-array@^1.1.14: + version "1.1.14" + resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz" + integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== + dependencies: + available-typed-arrays "^1.0.6" + call-bind "^1.0.5" + for-each "^0.3.3" + gopd "^1.0.1" + has-tostringtag "^1.0.1" + +which@^2.0.1, which@2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" +wif@^2.0.6: + version "2.0.6" + resolved "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz" + integrity sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ== + dependencies: + bs58check "<3.0.0" + workerpool@6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" + resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz" integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -1092,37 +5020,60 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^7.4.5: +ws@*, ws@^7, ws@^7.4.5, ws@^7.5.8, ws@^7.5.9: version "7.5.9" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.9.tgz#54fa7db29f4c7cec68b1ddd3a89de099942bb591" + resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== ws@^8.5.0: version "8.16.0" - resolved "https://registry.yarnpkg.com/ws/-/ws-8.16.0.tgz#d1cd774f36fbc07165066a60e40323eab6446fd4" + resolved "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz" integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== +ws@7.4.6: + version "7.4.6" + resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" + integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== + +xstream@^11.14.0: + version "11.14.0" + resolved "https://registry.npmjs.org/xstream/-/xstream-11.14.0.tgz" + integrity sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw== + dependencies: + globalthis "^1.0.1" + symbol-observable "^2.0.3" + +xtend@~4.0.1: + version "4.0.2" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" + integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== + y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== +yallist@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" + integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yargs-parser@^20.2.2: version "20.2.9" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== +yargs-parser@20.2.4: + version "20.2.4" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" + integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== + yargs-unparser@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" + resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== dependencies: camelcase "^6.0.0" @@ -1130,9 +5081,9 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0: +yargs@^16.1.0, yargs@16.2.0: version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" + resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== dependencies: cliui "^7.0.2" @@ -1145,10 +5096,22 @@ yargs@16.2.0: yn@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" + resolved "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz" integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== yocto-queue@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" + resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +zen-observable-ts@^1.2.5: + version "1.2.5" + resolved "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz" + integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== + dependencies: + zen-observable "0.8.15" + +zen-observable@0.8.15: + version "0.8.15" + resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz" + integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From 2b291f1ecd5b8b07b265d980b08f4513dbfff811 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 18:02:16 +0400 Subject: [PATCH 27/90] solana: ts: implement sdk --- solana/ts/sdk/index.ts | 597 ++++++++++++++++++++++++++++ solana/ts/sdk/normalized_amount.ts | 22 + solana/ts/sdk/payloads/common.ts | 65 +++ solana/ts/sdk/payloads/transfers.ts | 40 ++ solana/ts/sdk/payloads/wormhole.ts | 5 + solana/ts/sdk/utils/wormhole.ts | 19 + 6 files changed, 748 insertions(+) create mode 100644 solana/ts/sdk/index.ts create mode 100644 solana/ts/sdk/normalized_amount.ts create mode 100644 solana/ts/sdk/payloads/common.ts create mode 100644 solana/ts/sdk/payloads/transfers.ts create mode 100644 solana/ts/sdk/payloads/wormhole.ts create mode 100644 solana/ts/sdk/utils/wormhole.ts diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts new file mode 100644 index 000000000..6bebeb34e --- /dev/null +++ b/solana/ts/sdk/index.ts @@ -0,0 +1,597 @@ +import { type ChainName, toChainId, coalesceChainId, type ChainId, SignedVaa, parseVaa } from '@certusone/wormhole-sdk' +import { derivePostedVaaKey, getWormholeDerivedAccounts } from '@certusone/wormhole-sdk/lib/cjs/solana/wormhole' +import { BN, translateError, type IdlAccounts, type Program } from '@coral-xyz/anchor' +import { associatedAddress } from '@coral-xyz/anchor/dist/cjs/utils/token' +import { + type PublicKeyInitData, + PublicKey, + type Keypair, + type TransactionInstruction, + Transaction, + sendAndConfirmTransaction, + type TransactionSignature +} from '@solana/web3.js' +import { type ExampleNativeTokenTransfers } from '../../target/types/example_native_token_transfers' +import { EndpointMessage, ManagerMessage } from './payloads/common' +import { NativeTokenTransfer } from './payloads/transfers' +import { WormholeEndpointMessage } from './payloads/wormhole' + +export { NormalizedAmount } from './normalized_amount' +export { EndpointMessage, ManagerMessage } from './payloads/common' +export { NativeTokenTransfer } from './payloads/transfers' +export { WormholeEndpointMessage } from './payloads/wormhole' + +export * from './utils/wormhole' + +export type Config = IdlAccounts['config'] +export type InboxItem = IdlAccounts['inboxItem'] + +export class NTT { + readonly program: Program + readonly wormholeId: PublicKey + // mapping from error code to error message. Used for prettifying error messages + private readonly errors: Map + + constructor(args: { program: Program, wormholeId: PublicKeyInitData }) { + // TODO: initialise a new Program here with a passed in Connection + this.program = args.program + this.wormholeId = new PublicKey(args.wormholeId) + this.errors = this.processErrors() + } + + // The `translateError` function expects this format, but the idl gives us a + // different one, so we preprocess the idl and store the expected format. + // NOTE: I'm sure there's a function within anchor that does this, but I + // couldn't find it. + private processErrors(): Map { + const errors = this.program.idl.errors + const result: Map = new Map() + errors.forEach(entry => result.set(entry.code, entry.msg)) + return result + } + + // Account addresses + + private derive_pda(seeds: Buffer | Array, program = this.program.programId): PublicKey { + const seedsArray = seeds instanceof Buffer ? [seeds] : seeds + const [address] = PublicKey.findProgramAddressSync(seedsArray, program) + return address + } + + configAccountAddress(): PublicKey { + return this.derive_pda(Buffer.from('config')) + } + + sequenceTrackerAccountAddress(): PublicKey { + return this.derive_pda(Buffer.from('sequence')) + } + + outboxRateLimitAccountAddress(): PublicKey { + return this.derive_pda(Buffer.from('outbox_rate_limit')) + } + + outboxItemAccountAddress(sequence: BN): PublicKey { + return this.derive_pda([Buffer.from('outbox_item'), sequence.toBuffer('be', 8)]) + } + + inboxRateLimitAccountAddress(chain: ChainName | ChainId): PublicKey { + const chainId = coalesceChainId(chain) + return this.derive_pda([Buffer.from('inbox_rate_limit'), new BN(chainId).toBuffer('be', 2)]) + } + + inboxItemAccountAddress(chain: ChainName | ChainId, sequence: BN): PublicKey { + const chainId = coalesceChainId(chain) + return this.derive_pda( + [ + Buffer.from('inbox_item'), + new BN(chainId).toBuffer('be', 2), + sequence.toBuffer('be', 8) + ]) + } + + custodyAuthorityAddress(): PublicKey { + return this.derive_pda([Buffer.from('custody_authority')]) + } + + emitterAccountAddress(): PublicKey { + return this.derive_pda([Buffer.from('emitter')]) + } + + wormholeMessageAccountAddress(sequence: BN): PublicKey { + return this.derive_pda([Buffer.from('message'), sequence.toBuffer('be', 8)]) + } + + mintAuthorityAddress(): PublicKey { + return this.derive_pda([Buffer.from('token_minter')]) + } + + siblingAccountAddress(chain: ChainName | ChainId): PublicKey { + const chainId = coalesceChainId(chain) + return this.derive_pda([Buffer.from('sibling'), new BN(chainId).toBuffer('be', 2)]) + } + + // Instructions + + async initialize(args: { + payer: Keypair + owner: Keypair + chain: ChainName + mint: PublicKey + outboundLimit: BN + mode: 'burning' | 'locking' + }): Promise { + const mode = + args.mode === 'burning' + ? { burning: {} } + : { locking: {} } + const chainId = toChainId(args.chain) + const mintInfo = await this.program.provider.connection.getAccountInfo(args.mint) + if (mintInfo === null) { + throw new Error("Couldn't determine token program. Mint account is null.") + } + const tokenProgram = mintInfo.owner + await this.program.methods + .initialize({ chainId, limit: args.outboundLimit, mode }) + .accounts({ + payer: args.payer.publicKey, + owner: args.owner.publicKey, + config: this.configAccountAddress(), + mint: args.mint, + seq: this.sequenceTrackerAccountAddress(), + rateLimit: this.outboxRateLimitAccountAddress(), + tokenProgram, + custodyAuthority: this.custodyAuthorityAddress(), + mintAuthority: this.mintAuthorityAddress(), + custody: await this.custodyAccountAddress(args.mint) + }) + .signers([args.payer, args.owner]) + .rpc() + } + + async transfer(args: { + payer: Keypair + from: PublicKey + fromAuthority: Keypair + amount: BN + recipientChain: ChainName + recipientAddress: ArrayLike + // TODO: implement shouldQueue logic + // actually, this should be on the inbound direction + shouldQueue: boolean + config?: Config + }): Promise { + const config: Config = await this.getConfig(args.config) + + const sequence = await this.nextSequence() + + const txArgs = { + ...args, + payer: args.payer.publicKey, + fromAuthority: args.fromAuthority.publicKey, + sequence, + config + } + + let transferIx: TransactionInstruction + if (config.mode.locking != null) { + transferIx = await this.createTransferLockInstruction(txArgs) + } else if (config.mode.burning != null) { + transferIx = await this.createTransferBurnInstruction(txArgs) + } else { + transferIx = exhaustive(config.mode) + } + + const releaseIx: TransactionInstruction = await this.createReleaseOutboundInstruction({ + payer: args.payer.publicKey, + sequence + }) + + const signers = [args.payer, args.fromAuthority] + + const tx = new Transaction() + tx.add(transferIx) + tx.add(releaseIx) + await this.sendAndConfirmTransaction(tx, signers) + + return sequence + } + + /** + * Like `sendAndConfirmTransaction` but parses the anchor error code. + */ + private async sendAndConfirmTransaction(tx: Transaction, signers: Keypair[]): Promise { + try { + return await sendAndConfirmTransaction(this.program.provider.connection, tx, signers) + } catch (err) { + throw translateError(err, this.errors) + } + } + + /** + * Creates a transfer_burn instruction. The `payer` and `fromAuthority` + * arguments must sign the transaction + */ + async createTransferBurnInstruction(args: { + payer: PublicKey + from: PublicKey + fromAuthority: PublicKey + amount: BN + recipientChain: ChainName + recipientAddress: ArrayLike + sequence?: BN + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + if (await this.isPaused(config)) { + throw new Error('Contract is paused') + } + + const chainId = toChainId(args.recipientChain) + const mint = await this.mintAccountAddress(config) + // TODO: how to gracefully handle the race condition when multiple people + // attempt to grab the same sequence number? + const sequence = args.sequence ?? await this.nextSequence() + + return await this.program.methods + .transferBurn({ + amount: args.amount, + recipientChain: { id: chainId }, + recipientAddress: Array.from(args.recipientAddress) + }) + .accounts({ + common: { + payer: args.payer, + config: { config: this.configAccountAddress() }, + mint, + from: args.from, + fromAuthority: args.fromAuthority, + seq: this.sequenceTrackerAccountAddress(), + outboxItem: this.outboxItemAccountAddress(sequence), + rateLimit: this.outboxRateLimitAccountAddress() + } + }) + .instruction() + } + + /** + * Creates a transfer_lock instruction. The `payer` and `fromAuthority` + * arguments must sign the transaction + */ + async createTransferLockInstruction(args: { + payer: PublicKey + from: PublicKey + fromAuthority: PublicKey + amount: BN + recipientChain: ChainName + recipientAddress: ArrayLike + sequence?: BN + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + if (await this.isPaused(config)) { + throw new Error('Contract is paused') + } + + const chainId = toChainId(args.recipientChain) + const mint = await this.mintAccountAddress(config) + // TODO: how to gracefully handle the race condition when multiple people + // attempt to grab the same sequence number? + const sequence = args.sequence ?? await this.nextSequence() + + return await this.program.methods + .transferLock({ + amount: args.amount, + recipientChain: { id: chainId }, + recipientAddress: Array.from(args.recipientAddress) + }) + .accounts({ + common: { + payer: args.payer, + config: { config: this.configAccountAddress() }, + mint, + from: args.from, + fromAuthority: args.fromAuthority, + tokenProgram: await this.tokenProgram(config), + seq: this.sequenceTrackerAccountAddress(), + outboxItem: this.outboxItemAccountAddress(sequence), + rateLimit: this.outboxRateLimitAccountAddress() + }, + custodyAuthority: this.custodyAuthorityAddress(), + custody: await this.custodyAccountAddress(config) + }) + .instruction() + } + + /** + * Creates a release_outbound instruction. The `payer` needs to sign the transaction. + */ + async createReleaseOutboundInstruction(args: { + payer: PublicKey + sequence: BN + }): Promise { + const whAccs = getWormholeDerivedAccounts(this.program.programId, this.wormholeId) + + return await this.program.methods + .releaseOutbound({}) + .accounts({ + payer: args.payer, + config: { config: this.configAccountAddress() }, + outboxItem: this.outboxItemAccountAddress(args.sequence), + wormholeMessage: this.wormholeMessageAccountAddress(args.sequence), + emitter: whAccs.wormholeEmitter, + wormholeBridge: whAccs.wormholeBridge, + wormholeFeeCollector: whAccs.wormholeFeeCollector, + wormholeSequence: whAccs.wormholeSequence, + wormholeProgram: this.wormholeId + }) + .instruction() + } + + async releaseOutbound(args: { + payer: Keypair + sequence: BN + config?: Config + }): Promise { + if (await this.isPaused()) { + throw new Error('Contract is paused') + } + + const txArgs = { + ...args, + payer: args.payer.publicKey + } + + const tx = new Transaction() + tx.add(await this.createReleaseOutboundInstruction(txArgs)) + + const signers = [args.payer] + await sendAndConfirmTransaction(this.program.provider.connection, tx, signers) + } + + // TODO: document that if recipient is provided, then the instruction can be + // created before the inbox item is created (i.e. they can be put in the same tx) + async createReleaseInboundMintInstruction(args: { + payer: PublicKey + chain: ChainName | ChainId + sequence: BN + recipient?: PublicKey + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + if (await this.isPaused(config)) { + throw new Error('Contract is paused') + } + + const recipientAddress = + args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress + + return await this.program.methods + .releaseInboundMint() + .accounts({ + common: { + payer: args.payer, + config: { config: this.configAccountAddress() }, + inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), + recipient: recipientAddress, + mint: await this.mintAccountAddress(config) + }, + mintAuthority: this.mintAuthorityAddress() + }) + .instruction() + } + + async releaseInboundMint(args: { + payer: Keypair + chain: ChainName | ChainId + sequence: BN + config?: Config + }): Promise { + if (await this.isPaused()) { + throw new Error('Contract is paused') + } + + const txArgs = { + ...args, + payer: args.payer.publicKey + } + + const tx = new Transaction() + tx.add(await this.createReleaseInboundMintInstruction(txArgs)) + + const signers = [args.payer] + await this.sendAndConfirmTransaction(tx, signers) + } + + async createReleaseInboundUnlockInstruction(args: { + payer: PublicKey + chain: ChainName | ChainId + sequence: BN + recipient?: PublicKey + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + if (await this.isPaused(config)) { + throw new Error('Contract is paused') + } + + const recipientAddress = + args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress + + return await this.program.methods + .releaseInboundUnlock() + .accounts({ + common: { + payer: args.payer, + config: { config: this.configAccountAddress() }, + inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), + recipient: recipientAddress, + mint: await this.mintAccountAddress(config) + }, + custodyAuthority: this.custodyAuthorityAddress(), + custody: await this.custodyAccountAddress(config) + }) + .instruction() + } + + async setSibling(args: { + payer: Keypair + owner: Keypair + chain: ChainName + address: ArrayLike + limit: BN + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + await this.program.methods.setSibling({ + chainId: { id: toChainId(args.chain) }, + address: Array.from(args.address), + limit: args.limit + }) + .accounts({ + payer: args.payer.publicKey, + owner: args.owner.publicKey, + config: this.configAccountAddress(), + sibling: this.siblingAccountAddress(args.chain), + rateLimit: this.inboxRateLimitAccountAddress(args.chain), + mint: config.mint, + }) + .signers([args.payer, args.owner]) + .rpc() + + } + + async createRedeemInstruction(args: { + payer: PublicKey + vaa: SignedVaa + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + if (await this.isPaused(config)) { + throw new Error('Contract is paused') + } + + const parsedVaa = parseVaa(args.vaa) + const managerMessage = + WormholeEndpointMessage.deserialize( + parsedVaa.payload, a => ManagerMessage.deserialize(a, a => a) + ).managerPayload + // NOTE: we do an 'as ChainId' cast here, which is generally unsafe. + // TODO: explain why this is fine here + const chainId = managerMessage.chainId as ChainId + + const sibling = this.siblingAccountAddress(chainId) + const rateLimit = this.inboxRateLimitAccountAddress(chainId) + + return await this.program.methods + .redeem({}) + .accounts({ + payer: args.payer, + config: { config: this.configAccountAddress() }, + sibling, + vaa: derivePostedVaaKey(this.wormholeId, parseVaa(args.vaa).hash), + inboxItem: this.inboxItemAccountAddress(chainId, new BN(managerMessage.sequence.toString())), + rateLimit, + }) + .instruction() + } + + // TODO: add option to return if the redeem was queued + async redeem(args: { + payer: Keypair + vaa: SignedVaa + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + const redeemArgs = { + ...args, + payer: args.payer.publicKey + } + + const parsedVaa = parseVaa(args.vaa) + + const managerMessage = + WormholeEndpointMessage.deserialize( + parsedVaa.payload, a => ManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) + ).managerPayload + // TODO: explain why this is fine here + const chainId = managerMessage.chainId as ChainId + + const tx = new Transaction() + tx.add(await this.createRedeemInstruction(redeemArgs)) + + const releaseArgs = { + ...args, + payer: args.payer.publicKey, + sequence: new BN(managerMessage.sequence.toString()), + recipient: new PublicKey(managerMessage.payload.recipientAddress), + chain: chainId + } + + if (config.mode.locking != null) { + tx.add(await this.createReleaseInboundUnlockInstruction(releaseArgs)) + } else { + tx.add(await this.createReleaseInboundMintInstruction(releaseArgs)) + } + + const signers = [args.payer] + await this.sendAndConfirmTransaction(tx, signers) + } + + // Account access + + /** + * Fetches the Config account from the contract. + * + * @param config If provided, the config is just returned without making a + * network request. This is handy in case multiple config + * accessor functions are used, the config can just be queried + * once and passed around. + */ + async getConfig(config?: Config): Promise { + return config ?? await this.program.account.config.fetch(this.configAccountAddress()) + } + + async isPaused(config?: Config): Promise { + return (await this.getConfig(config)).paused + } + + async mintAccountAddress(config?: Config): Promise { + return (await this.getConfig(config)).mint + } + + async tokenProgram(config?: Config): Promise { + return (await this.getConfig(config)).tokenProgram + } + + async nextSequence(): Promise { + return (await this.program.account.sequence.fetch(this.sequenceTrackerAccountAddress())).sequence + } + + async getInboxItem(chain: ChainName | ChainId, sequence: BN): Promise { + return await this.program.account.inboxItem.fetch(this.inboxItemAccountAddress(chain, sequence)) + } + + /** + * Returns the address of the custody account. If the config is available + * (i.e. the program is initialised), the mint is derived from the config. + * Otherwise, the mint must be provided. + */ + async custodyAccountAddress(configOrMint: Config | PublicKey): Promise { + if (configOrMint instanceof PublicKey) { + return associatedAddress({ mint: configOrMint, owner: this.custodyAuthorityAddress() }) + } else { + return associatedAddress({ mint: await this.mintAccountAddress(configOrMint), owner: this.custodyAuthorityAddress() }) + } + } +} + +function exhaustive(_: never): A { + throw new Error('Impossible') +} diff --git a/solana/ts/sdk/normalized_amount.ts b/solana/ts/sdk/normalized_amount.ts new file mode 100644 index 000000000..71f88382a --- /dev/null +++ b/solana/ts/sdk/normalized_amount.ts @@ -0,0 +1,22 @@ +export class NormalizedAmount { + amount: bigint + decimals: number + + constructor(amount: bigint, decimals: number) { + this.amount = amount + this.decimals = decimals + } + + static deserialize(data: Buffer): NormalizedAmount { + const decimals = data.readUInt8(0) + const amount = data.readBigUInt64BE(1) + return new NormalizedAmount(amount, decimals) + } + + static serialize(amount: NormalizedAmount): Buffer { + const buffer = Buffer.alloc(9) + buffer.writeUInt8(amount.decimals, 0) + buffer.writeBigUInt64BE(amount.amount, 1) + return buffer + } +} diff --git a/solana/ts/sdk/payloads/common.ts b/solana/ts/sdk/payloads/common.ts new file mode 100644 index 000000000..4bcdfdb4c --- /dev/null +++ b/solana/ts/sdk/payloads/common.ts @@ -0,0 +1,65 @@ +import { BN } from '@coral-xyz/anchor' + +export class EndpointMessage { + static prefix: Buffer + managerPayload: ManagerMessage + + constructor(managerPayload: ManagerMessage) { + this.managerPayload = managerPayload + } + + static deserialize(data: Buffer, deserializer: (data: Buffer) => ManagerMessage): EndpointMessage { + if (this.prefix == undefined) { + throw new Error('Unknown prefix.') + } + const prefix = data.subarray(0, 4) + if (!prefix.equals(this.prefix)) { + throw new Error('Invalid prefix') + } + const managerPayloadLen = data.readUInt16BE(4) + const managerPayload = deserializer(data.subarray(6, 6 + managerPayloadLen)) + return new EndpointMessage(managerPayload) + } + + static serialize(msg: EndpointMessage, serializer: (payload: ManagerMessage) => Buffer): Buffer { + const payload = serializer(msg.managerPayload) + const buffer = Buffer.concat([this.prefix, new BN(payload.length).toBuffer('be', 2), payload]) + return buffer + } +} + +export class ManagerMessage { + chainId: number + sequence: bigint + sourceManager: Buffer + sender: Buffer + payload: A + + constructor(chainId: number, sequence: bigint, sourceManager: Buffer, sender: Buffer, payload: A) { + this.chainId = chainId + this.sequence = sequence + this.sourceManager = sourceManager + this.sender = sender + this.payload = payload + } + + static deserialize = (data: Buffer, deserializer: (data: Buffer) => A): ManagerMessage => { + const chainId = data.readUInt16BE(0) + const sequence = data.readBigUInt64BE(2) + const sourceManager = data.subarray(10, 42) + const sender = data.subarray(42, 74) + const payloadLen = data.readUint16BE(74) + const payload = deserializer(data.subarray(76, 76 + payloadLen)) + return new ManagerMessage(chainId, sequence, sourceManager, sender, payload) + } + + static serialize = (msg: ManagerMessage, serializer: (payload: A) => Buffer): Buffer => { + const buffer = Buffer.alloc(74) + buffer.writeUInt16BE(msg.chainId, 0) + buffer.writeBigUInt64BE(msg.sequence, 2) + buffer.set(msg.sourceManager, 10) + buffer.set(msg.sender, 42) + const payload = serializer(msg.payload) + return Buffer.concat([buffer, new BN(payload.length).toBuffer('be', 2), payload]) + } +} diff --git a/solana/ts/sdk/payloads/transfers.ts b/solana/ts/sdk/payloads/transfers.ts new file mode 100644 index 000000000..1e77e4ce2 --- /dev/null +++ b/solana/ts/sdk/payloads/transfers.ts @@ -0,0 +1,40 @@ +import { NormalizedAmount } from '../normalized_amount' + +export class NativeTokenTransfer { + static prefix = Buffer.from([0x99, 0x4E, 0x54, 0x54]) + normalizedAmount: NormalizedAmount + sourceToken: Buffer + recipientAddress: Buffer + recipientChain: number + + constructor(sourceToken: Buffer, amount: NormalizedAmount, recipientChain: number, recipientAddress: Buffer) { + this.normalizedAmount = amount + this.sourceToken = sourceToken + this.recipientAddress = recipientAddress + this.recipientChain = recipientChain + } + + static deserialize = (data: Buffer): NativeTokenTransfer => { + const prefix = data.subarray(0, 4) + if (!prefix.equals(NativeTokenTransfer.prefix)) { + throw new Error('Invalid prefix') + } + const amount = NormalizedAmount.deserialize(data.subarray(4, 13)) + const sourceToken = data.subarray(13, 45) + const recipientAddress = data.subarray(45, 77) + const recipientChain = data.readUInt16BE(77) + return new NativeTokenTransfer(sourceToken, amount, recipientChain, recipientAddress) + } + + static serialize = (msg: NativeTokenTransfer): Buffer => { + const buffer = Buffer.concat([ + NativeTokenTransfer.prefix, + NormalizedAmount.serialize(msg.normalizedAmount), + msg.sourceToken, + msg.recipientAddress + ]) + const recipientChain = Buffer.alloc(2) + recipientChain.writeUInt16BE(msg.recipientChain, 0) + return Buffer.concat([buffer, recipientChain]) + } +} diff --git a/solana/ts/sdk/payloads/wormhole.ts b/solana/ts/sdk/payloads/wormhole.ts new file mode 100644 index 000000000..d672f76d2 --- /dev/null +++ b/solana/ts/sdk/payloads/wormhole.ts @@ -0,0 +1,5 @@ +import { EndpointMessage } from './common' + +export class WormholeEndpointMessage extends EndpointMessage { + static prefix = Buffer.from([0x99, 0x45, 0xFF, 0x10]) +} diff --git a/solana/ts/sdk/utils/wormhole.ts b/solana/ts/sdk/utils/wormhole.ts new file mode 100644 index 000000000..b7c6aabc7 --- /dev/null +++ b/solana/ts/sdk/utils/wormhole.ts @@ -0,0 +1,19 @@ + +import { postVaaSolana } from "@certusone/wormhole-sdk"; +import { NodeWallet } from "@certusone/wormhole-sdk/lib/cjs/solana"; +import * as anchor from "@coral-xyz/anchor"; + +export async function postVaa( + connection: anchor.web3.Connection, + payer: anchor.web3.Keypair, + vaaBuf: Buffer, + coreBridgeAddress: anchor.web3.PublicKey, +) { + await postVaaSolana( + connection, + new NodeWallet(payer).signTransaction, + coreBridgeAddress, + payer.publicKey, + vaaBuf, + ); +} From e12d73de0d1c6b7d9355e03f9afc77e7c7f11688 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 18:03:27 +0400 Subject: [PATCH 28/90] solana: tests: add test for lock&unlock using ts sdk --- solana/tests/example-native-token-transfer.ts | 160 ++++++++++++++++++ 1 file changed, 160 insertions(+) create mode 100644 solana/tests/example-native-token-transfer.ts diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts new file mode 100644 index 000000000..b00fd3db5 --- /dev/null +++ b/solana/tests/example-native-token-transfer.ts @@ -0,0 +1,160 @@ +import * as anchor from '@coral-xyz/anchor' +import { BN, type Program } from '@coral-xyz/anchor' +import * as spl from '@solana/spl-token' +import { type ExampleNativeTokenTransfers } from '../target/types/example_native_token_transfers' +import { PostedMessageData } from '@certusone/wormhole-sdk/lib/cjs/solana/wormhole' +import { expect } from 'chai' +import { toChainId } from '@certusone/wormhole-sdk' +import { MockEmitter, MockGuardians } from '@certusone/wormhole-sdk/lib/cjs/mock' + +import { type EndpointMessage, ManagerMessage, NativeTokenTransfer, NormalizedAmount, postVaa, WormholeEndpointMessage, NTT } from '../ts/sdk' + +export const GUARDIAN_KEY = 'cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0' + +describe('example-native-token-transfers', () => { + // Configure the client to use the local cluster. + anchor.setProvider(anchor.AnchorProvider.env()) + + const program = anchor.workspace.ExampleNativeTokenTransfers as Program + + it('Supports lock&unlock', async () => { + // TODO: factor out this test so it can be reused for burn&mint + const payer = anchor.web3.Keypair.generate() + const owner = anchor.web3.Keypair.generate() + // airdrop some tokens to payer + const signature = await program.provider.connection.requestAirdrop(payer.publicKey, 1000000000) + await program.provider.connection.confirmTransaction(signature) + // check owner lamports balance + + const mint = await spl.createMint( + program.provider.connection, + payer, + owner.publicKey, + null, + 9 + ) + + const user = anchor.web3.Keypair.generate() + const tokenAccount = await spl.createAssociatedTokenAccount(program.provider.connection, payer, mint, user.publicKey) + await spl.mintTo(program.provider.connection, payer, mint, tokenAccount, owner, BigInt(10000000)) + + const ntt = new NTT({ + program, + wormholeId: 'worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth' + }) + + await spl.setAuthority( + program.provider.connection, + payer, + mint, + owner, + 0, // mint + ntt.mintAuthorityAddress() + ) + + await ntt.initialize({ + payer, + owner, + chain: 'solana', + mint, + outboundLimit: new BN(1000000), + mode: 'locking' + }) + + // transfer some tokens + + const amount = new BN(100000) + + const sequence = await ntt.transfer({ + payer, + from: tokenAccount, + fromAuthority: user, + amount, + recipientChain: 'ethereum', + recipientAddress: Array.from(user.publicKey.toBuffer()), // TODO: dummy + shouldQueue: false + }) + + const wormholeMessage = ntt.wormholeMessageAccountAddress(sequence) + + const wormholeMessageAccount = await program.provider.connection.getAccountInfo(wormholeMessage) + if (wormholeMessageAccount === null) { + throw new Error('wormhole message account not found') + } + + const messageData = PostedMessageData.deserialize(wormholeMessageAccount.data) + const endpointMessage = WormholeEndpointMessage.deserialize( + messageData.message.payload, + a => ManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) + ) + + // assert theat amount is what we expect + expect(endpointMessage.managerPayload.payload.normalizedAmount).to.deep.equal(new NormalizedAmount(BigInt(10000), 8)) + // get from balance + const balance = await program.provider.connection.getTokenAccountBalance(tokenAccount) + expect(balance.value.amount).to.equal('9900000') + + const emitter = + new MockEmitter( + '00000000000000000000000000000000000000000000000000000000BEEFFACE', + toChainId('ethereum'), + Number(0) // sequence + ) + + const guardians = new MockGuardians(0, [GUARDIAN_KEY]) + + const sendingEndpointMessage: EndpointMessage = { + managerPayload: new ManagerMessage( + toChainId('ethereum'), + BigInt(0), + Buffer.from('BEEF'.padStart(64, '0'), 'hex'), + Buffer.from('FACE'.padStart(64, '0'), 'hex'), + new NativeTokenTransfer( + Buffer.from('FAFA'.padStart(64, '0'), 'hex'), + new NormalizedAmount(BigInt(10000), 8), + toChainId('solana'), + tokenAccount.toBuffer() + ) + ) + } + + const serialized = WormholeEndpointMessage.serialize(sendingEndpointMessage, a => ManagerMessage.serialize(a, NativeTokenTransfer.serialize)) + + const published = emitter.publishMessage( + 0, // nonce + serialized, + 0 // consistency level + ) + + const vaaBuf = guardians.addSignatures(published, [0]) + + await postVaa(program.provider.connection, payer, vaaBuf, ntt.wormholeId) + + await ntt.setSibling({ + payer, + owner, + chain: 'ethereum', + address: Buffer.from('BEEFFACE'.padStart(64, '0'), 'hex'), + limit: new BN(1000000) + }) + + await ntt.redeem({ + payer, + vaa: vaaBuf, + }) + + // grab logs + // await program.provider.connection.confirmTransaction(redeemTx, 'confirmed'); + // const tx = await anchor.getProvider().connection.getParsedTransaction(redeemTx, { + // commitment: "confirmed", + // }); + // console.log(tx); + + // const log = tx.meta.logMessages[1]; + // const message = log.substring(log.indexOf(':') + 1); + // console.log(message); + + // TODO: assert other stuff in the message + // console.log(managerMessage); + }) +}) From 629d5ff4a91a06d583a68ae455193ee817074edb Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 19:56:11 +0400 Subject: [PATCH 29/90] solana: gracefully handle redeems being delayed --- .../src/instructions/release_inbound.rs | 45 +++++++++++-- .../example-native-token-transfers/src/lib.rs | 8 +-- .../src/queue/inbox.rs | 8 ++- solana/tests/example-native-token-transfer.ts | 4 +- solana/ts/sdk/index.ts | 65 +++++++++++++++++-- 5 files changed, 113 insertions(+), 17 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 1b7da8a88..735c30935 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -35,6 +35,11 @@ pub struct ReleaseInbound<'info> { pub token_program: Interface<'info, token_interface::TokenInterface>, } +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct ReleaseInboundArgs { + pub revert_on_delay: bool, +} + // Burn/mint #[derive(Accounts)] @@ -49,11 +54,27 @@ pub struct ReleaseInboundMint<'info> { pub mint_authority: AccountInfo<'info>, } -pub fn release_inbound_mint(ctx: Context) -> Result<()> { +/// Release an inbound transfer and mint the tokens to the recipient. +/// When `revert_on_error` is true, the transaction will revert if the +/// release timestamp has not been reached. When `revert_on_error` is false, the +/// transaction succeeds, but the minting is not performed. +/// Setting this flag to `false` is useful when bundling this instruction +/// together with [`crate::instructions::redeem`] in a transaction, so that the minting +/// is attempted optimistically. +pub fn release_inbound_mint(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { let inbox_item = &mut ctx.accounts.common.inbox_item; - inbox_item.release()?; + let released = inbox_item.try_release()?; + + if !released { + if args.revert_on_delay { + return Err(NTTError::ReleaseTimestampNotReached.into()); + } else { + return Ok(()); + } + } + assert!(inbox_item.released); match ctx.accounts.common.config.mode { Mode::Burning => token_interface::mint_to( CpiContext::new_with_signer( @@ -90,11 +111,27 @@ pub struct ReleaseInboundUnlock<'info> { pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, } -pub fn release_inbound_unlock(ctx: Context) -> Result<()> { +/// Release an inbound transfer and unlock the tokens to the recipient. +/// When `revert_on_error` is true, the transaction will revert if the +/// release timestamp has not been reached. When `revert_on_error` is false, the +/// transaction succeeds, but the unlocking is not performed. +/// Setting this flag to `false` is useful when bundling this instruction +/// together with [`crate::instructions::redeem`], so that the unlocking +/// is attempted optimistically. +pub fn release_inbound_unlock(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { let inbox_item = &mut ctx.accounts.common.inbox_item; - inbox_item.release()?; + let released = inbox_item.try_release()?; + + if !released { + if args.revert_on_delay { + return Err(NTTError::ReleaseTimestampNotReached.into()); + } else { + return Ok(()); + } + } + assert!(inbox_item.released); match ctx.accounts.common.config.mode { Mode::Burning => Err(NTTError::InvalidMode.into()), Mode::Locking => token_interface::transfer_checked( diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 8aa34ea49..9f6e30ac4 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -43,12 +43,12 @@ pub mod example_native_token_transfers { instructions::redeem(ctx, args) } - pub fn release_inbound_mint(ctx: Context) -> Result<()> { - instructions::release_inbound_mint(ctx) + pub fn release_inbound_mint(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { + instructions::release_inbound_mint(ctx, args) } - pub fn release_inbound_unlock(ctx: Context) -> Result<()> { - instructions::release_inbound_unlock(ctx) + pub fn release_inbound_unlock(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { + instructions::release_inbound_unlock(ctx, args) } pub fn transfer_ownership( diff --git a/solana/programs/example-native-token-transfers/src/queue/inbox.rs b/solana/programs/example-native-token-transfers/src/queue/inbox.rs index 794e29c1b..650ed0258 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbox.rs @@ -20,11 +20,13 @@ pub struct InboxItem { impl InboxItem { pub const SEED_PREFIX: &'static [u8] = b"inbox_item"; - pub fn release(&mut self) -> Result<()> { + /// Attempt to release the transfer. + /// Returns true if the transfer was released, false if it was not yet time to release it. + pub fn try_release(&mut self) -> Result { let now = current_timestamp(); if self.release_timestamp > now { - return Err(NTTError::ReleaseTimestampNotReached.into()); + return Ok(false) } if self.released { @@ -33,7 +35,7 @@ impl InboxItem { self.released = true; - Ok(()) + Ok(true) } } diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index b00fd3db5..3ce92a0d8 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -138,11 +138,13 @@ describe('example-native-token-transfers', () => { limit: new BN(1000000) }) - await ntt.redeem({ + const released = await ntt.redeem({ payer, vaa: vaaBuf, }) + expect(released).to.equal(true) + // grab logs // await program.provider.connection.confirmTransaction(redeemTx, 'confirmed'); // const tx = await anchor.getProvider().connection.getParsedTransaction(redeemTx, { diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 6bebeb34e..f4d98a50f 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -356,6 +356,7 @@ export class NTT { payer: PublicKey chain: ChainName | ChainId sequence: BN + revertOnDelay: boolean recipient?: PublicKey config?: Config }): Promise { @@ -369,7 +370,9 @@ export class NTT { args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress return await this.program.methods - .releaseInboundMint() + .releaseInboundMint({ + revertOnDelay: args.revertOnDelay + }) .accounts({ common: { payer: args.payer, @@ -387,6 +390,7 @@ export class NTT { payer: Keypair chain: ChainName | ChainId sequence: BN + revertOnDelay: boolean config?: Config }): Promise { if (await this.isPaused()) { @@ -409,6 +413,7 @@ export class NTT { payer: PublicKey chain: ChainName | ChainId sequence: BN + revertOnDelay: boolean recipient?: PublicKey config?: Config }): Promise { @@ -422,7 +427,9 @@ export class NTT { args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress return await this.program.methods - .releaseInboundUnlock() + .releaseInboundUnlock({ + revertOnDelay: args.revertOnDelay + }) .accounts({ common: { payer: args.payer, @@ -437,6 +444,29 @@ export class NTT { .instruction() } + async releaseInboundUnlock(args: { + payer: Keypair + chain: ChainName | ChainId + sequence: BN + revertOnDelay: boolean + config?: Config + }): Promise { + if (await this.isPaused()) { + throw new Error('Contract is paused') + } + + const txArgs = { + ...args, + payer: args.payer.publicKey + } + + const tx = new Transaction() + tx.add(await this.createReleaseInboundUnlockInstruction(txArgs)) + + const signers = [args.payer] + await this.sendAndConfirmTransaction(tx, signers) + } + async setSibling(args: { payer: Keypair owner: Keypair @@ -501,12 +531,19 @@ export class NTT { .instruction() } - // TODO: add option to return if the redeem was queued + /** + * Redeems a VAA. + * + * @returns Whether the transfer was released. If the transfer was delayed, + * this will be false. In that case, a subsequent call to + * `releaseInboundMint` or `releaseInboundUnlock` will release the + * transfer after the delay (24h). + */ async redeem(args: { payer: Keypair vaa: SignedVaa config?: Config - }): Promise { + }): Promise { const config = await this.getConfig(args.config) const redeemArgs = { @@ -523,6 +560,19 @@ export class NTT { // TODO: explain why this is fine here const chainId = managerMessage.chainId as ChainId + // Here we create a transaction with two instructions: + // 1. redeem + // 2. releaseInboundMint or releaseInboundUnlock (depending on mode) + // + // The first instruction places the transfer in the inbox, then the second instruction + // releases it. + // + // In case the redeemed amount exceeds the remaining inbound rate limit capacity, + // the transaction gets delayed. If this happens, the second instruction will not actually + // be able to release the transfer yet. + // To make sure the transaction still succeeds, we set revertOnDelay to false, which will + // just make the second instruction a no-op in case the transfer is delayed. + const tx = new Transaction() tx.add(await this.createRedeemInstruction(redeemArgs)) @@ -531,7 +581,8 @@ export class NTT { payer: args.payer.publicKey, sequence: new BN(managerMessage.sequence.toString()), recipient: new PublicKey(managerMessage.payload.recipientAddress), - chain: chainId + chain: chainId, + revertOnDelay: false } if (config.mode.locking != null) { @@ -542,6 +593,10 @@ export class NTT { const signers = [args.payer] await this.sendAndConfirmTransaction(tx, signers) + + // Let's check if the transfer was released + const inboxItem = await this.getInboxItem(chainId, new BN(managerMessage.sequence.toString())) + return inboxItem.released } // Account access From 380801513e7872cc3c1c9ea5926a707472caa9e3 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 21:13:10 +0400 Subject: [PATCH 30/90] solana: transfer: remove race condition In the previous implementation, the outbox item account was a PDA keyed by the sequence number. This meant that the client had to query the next sequence, then submit a transaction with the outbox item account seeded by that sequence. This created a race condition, since the query and submit cannot be done atomically. Instead, we just remove the requirement that the account is a PDA, and instead require it to be a signer when creating the outbox item. This removes the race condition because the client can just generate a new unique address, and store it for later (which they had to do with the sequence number anyway) --- .../src/instructions/release_outbound.rs | 4 +- .../src/instructions/transfer.rs | 12 ----- .../src/queue/outbox.rs | 3 -- solana/tests/example-native-token-transfer.ts | 4 +- solana/ts/sdk/index.ts | 50 ++++++++----------- 5 files changed, 24 insertions(+), 49 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index c9b870276..14b87de13 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -25,7 +25,7 @@ pub struct ReleaseOutbound<'info> { #[account( mut, - seeds = [b"message", outbox_item.sequence.to_be_bytes().as_ref()], + seeds = [b"message", outbox_item.key().as_ref()], bump, )] /// CHECK: initialized and written to by wormhole core bridge @@ -117,7 +117,7 @@ pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArg &[b"emitter", &[ctx.bumps.emitter]], &[ b"message", - accs.outbox_item.sequence.to_be_bytes().as_ref(), + accs.outbox_item.key().as_ref(), &[ctx.bumps.wormhole_message], ], ], diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index c2775e1f5..f4384e2ac 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -48,14 +48,6 @@ pub struct Transfer<'info> { init, payer = payer, space = 8 + OutboxItem::INIT_SPACE, - // TODO: this creates a race condition - // when two people try to send a transfer at the same time - // only one of them can claim the sequence number. - // Not sure if there's a way around this, the PDA has to be seeded by - // something unique to this transfer, so I think it has to include the - // sequence number (everything else can be the same) - seeds = [OutboxItem::SEED_PREFIX, seq.sequence.to_be_bytes().as_ref()], - bump, )] pub outbox_item: Account<'info, OutboxItem>, @@ -109,7 +101,6 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( insert_into_outbox( &mut accs.common, amount, - ctx.bumps.common.outbox_item, recipient_chain, recipient_address, ) @@ -168,7 +159,6 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( insert_into_outbox( &mut accs.common, amount, - ctx.bumps.common.outbox_item, recipient_chain, recipient_address, ) @@ -177,7 +167,6 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( fn insert_into_outbox( common: &mut Transfer<'_>, amount: NormalizedAmount, - outbox_item_bump: u8, recipient_chain: ChainId, recipient_address: [u8; 32], ) -> Result<()> { @@ -187,7 +176,6 @@ fn insert_into_outbox( let sequence = common.seq.next(); common.outbox_item.set_inner(OutboxItem { - bump: outbox_item_bump, sequence, amount, recipient_chain, diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 113600381..40bec562e 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -13,7 +13,6 @@ use super::rate_limit::RateLimitState; #[derive(InitSpace)] // TODO: generalise this to arbitrary outbound messages (via a generic parameter in place of amount and recipient info) pub struct OutboxItem { - pub bump: u8, pub sequence: u64, pub amount: NormalizedAmount, pub recipient_chain: ChainId, @@ -25,8 +24,6 @@ pub struct OutboxItem { } impl OutboxItem { - pub const SEED_PREFIX: &'static [u8] = b"outbox_item"; - pub fn release(&mut self) -> Result<()> { let now = current_timestamp(); if self.release_timestamp > now { diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index 3ce92a0d8..c384be832 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -65,7 +65,7 @@ describe('example-native-token-transfers', () => { const amount = new BN(100000) - const sequence = await ntt.transfer({ + const outboxItem = await ntt.transfer({ payer, from: tokenAccount, fromAuthority: user, @@ -75,7 +75,7 @@ describe('example-native-token-transfers', () => { shouldQueue: false }) - const wormholeMessage = ntt.wormholeMessageAccountAddress(sequence) + const wormholeMessage = ntt.wormholeMessageAccountAddress(outboxItem) const wormholeMessageAccount = await program.provider.connection.getAccountInfo(wormholeMessage) if (wormholeMessageAccount === null) { diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index f4d98a50f..5c00ae888 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -4,15 +4,14 @@ import { BN, translateError, type IdlAccounts, type Program } from '@coral-xyz/a import { associatedAddress } from '@coral-xyz/anchor/dist/cjs/utils/token' import { type PublicKeyInitData, - PublicKey, - type Keypair, + PublicKey, Keypair, type TransactionInstruction, Transaction, sendAndConfirmTransaction, type TransactionSignature } from '@solana/web3.js' import { type ExampleNativeTokenTransfers } from '../../target/types/example_native_token_transfers' -import { EndpointMessage, ManagerMessage } from './payloads/common' +import { ManagerMessage } from './payloads/common' import { NativeTokenTransfer } from './payloads/transfers' import { WormholeEndpointMessage } from './payloads/wormhole' @@ -70,10 +69,6 @@ export class NTT { return this.derive_pda(Buffer.from('outbox_rate_limit')) } - outboxItemAccountAddress(sequence: BN): PublicKey { - return this.derive_pda([Buffer.from('outbox_item'), sequence.toBuffer('be', 8)]) - } - inboxRateLimitAccountAddress(chain: ChainName | ChainId): PublicKey { const chainId = coalesceChainId(chain) return this.derive_pda([Buffer.from('inbox_rate_limit'), new BN(chainId).toBuffer('be', 2)]) @@ -97,8 +92,8 @@ export class NTT { return this.derive_pda([Buffer.from('emitter')]) } - wormholeMessageAccountAddress(sequence: BN): PublicKey { - return this.derive_pda([Buffer.from('message'), sequence.toBuffer('be', 8)]) + wormholeMessageAccountAddress(outboxItem: PublicKey): PublicKey { + return this.derive_pda([Buffer.from('message'), outboxItem.toBuffer()]) } mintAuthorityAddress(): PublicKey { @@ -158,17 +153,18 @@ export class NTT { // TODO: implement shouldQueue logic // actually, this should be on the inbound direction shouldQueue: boolean + outboxItem?: Keypair config?: Config - }): Promise { + }): Promise { const config: Config = await this.getConfig(args.config) - const sequence = await this.nextSequence() + const outboxItem = args.outboxItem ?? Keypair.generate() const txArgs = { ...args, payer: args.payer.publicKey, fromAuthority: args.fromAuthority.publicKey, - sequence, + outboxItem: outboxItem.publicKey, config } @@ -183,17 +179,17 @@ export class NTT { const releaseIx: TransactionInstruction = await this.createReleaseOutboundInstruction({ payer: args.payer.publicKey, - sequence + outboxItem: outboxItem.publicKey }) - const signers = [args.payer, args.fromAuthority] + const signers = [args.payer, args.fromAuthority, outboxItem] const tx = new Transaction() tx.add(transferIx) tx.add(releaseIx) await this.sendAndConfirmTransaction(tx, signers) - return sequence + return outboxItem.publicKey } /** @@ -218,7 +214,7 @@ export class NTT { amount: BN recipientChain: ChainName recipientAddress: ArrayLike - sequence?: BN + outboxItem: PublicKey config?: Config }): Promise { const config = await this.getConfig(args.config) @@ -229,9 +225,6 @@ export class NTT { const chainId = toChainId(args.recipientChain) const mint = await this.mintAccountAddress(config) - // TODO: how to gracefully handle the race condition when multiple people - // attempt to grab the same sequence number? - const sequence = args.sequence ?? await this.nextSequence() return await this.program.methods .transferBurn({ @@ -247,7 +240,7 @@ export class NTT { from: args.from, fromAuthority: args.fromAuthority, seq: this.sequenceTrackerAccountAddress(), - outboxItem: this.outboxItemAccountAddress(sequence), + outboxItem: args.outboxItem, rateLimit: this.outboxRateLimitAccountAddress() } }) @@ -255,7 +248,7 @@ export class NTT { } /** - * Creates a transfer_lock instruction. The `payer` and `fromAuthority` + * Creates a transfer_lock instruction. The `payer`, `fromAuthority`, and `outboxItem` * arguments must sign the transaction */ async createTransferLockInstruction(args: { @@ -265,7 +258,7 @@ export class NTT { amount: BN recipientChain: ChainName recipientAddress: ArrayLike - sequence?: BN + outboxItem: PublicKey config?: Config }): Promise { const config = await this.getConfig(args.config) @@ -276,9 +269,6 @@ export class NTT { const chainId = toChainId(args.recipientChain) const mint = await this.mintAccountAddress(config) - // TODO: how to gracefully handle the race condition when multiple people - // attempt to grab the same sequence number? - const sequence = args.sequence ?? await this.nextSequence() return await this.program.methods .transferLock({ @@ -295,7 +285,7 @@ export class NTT { fromAuthority: args.fromAuthority, tokenProgram: await this.tokenProgram(config), seq: this.sequenceTrackerAccountAddress(), - outboxItem: this.outboxItemAccountAddress(sequence), + outboxItem: args.outboxItem, rateLimit: this.outboxRateLimitAccountAddress() }, custodyAuthority: this.custodyAuthorityAddress(), @@ -309,7 +299,7 @@ export class NTT { */ async createReleaseOutboundInstruction(args: { payer: PublicKey - sequence: BN + outboxItem: PublicKey }): Promise { const whAccs = getWormholeDerivedAccounts(this.program.programId, this.wormholeId) @@ -318,8 +308,8 @@ export class NTT { .accounts({ payer: args.payer, config: { config: this.configAccountAddress() }, - outboxItem: this.outboxItemAccountAddress(args.sequence), - wormholeMessage: this.wormholeMessageAccountAddress(args.sequence), + outboxItem: args.outboxItem, + wormholeMessage: this.wormholeMessageAccountAddress(args.outboxItem), emitter: whAccs.wormholeEmitter, wormholeBridge: whAccs.wormholeBridge, wormholeFeeCollector: whAccs.wormholeFeeCollector, @@ -331,7 +321,7 @@ export class NTT { async releaseOutbound(args: { payer: Keypair - sequence: BN + outboxItem: PublicKey config?: Config }): Promise { if (await this.isPaused()) { From 0fab3fe8d31cb3336195b529769c8a5b85b05fe9 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Mon, 12 Feb 2024 23:34:30 +0400 Subject: [PATCH 31/90] solana: transfer: add option to revert if tx would be delayed --- .../src/error.rs | 2 ++ .../src/instructions/release_outbound.rs | 17 ++++++++++++++--- .../src/instructions/transfer.rs | 11 +++++++++++ .../src/queue/outbox.rs | 10 +++++++--- solana/ts/sdk/index.ts | 19 +++++++++++++------ 5 files changed, 47 insertions(+), 12 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index f2e6dc887..f6d7b2742 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -19,4 +19,6 @@ pub enum NTTError { InvalidMode, #[msg("InvalidMintAuthority")] InvalidMintAuthority, + #[msg("TransferExceedsRateLimit")] + TransferExceedsRateLimit, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 14b87de13..e8482fe7b 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -63,15 +63,26 @@ pub struct ReleaseOutbound<'info> { } #[derive(AnchorSerialize, AnchorDeserialize)] -pub struct ReleaseOutboundArgs {} +pub struct ReleaseOutboundArgs { + pub revert_on_delay: bool, +} -pub fn release_outbound(ctx: Context, _args: ReleaseOutboundArgs) -> Result<()> { +pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs) -> Result<()> { let accs = ctx.accounts; let batch_id = 0; // TODO: record endpoint position - accs.outbox_item.release()?; + let released = accs.outbox_item.try_release()?; + + if !released { + if args.revert_on_delay { + return Err(NTTError::ReleaseTimestampNotReached.into()); + } else { + return Ok(()); + } + } + assert!(accs.outbox_item.released); let message: EndpointMessage = EndpointMessage::new(ManagerMessage { chain_id: accs.config.chain_id, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index f4384e2ac..0562431e4 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -3,6 +3,7 @@ use anchor_spl::token_interface; use crate::{ chain_id::ChainId, + clock::current_timestamp, config::*, error::NTTError, normalized_amount::NormalizedAmount, @@ -62,6 +63,7 @@ pub struct TransferArgs { pub amount: u64, pub recipient_chain: ChainId, pub recipient_address: [u8; 32], + pub should_queue: bool, } // Burn/mint @@ -78,6 +80,7 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( amount, recipient_chain, recipient_address, + should_queue, } = args; let amount = NormalizedAmount::normalize(amount, accs.common.mint.decimals); @@ -103,6 +106,7 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( amount, recipient_chain, recipient_address, + should_queue, ) } @@ -134,6 +138,7 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( amount, recipient_chain, recipient_address, + should_queue, } = args; let amount = NormalizedAmount::normalize(amount, accs.common.mint.decimals); @@ -161,6 +166,7 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( amount, recipient_chain, recipient_address, + should_queue, ) } @@ -169,10 +175,15 @@ fn insert_into_outbox( amount: NormalizedAmount, recipient_chain: ChainId, recipient_address: [u8; 32], + should_queue: bool, ) -> Result<()> { // consume the rate limit, or delay the transfer if it's outside the limit let release_timestamp = common.rate_limit.rate_limit.consume_or_delay(amount); + if release_timestamp > current_timestamp() && !should_queue { + return Err(NTTError::TransferExceedsRateLimit.into()); + } + let sequence = common.seq.next(); common.outbox_item.set_inner(OutboxItem { diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 40bec562e..6b4d653f8 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -24,10 +24,14 @@ pub struct OutboxItem { } impl OutboxItem { - pub fn release(&mut self) -> Result<()> { + /// Attempt to release the transfer. + /// Returns true if the transfer was released, false if it was not yet time to release it. + /// TODO: this is duplicated in inbox.rs. factor out? + pub fn try_release(&mut self) -> Result { let now = current_timestamp(); + if self.release_timestamp > now { - return Err(NTTError::ReleaseTimestampNotReached.into()); + return Ok(false) } if self.released { @@ -36,7 +40,7 @@ impl OutboxItem { self.released = true; - Ok(()) + Ok(true) } } diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 5c00ae888..520a5b815 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -150,8 +150,6 @@ export class NTT { amount: BN recipientChain: ChainName recipientAddress: ArrayLike - // TODO: implement shouldQueue logic - // actually, this should be on the inbound direction shouldQueue: boolean outboxItem?: Keypair config?: Config @@ -179,7 +177,8 @@ export class NTT { const releaseIx: TransactionInstruction = await this.createReleaseOutboundInstruction({ payer: args.payer.publicKey, - outboxItem: outboxItem.publicKey + outboxItem: outboxItem.publicKey, + revertOnDelay: !args.shouldQueue }) const signers = [args.payer, args.fromAuthority, outboxItem] @@ -215,6 +214,7 @@ export class NTT { recipientChain: ChainName recipientAddress: ArrayLike outboxItem: PublicKey + shouldQueue: boolean config?: Config }): Promise { const config = await this.getConfig(args.config) @@ -230,7 +230,8 @@ export class NTT { .transferBurn({ amount: args.amount, recipientChain: { id: chainId }, - recipientAddress: Array.from(args.recipientAddress) + recipientAddress: Array.from(args.recipientAddress), + shouldQueue: args.shouldQueue }) .accounts({ common: { @@ -258,6 +259,7 @@ export class NTT { amount: BN recipientChain: ChainName recipientAddress: ArrayLike + shouldQueue: boolean outboxItem: PublicKey config?: Config }): Promise { @@ -274,7 +276,8 @@ export class NTT { .transferLock({ amount: args.amount, recipientChain: { id: chainId }, - recipientAddress: Array.from(args.recipientAddress) + recipientAddress: Array.from(args.recipientAddress), + shouldQueue: args.shouldQueue }) .accounts({ common: { @@ -300,11 +303,14 @@ export class NTT { async createReleaseOutboundInstruction(args: { payer: PublicKey outboxItem: PublicKey + revertOnDelay: boolean }): Promise { const whAccs = getWormholeDerivedAccounts(this.program.programId, this.wormholeId) return await this.program.methods - .releaseOutbound({}) + .releaseOutbound({ + revertOnDelay: args.revertOnDelay + }) .accounts({ payer: args.payer, config: { config: this.configAccountAddress() }, @@ -322,6 +328,7 @@ export class NTT { async releaseOutbound(args: { payer: Keypair outboxItem: PublicKey + revertOnDelay: boolean config?: Config }): Promise { if (await this.isPaused()) { From 58f843ea19aacdea7d9b3035df480e3cae180bef Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 13 Feb 2024 00:18:20 +0400 Subject: [PATCH 32/90] solana: InboundRateLimit -> InboxRateLimit --- .../src/instructions/admin.rs | 14 +++++++------- .../src/instructions/redeem.rs | 6 +++--- .../src/queue/inbox.rs | 8 ++++---- 3 files changed, 14 insertions(+), 14 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 60f4547bf..ee0c1cd7e 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -5,7 +5,7 @@ use crate::{ chain_id::ChainId, config::Config, normalized_amount::NormalizedAmount, - queue::{inbox::InboundRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, + queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, sibling::Sibling, }; @@ -81,15 +81,15 @@ pub struct SetSibling<'info> { #[account( init, - space = 8 + InboundRateLimit::INIT_SPACE, + space = 8 + InboxRateLimit::INIT_SPACE, payer = payer, seeds = [ - InboundRateLimit::SEED_PREFIX, + InboxRateLimit::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref() ], bump, )] - pub rate_limit: Account<'info, InboundRateLimit>, + pub rate_limit: Account<'info, InboxRateLimit>, #[account( constraint = mint.key() == config.mint @@ -114,7 +114,7 @@ pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> address: args.address, }); - ctx.accounts.rate_limit.set_inner(InboundRateLimit { + ctx.accounts.rate_limit.set_inner(InboxRateLimit { bump: ctx.bumps.rate_limit, rate_limit: RateLimitState::new(NormalizedAmount::normalize( args.limit, @@ -170,12 +170,12 @@ pub struct SetInboundLimit<'info> { #[account( mut, seeds = [ - InboundRateLimit::SEED_PREFIX, + InboxRateLimit::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref() ], bump = rate_limit.bump )] - pub rate_limit: Account<'info, InboundRateLimit>, + pub rate_limit: Account<'info, InboxRateLimit>, #[account( constraint = mint.key() == config.mint diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index b5ee03482..ebe96ddc9 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -6,7 +6,7 @@ use crate::{ config::*, error::NTTError, messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, - queue::inbox::{InboundRateLimit, InboxItem}, + queue::inbox::{InboxItem, InboxRateLimit}, sibling::Sibling, }; @@ -54,12 +54,12 @@ pub struct Redeem<'info> { #[account( mut, seeds = [ - InboundRateLimit::SEED_PREFIX, + InboxRateLimit::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref() ], bump, )] - pub rate_limit: Account<'info, InboundRateLimit>, + pub rate_limit: Account<'info, InboxRateLimit>, pub system_program: Program<'info, System>, } diff --git a/solana/programs/example-native-token-transfers/src/queue/inbox.rs b/solana/programs/example-native-token-transfers/src/queue/inbox.rs index 650ed0258..91e735e53 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbox.rs @@ -43,23 +43,23 @@ impl InboxItem { /// SECURITY: must check the PDA (since there are multiple PDAs, namely one for each chain.) #[account] #[derive(InitSpace)] -pub struct InboundRateLimit { +pub struct InboxRateLimit { pub bump: u8, pub rate_limit: RateLimitState, } -impl InboundRateLimit { +impl InboxRateLimit { pub const SEED_PREFIX: &'static [u8] = b"inbox_rate_limit"; } -impl Deref for InboundRateLimit { +impl Deref for InboxRateLimit { type Target = RateLimitState; fn deref(&self) -> &Self::Target { &self.rate_limit } } -impl DerefMut for InboundRateLimit { +impl DerefMut for InboxRateLimit { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.rate_limit } From 767f52b45928c788b139fdf4578fd112d58d6be2 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 13 Feb 2024 01:41:52 +0400 Subject: [PATCH 33/90] solana: implement backflows --- .../src/instructions/admin.rs | 6 +-- .../src/instructions/initialize.rs | 4 +- .../src/instructions/redeem.rs | 21 ++++++-- .../src/instructions/transfer.rs | 50 ++++++++++++++++--- .../src/normalized_amount.rs | 1 + .../src/queue/rate_limit.rs | 31 ++++++++++-- solana/tests/example-native-token-transfer.ts | 16 +++--- solana/ts/sdk/index.ts | 15 +++--- 8 files changed, 110 insertions(+), 34 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index ee0c1cd7e..c2e8d7818 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -89,7 +89,7 @@ pub struct SetSibling<'info> { ], bump, )] - pub rate_limit: Account<'info, InboxRateLimit>, + pub inbox_rate_limit: Account<'info, InboxRateLimit>, #[account( constraint = mint.key() == config.mint @@ -114,8 +114,8 @@ pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> address: args.address, }); - ctx.accounts.rate_limit.set_inner(InboxRateLimit { - bump: ctx.bumps.rate_limit, + ctx.accounts.inbox_rate_limit.set_inner(InboxRateLimit { + bump: ctx.bumps.inbox_rate_limit, rate_limit: RateLimitState::new(NormalizedAmount::normalize( args.limit, ctx.accounts.mint.decimals, diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 1bc254f08..e311399ca 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -11,7 +11,7 @@ use crate::{ // TODO: upgradeability #[derive(Accounts)] -#[instruction(mode: crate::config::Mode)] +#[instruction(args: InitializeArgs)] pub struct Initialize<'info> { #[account(mut)] pub payer: Signer<'info>, @@ -29,7 +29,7 @@ pub struct Initialize<'info> { #[account( constraint = - mode == crate::config::Mode::Burning + args.mode == crate::config::Mode::Burning || mint.mint_authority.unwrap() == mint_authority.key() @ NTTError::InvalidMintAuthority, )] diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index ebe96ddc9..f9cd53328 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -3,10 +3,15 @@ use anchor_lang::prelude::*; use wormhole_anchor_sdk::wormhole::PostedVaa; use crate::{ + clock::current_timestamp, config::*, error::NTTError, messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, - queue::inbox::{InboxItem, InboxRateLimit}, + queue::{ + inbox::{InboxItem, InboxRateLimit}, + outbox::OutboxRateLimit, + rate_limit::RateLimitResult, + }, sibling::Sibling, }; @@ -59,7 +64,9 @@ pub struct Redeem<'info> { ], bump, )] - pub rate_limit: Account<'info, InboxRateLimit>, + pub inbox_rate_limit: Account<'info, InboxRateLimit>, + + pub outbox_rate_limit: Account<'info, OutboxRateLimit>, pub system_program: Program<'info, System>, } @@ -76,7 +83,15 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let recipient_address = Pubkey::try_from(message.payload.to).map_err(|_| NTTError::InvalidRecipientAddress)?; - let release_timestamp = accs.rate_limit.rate_limit.consume_or_delay(amount); + let release_timestamp = match accs.inbox_rate_limit.rate_limit.consume_or_delay(amount) { + RateLimitResult::Consumed => { + // When receiving a transfer, we refill the outbound rate limit with + // the same amount (we call this "backflow") + accs.outbox_rate_limit.rate_limit.refill(amount); + current_timestamp() + } + RateLimitResult::Delayed(release_timestamp) => release_timestamp, + }; accs.inbox_item.set_inner(InboxItem { bump: ctx.bumps.inbox_item, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 0562431e4..eef50e0ca 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -7,7 +7,11 @@ use crate::{ config::*, error::NTTError, normalized_amount::NormalizedAmount, - queue::outbox::{OutboxItem, OutboxRateLimit}, + queue::{ + inbox::InboxRateLimit, + outbox::{OutboxItem, OutboxRateLimit}, + rate_limit::RateLimitResult, + }, }; // this will burn the funds and create an account that either allows sending the @@ -53,7 +57,7 @@ pub struct Transfer<'info> { pub outbox_item: Account<'info, OutboxItem>, #[account(mut)] - pub rate_limit: Account<'info, OutboxRateLimit>, + pub outbox_rate_limit: Account<'info, OutboxRateLimit>, pub system_program: Program<'info, System>, } @@ -69,8 +73,18 @@ pub struct TransferArgs { // Burn/mint #[derive(Accounts)] +#[instruction(args: TransferArgs)] pub struct TransferBurn<'info> { pub common: Transfer<'info>, + + #[account( + mut, + seeds = [InboxRateLimit::SEED_PREFIX, args.recipient_chain.id.to_be_bytes().as_ref()], + bump = inbox_rate_limit.bump, + )] + // NOTE: it would be nice to put this into `common`, but that way we don't + // have access to the instruction args + pub inbox_rate_limit: Account<'info, InboxRateLimit>, } // TODO: fees for relaying? @@ -103,6 +117,7 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( insert_into_outbox( &mut accs.common, + &mut accs.inbox_rate_limit, amount, recipient_chain, recipient_address, @@ -113,9 +128,19 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( // Lock/unlock #[derive(Accounts)] +#[instruction(args: TransferArgs)] pub struct TransferLock<'info> { pub common: Transfer<'info>, + #[account( + mut, + seeds = [InboxRateLimit::SEED_PREFIX, args.recipient_chain.id.to_be_bytes().as_ref()], + bump = inbox_rate_limit.bump, + )] + // NOTE: it would be nice to put this into `common`, but that way we don't + // have access to the instruction args + pub inbox_rate_limit: Account<'info, InboxRateLimit>, + #[account( seeds = [b"custody_authority"], bump, @@ -163,6 +188,7 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( insert_into_outbox( &mut accs.common, + &mut accs.inbox_rate_limit, amount, recipient_chain, recipient_address, @@ -172,17 +198,27 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( fn insert_into_outbox( common: &mut Transfer<'_>, + inbox_rate_limit: &mut InboxRateLimit, amount: NormalizedAmount, recipient_chain: ChainId, recipient_address: [u8; 32], should_queue: bool, ) -> Result<()> { // consume the rate limit, or delay the transfer if it's outside the limit - let release_timestamp = common.rate_limit.rate_limit.consume_or_delay(amount); - - if release_timestamp > current_timestamp() && !should_queue { - return Err(NTTError::TransferExceedsRateLimit.into()); - } + let release_timestamp = match common.outbox_rate_limit.rate_limit.consume_or_delay(amount) { + RateLimitResult::Consumed => { + // When sending a transfer, we refill the inbound rate limit for + // that chain the same amount (we call this "backflow") + inbox_rate_limit.rate_limit.refill(amount); + current_timestamp() + }, + RateLimitResult::Delayed(release_timestamp) => { + if !should_queue { + return Err(NTTError::TransferExceedsRateLimit.into()); + } + release_timestamp + } + }; let sequence = common.seq.next(); diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index 9fc38c059..389d285a1 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -20,6 +20,7 @@ pub const NORMALIZED_DECIMALS: u8 = 8; Copy, PartialEq, Eq, + // TODO: manually write this and make sure the decimals are the same PartialOrd, Ord, AnchorSerialize, diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index ed117f644..a0ad3cbff 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -17,6 +17,17 @@ pub struct RateLimitState { last_tx_timestamp: i64, } +/// The result of attempting to consume from a rate limiter. +#[derive(Clone, Copy, PartialEq, Debug)] +pub enum RateLimitResult { + /// If the rate limit is not exceeded, the transfer is immediate, + /// and the capacity is reduced. + Consumed, + /// If the rate limit is exceeded, the transfer is delayed until the + /// given timestamp. + Delayed(UnixTimestamp), +} + impl RateLimitState { pub fn new(limit: NormalizedAmount) -> Self { Self { @@ -65,18 +76,28 @@ impl RateLimitState { /// returned, and the remaining capacity is reduced. /// Otherwise, the timestamp at which the capacity will be available is /// returned. - pub fn consume_or_delay(&mut self, amount: NormalizedAmount) -> UnixTimestamp { + pub fn consume_or_delay(&mut self, amount: NormalizedAmount) -> RateLimitResult { let now = current_timestamp(); let capacity = self.capacity(); if capacity >= amount { self.capacity_at_last_tx = capacity - amount; self.last_tx_timestamp = now; - now + RateLimitResult::Consumed } else { - now + Self::RATE_LIMIT_DURATION + RateLimitResult::Delayed(now + Self::RATE_LIMIT_DURATION) } } + /// Refills the capacity by the given amount. + /// This is used to replenish the capacity via backflows. + pub fn refill(&mut self, amount: NormalizedAmount) { + self.capacity_at_last_tx = self + .capacity_at_last_tx + .saturating_add(amount) + .min(self.limit); + self.last_tx_timestamp = current_timestamp(); + } + pub fn set_limit(&mut self, limit: NormalizedAmount) { let old_limit = self.limit; let current_capacity = self.capacity(); @@ -116,7 +137,7 @@ mod tests { // consume 30k. should be immediate let immediately = rate_limit_state.consume_or_delay(NormalizedAmount::new(30_000, 8)); - assert_eq!(immediately, current_timestamp()); + assert_eq!(immediately, RateLimitResult::Consumed); assert_eq!( rate_limit_state.capacity(), NormalizedAmount::new(70_000, 8) @@ -136,7 +157,7 @@ mod tests { let tomorrow = rate_limit_state.consume_or_delay(NormalizedAmount::new(150_000, 8)); assert_eq!( tomorrow, - current_timestamp() + RateLimitState::RATE_LIMIT_DURATION + RateLimitResult::Delayed(current_timestamp() + RateLimitState::RATE_LIMIT_DURATION) ); // the limit is not changed, since the tx was delayed diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index c384be832..9ebbdc1ab 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -61,6 +61,14 @@ describe('example-native-token-transfers', () => { mode: 'locking' }) + await ntt.setSibling({ + payer, + owner, + chain: 'ethereum', + address: Buffer.from('BEEFFACE'.padStart(64, '0'), 'hex'), + limit: new BN(1000000) + }) + // transfer some tokens const amount = new BN(100000) @@ -130,14 +138,6 @@ describe('example-native-token-transfers', () => { await postVaa(program.provider.connection, payer, vaaBuf, ntt.wormholeId) - await ntt.setSibling({ - payer, - owner, - chain: 'ethereum', - address: Buffer.from('BEEFFACE'.padStart(64, '0'), 'hex'), - limit: new BN(1000000) - }) - const released = await ntt.redeem({ payer, vaa: vaaBuf, diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 520a5b815..bac605c25 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -242,8 +242,9 @@ export class NTT { fromAuthority: args.fromAuthority, seq: this.sequenceTrackerAccountAddress(), outboxItem: args.outboxItem, - rateLimit: this.outboxRateLimitAccountAddress() - } + outboxRateLimit: this.outboxRateLimitAccountAddress(), + }, + inboxRateLimit: this.inboxRateLimitAccountAddress(args.recipientChain) }) .instruction() } @@ -289,8 +290,9 @@ export class NTT { tokenProgram: await this.tokenProgram(config), seq: this.sequenceTrackerAccountAddress(), outboxItem: args.outboxItem, - rateLimit: this.outboxRateLimitAccountAddress() + outboxRateLimit: this.outboxRateLimitAccountAddress(), }, + inboxRateLimit: this.inboxRateLimitAccountAddress(args.recipientChain), custodyAuthority: this.custodyAuthorityAddress(), custody: await this.custodyAccountAddress(config) }) @@ -484,7 +486,7 @@ export class NTT { owner: args.owner.publicKey, config: this.configAccountAddress(), sibling: this.siblingAccountAddress(args.chain), - rateLimit: this.inboxRateLimitAccountAddress(args.chain), + inboxRateLimit: this.inboxRateLimitAccountAddress(args.chain), mint: config.mint, }) .signers([args.payer, args.owner]) @@ -513,7 +515,7 @@ export class NTT { const chainId = managerMessage.chainId as ChainId const sibling = this.siblingAccountAddress(chainId) - const rateLimit = this.inboxRateLimitAccountAddress(chainId) + const inboxRateLimit = this.inboxRateLimitAccountAddress(chainId) return await this.program.methods .redeem({}) @@ -523,7 +525,8 @@ export class NTT { sibling, vaa: derivePostedVaaKey(this.wormholeId, parseVaa(args.vaa).hash), inboxItem: this.inboxItemAccountAddress(chainId, new BN(managerMessage.sequence.toString())), - rateLimit, + inboxRateLimit, + outboxRateLimit: this.outboxRateLimitAccountAddress(), }) .instruction() } From 400536510af9de302bfd11e779901d9a6dc55644 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 13 Feb 2024 19:10:01 +0400 Subject: [PATCH 34/90] solana: move core bridge binary to tests/fixtures this is in preparation for using it with solana-program-test --- solana/Anchor.toml | 2 +- .../tests/fixtures}/mainnet_core_bridge.so | Bin 2 files changed, 1 insertion(+), 1 deletion(-) rename solana/{tests/accounts/mainnet => programs/example-native-token-transfers/tests/fixtures}/mainnet_core_bridge.so (100%) diff --git a/solana/Anchor.toml b/solana/Anchor.toml index a66a11926..59a10d0cd 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -21,7 +21,7 @@ url = "https://api.mainnet-beta.solana.com" ### Wormhole Core Bridge (Mainnet) -- Program [[test.genesis]] address = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth" -program = "tests/accounts/mainnet/mainnet_core_bridge.so" +program = "programs/example-native-token-transfers/tests/fixtures/mainnet_core_bridge.so" ### Wormhole Core Bridge (Mainnet) -- Config [[test.validator.account]] diff --git a/solana/tests/accounts/mainnet/mainnet_core_bridge.so b/solana/programs/example-native-token-transfers/tests/fixtures/mainnet_core_bridge.so similarity index 100% rename from solana/tests/accounts/mainnet/mainnet_core_bridge.so rename to solana/programs/example-native-token-transfers/tests/fixtures/mainnet_core_bridge.so From e60ccbbbfe2651c5c6c1be3bc0cbceb75ddf7b37 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 13 Feb 2024 19:11:05 +0400 Subject: [PATCH 35/90] solana: unify custody&mint token authorities these are used mutually exclusively anyway, so we can unify them into a single account --- .../src/instructions/initialize.rs | 17 +- .../src/instructions/release_inbound.rs | 37 ++- .../src/instructions/transfer.rs | 8 +- .../src/queue/rate_limit.rs | 14 + solana/tests/example-native-token-transfer.ts | 262 ++++++++++-------- solana/ts/sdk/index.ts | 25 +- 6 files changed, 197 insertions(+), 166 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index e311399ca..ea596b602 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -30,7 +30,7 @@ pub struct Initialize<'info> { #[account( constraint = args.mode == crate::config::Mode::Burning - || mint.mint_authority.unwrap() == mint_authority.key() + || mint.mint_authority.unwrap() == token_authority.key() @ NTTError::InvalidMintAuthority, )] pub mint: InterfaceAccount<'info, token_interface::Mint>, @@ -54,25 +54,22 @@ pub struct Initialize<'info> { pub rate_limit: Account<'info, OutboxRateLimit>, #[account( - seeds = [b"custody_authority"], + seeds = [b"token_authority"], bump, )] - pub custody_authority: AccountInfo<'info>, + pub token_authority: AccountInfo<'info>, #[account( init, payer = payer, associated_token::mint = mint, - associated_token::authority = custody_authority, + associated_token::authority = token_authority, )] + /// The custody account that holds tokens in locking mode. + /// NOTE: the account is unconditionally initialized, but not used in + /// burning mode. pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, - #[account( - seeds = [b"token_minter"], - bump, - )] - pub mint_authority: AccountInfo<'info>, - /// CHECK: checked to be the appropriate token progrem when initialising the /// associated token account for the given mint. pub token_program: Interface<'info, token_interface::TokenInterface>, diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 735c30935..c7d758244 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -25,6 +25,12 @@ pub struct ReleaseInbound<'info> { /// TODO: send to ATA? pub recipient: InterfaceAccount<'info, token_interface::TokenAccount>, + #[account( + seeds = [b"token_authority"], + bump, + )] + pub token_authority: AccountInfo<'info>, + #[account( mut, address = config.mint, @@ -45,13 +51,6 @@ pub struct ReleaseInboundArgs { #[derive(Accounts)] pub struct ReleaseInboundMint<'info> { common: ReleaseInbound<'info>, - - #[account( - seeds = [b"token_minter"], - bump, - )] - /// CHECK: the token program checks if this indeed the right authority for the mint - pub mint_authority: AccountInfo<'info>, } /// Release an inbound transfer and mint the tokens to the recipient. @@ -61,7 +60,10 @@ pub struct ReleaseInboundMint<'info> { /// Setting this flag to `false` is useful when bundling this instruction /// together with [`crate::instructions::redeem`] in a transaction, so that the minting /// is attempted optimistically. -pub fn release_inbound_mint(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { +pub fn release_inbound_mint( + ctx: Context, + args: ReleaseInboundArgs, +) -> Result<()> { let inbox_item = &mut ctx.accounts.common.inbox_item; let released = inbox_item.try_release()?; @@ -82,9 +84,9 @@ pub fn release_inbound_mint(ctx: Context, args: ReleaseInbou token_interface::MintTo { mint: ctx.accounts.common.mint.to_account_info(), to: ctx.accounts.common.recipient.to_account_info(), - authority: ctx.accounts.mint_authority.clone(), + authority: ctx.accounts.common.token_authority.clone(), }, - &[&[b"token_minter", &[ctx.bumps.mint_authority]]], + &[&[b"token_authority", &[ctx.bumps.common.token_authority]]], ), inbox_item .amount @@ -100,12 +102,6 @@ pub fn release_inbound_mint(ctx: Context, args: ReleaseInbou pub struct ReleaseInboundUnlock<'info> { common: ReleaseInbound<'info>, - #[account( - seeds = [b"custody_authority"], - bump, - )] - pub custody_authority: AccountInfo<'info>, - /// CHECK: the token program checks if this indeed the right authority for the mint #[account(mut)] pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, @@ -118,7 +114,10 @@ pub struct ReleaseInboundUnlock<'info> { /// Setting this flag to `false` is useful when bundling this instruction /// together with [`crate::instructions::redeem`], so that the unlocking /// is attempted optimistically. -pub fn release_inbound_unlock(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { +pub fn release_inbound_unlock( + ctx: Context, + args: ReleaseInboundArgs, +) -> Result<()> { let inbox_item = &mut ctx.accounts.common.inbox_item; let released = inbox_item.try_release()?; @@ -140,10 +139,10 @@ pub fn release_inbound_unlock(ctx: Context, args: ReleaseI token_interface::TransferChecked { from: ctx.accounts.custody.to_account_info(), to: ctx.accounts.common.recipient.to_account_info(), - authority: ctx.accounts.custody_authority.clone(), + authority: ctx.accounts.common.token_authority.clone(), mint: ctx.accounts.common.mint.to_account_info(), }, - &[&[b"custody_authority", &[ctx.bumps.custody_authority]]], + &[&[b"token_authority", &[ctx.bumps.common.token_authority]]], ), inbox_item .amount diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index eef50e0ca..6b2f72805 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -142,15 +142,15 @@ pub struct TransferLock<'info> { pub inbox_rate_limit: Account<'info, InboxRateLimit>, #[account( - seeds = [b"custody_authority"], + seeds = [b"token_authority"], bump, )] - pub custody_authority: AccountInfo<'info>, + pub token_authority: AccountInfo<'info>, #[account( mut, token::mint = common.mint, - token::authority = custody_authority, + token::authority = token_authority, )] pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, } @@ -211,7 +211,7 @@ fn insert_into_outbox( // that chain the same amount (we call this "backflow") inbox_rate_limit.rate_limit.refill(amount); current_timestamp() - }, + } RateLimitResult::Delayed(release_timestamp) => { if !should_queue { return Err(NTTError::TransferExceedsRateLimit.into()); diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index a0ad3cbff..2ff9e64ac 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -182,5 +182,19 @@ mod tests { rate_limit_state.capacity(), NormalizedAmount::new(95_000, 8) ); + + // now refill 2k + rate_limit_state.refill(NormalizedAmount::new(2_000, 8)); + assert_eq!( + rate_limit_state.capacity(), + NormalizedAmount::new(97_000, 8) + ); + + // now refill 50k + rate_limit_state.refill(NormalizedAmount::new(50_000, 8)); + assert_eq!( + rate_limit_state.capacity(), + NormalizedAmount::new(100_000, 8) + ); } } diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index 9ebbdc1ab..09d793131 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -16,17 +16,23 @@ describe('example-native-token-transfers', () => { anchor.setProvider(anchor.AnchorProvider.env()) const program = anchor.workspace.ExampleNativeTokenTransfers as Program + const owner = anchor.web3.Keypair.generate() + const payer = anchor.web3.Keypair.generate() + const ntt = new NTT({ + program, + wormholeId: 'worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth' + }) + const user = anchor.web3.Keypair.generate() + let tokenAccount: anchor.web3.PublicKey + - it('Supports lock&unlock', async () => { - // TODO: factor out this test so it can be reused for burn&mint - const payer = anchor.web3.Keypair.generate() - const owner = anchor.web3.Keypair.generate() + let mint: anchor.web3.PublicKey + + before(async () => { // airdrop some tokens to payer const signature = await program.provider.connection.requestAirdrop(payer.publicKey, 1000000000) await program.provider.connection.confirmTransaction(signature) - // check owner lamports balance - - const mint = await spl.createMint( + mint = await spl.createMint( program.provider.connection, payer, owner.publicKey, @@ -34,129 +40,149 @@ describe('example-native-token-transfers', () => { 9 ) - const user = anchor.web3.Keypair.generate() - const tokenAccount = await spl.createAssociatedTokenAccount(program.provider.connection, payer, mint, user.publicKey) + tokenAccount = await spl.createAssociatedTokenAccount(program.provider.connection, payer, mint, user.publicKey) await spl.mintTo(program.provider.connection, payer, mint, tokenAccount, owner, BigInt(10000000)) + }); + + describe('Locking', () => { + before(async () => { + await spl.setAuthority( + program.provider.connection, + payer, + mint, + owner, + 0, // mint + ntt.tokenAuthorityAddress() + ) - const ntt = new NTT({ - program, - wormholeId: 'worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth' - }) - - await spl.setAuthority( - program.provider.connection, - payer, - mint, - owner, - 0, // mint - ntt.mintAuthorityAddress() - ) - - await ntt.initialize({ - payer, - owner, - chain: 'solana', - mint, - outboundLimit: new BN(1000000), - mode: 'locking' - }) - - await ntt.setSibling({ - payer, - owner, - chain: 'ethereum', - address: Buffer.from('BEEFFACE'.padStart(64, '0'), 'hex'), - limit: new BN(1000000) - }) - - // transfer some tokens - - const amount = new BN(100000) - - const outboxItem = await ntt.transfer({ - payer, - from: tokenAccount, - fromAuthority: user, - amount, - recipientChain: 'ethereum', - recipientAddress: Array.from(user.publicKey.toBuffer()), // TODO: dummy - shouldQueue: false - }) - - const wormholeMessage = ntt.wormholeMessageAccountAddress(outboxItem) - - const wormholeMessageAccount = await program.provider.connection.getAccountInfo(wormholeMessage) - if (wormholeMessageAccount === null) { - throw new Error('wormhole message account not found') - } - - const messageData = PostedMessageData.deserialize(wormholeMessageAccount.data) - const endpointMessage = WormholeEndpointMessage.deserialize( - messageData.message.payload, - a => ManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) - ) - - // assert theat amount is what we expect - expect(endpointMessage.managerPayload.payload.normalizedAmount).to.deep.equal(new NormalizedAmount(BigInt(10000), 8)) - // get from balance - const balance = await program.provider.connection.getTokenAccountBalance(tokenAccount) - expect(balance.value.amount).to.equal('9900000') - - const emitter = - new MockEmitter( - '00000000000000000000000000000000000000000000000000000000BEEFFACE', - toChainId('ethereum'), - Number(0) // sequence + await ntt.initialize({ + payer, + owner, + chain: 'solana', + mint, + outboundLimit: new BN(1000000), + mode: 'locking' + }) + + await ntt.setSibling({ + payer, + owner, + chain: 'ethereum', + address: Buffer.from('BEEFFACE'.padStart(64, '0'), 'hex'), + limit: new BN(1000000) + }) + + }); + + it('Can send tokens', async () => { + // TODO: factor out this test so it can be reused for burn&mint + + // transfer some tokens + + const amount = new BN(100000) + + const outboxItem = await ntt.transfer({ + payer, + from: tokenAccount, + fromAuthority: user, + amount, + recipientChain: 'ethereum', + recipientAddress: Array.from(user.publicKey.toBuffer()), // TODO: dummy + shouldQueue: false + }) + + const wormholeMessage = ntt.wormholeMessageAccountAddress(outboxItem) + + const wormholeMessageAccount = await program.provider.connection.getAccountInfo(wormholeMessage) + if (wormholeMessageAccount === null) { + throw new Error('wormhole message account not found') + } + + const messageData = PostedMessageData.deserialize(wormholeMessageAccount.data) + const endpointMessage = WormholeEndpointMessage.deserialize( + messageData.message.payload, + a => ManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) ) - const guardians = new MockGuardians(0, [GUARDIAN_KEY]) - - const sendingEndpointMessage: EndpointMessage = { - managerPayload: new ManagerMessage( - toChainId('ethereum'), - BigInt(0), - Buffer.from('BEEF'.padStart(64, '0'), 'hex'), - Buffer.from('FACE'.padStart(64, '0'), 'hex'), - new NativeTokenTransfer( - Buffer.from('FAFA'.padStart(64, '0'), 'hex'), - new NormalizedAmount(BigInt(10000), 8), - toChainId('solana'), - tokenAccount.toBuffer() + // assert theat amount is what we expect + expect(endpointMessage.managerPayload.payload.normalizedAmount).to.deep.equal(new NormalizedAmount(BigInt(10000), 8)) + // get from balance + const balance = await program.provider.connection.getTokenAccountBalance(tokenAccount) + expect(balance.value.amount).to.equal('9900000') + + // grab logs + // await program.provider.connection.confirmTransaction(redeemTx, 'confirmed'); + // const tx = await anchor.getProvider().connection.getParsedTransaction(redeemTx, { + // commitment: "confirmed", + // }); + // console.log(tx); + + // const log = tx.meta.logMessages[1]; + // const message = log.substring(log.indexOf(':') + 1); + // console.log(message); + + // TODO: assert other stuff in the message + // console.log(managerMessage); + }); + + it('Can receive tokens', async () => { + const emitter = + new MockEmitter( + '00000000000000000000000000000000000000000000000000000000BEEFFACE', + toChainId('ethereum'), + Number(0) // sequence ) - ) - } - const serialized = WormholeEndpointMessage.serialize(sendingEndpointMessage, a => ManagerMessage.serialize(a, NativeTokenTransfer.serialize)) + const guardians = new MockGuardians(0, [GUARDIAN_KEY]) + + const sendingEndpointMessage: EndpointMessage = { + managerPayload: new ManagerMessage( + toChainId('ethereum'), + BigInt(0), + Buffer.from('BEEF'.padStart(64, '0'), 'hex'), + Buffer.from('FACE'.padStart(64, '0'), 'hex'), + new NativeTokenTransfer( + Buffer.from('FAFA'.padStart(64, '0'), 'hex'), + new NormalizedAmount(BigInt(10000), 8), + toChainId('solana'), + tokenAccount.toBuffer() + ) + ) + } - const published = emitter.publishMessage( - 0, // nonce - serialized, - 0 // consistency level - ) + const serialized = WormholeEndpointMessage.serialize(sendingEndpointMessage, a => ManagerMessage.serialize(a, NativeTokenTransfer.serialize)) + + const published = emitter.publishMessage( + 0, // nonce + serialized, + 0 // consistency level + ) - const vaaBuf = guardians.addSignatures(published, [0]) + const vaaBuf = guardians.addSignatures(published, [0]) - await postVaa(program.provider.connection, payer, vaaBuf, ntt.wormholeId) + await postVaa(program.provider.connection, payer, vaaBuf, ntt.wormholeId) - const released = await ntt.redeem({ - payer, - vaa: vaaBuf, - }) + const released = await ntt.redeem({ + payer, + vaa: vaaBuf, + }) - expect(released).to.equal(true) + expect(released).to.equal(true) - // grab logs - // await program.provider.connection.confirmTransaction(redeemTx, 'confirmed'); - // const tx = await anchor.getProvider().connection.getParsedTransaction(redeemTx, { - // commitment: "confirmed", - // }); - // console.log(tx); + }); + }); - // const log = tx.meta.logMessages[1]; - // const message = log.substring(log.indexOf(':') + 1); - // console.log(message); + // describe('Burning', () => { + // beforeEach(async () => { + // await ntt.initialize({ + // payer, + // owner, + // chain: 'solana', + // mint, + // outboundLimit: new BN(1000000), + // mode: 'burning' + // }) + // }); + // }); - // TODO: assert other stuff in the message - // console.log(managerMessage); - }) }) diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index bac605c25..333ba7967 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -84,8 +84,8 @@ export class NTT { ]) } - custodyAuthorityAddress(): PublicKey { - return this.derive_pda([Buffer.from('custody_authority')]) + tokenAuthorityAddress(): PublicKey { + return this.derive_pda([Buffer.from('token_authority')]) } emitterAccountAddress(): PublicKey { @@ -96,10 +96,6 @@ export class NTT { return this.derive_pda([Buffer.from('message'), outboxItem.toBuffer()]) } - mintAuthorityAddress(): PublicKey { - return this.derive_pda([Buffer.from('token_minter')]) - } - siblingAccountAddress(chain: ChainName | ChainId): PublicKey { const chainId = coalesceChainId(chain) return this.derive_pda([Buffer.from('sibling'), new BN(chainId).toBuffer('be', 2)]) @@ -135,8 +131,7 @@ export class NTT { seq: this.sequenceTrackerAccountAddress(), rateLimit: this.outboxRateLimitAccountAddress(), tokenProgram, - custodyAuthority: this.custodyAuthorityAddress(), - mintAuthority: this.mintAuthorityAddress(), + tokenAuthority: this.tokenAuthorityAddress(), custody: await this.custodyAccountAddress(args.mint) }) .signers([args.payer, args.owner]) @@ -293,7 +288,7 @@ export class NTT { outboxRateLimit: this.outboxRateLimitAccountAddress(), }, inboxRateLimit: this.inboxRateLimitAccountAddress(args.recipientChain), - custodyAuthority: this.custodyAuthorityAddress(), + tokenAuthority: this.tokenAuthorityAddress(), custody: await this.custodyAccountAddress(config) }) .instruction() @@ -378,9 +373,9 @@ export class NTT { config: { config: this.configAccountAddress() }, inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), recipient: recipientAddress, - mint: await this.mintAccountAddress(config) + mint: await this.mintAccountAddress(config), + tokenAuthority: this.tokenAuthorityAddress(), }, - mintAuthority: this.mintAuthorityAddress() }) .instruction() } @@ -435,9 +430,9 @@ export class NTT { config: { config: this.configAccountAddress() }, inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), recipient: recipientAddress, - mint: await this.mintAccountAddress(config) + mint: await this.mintAccountAddress(config), + tokenAuthority: this.tokenAuthorityAddress(), }, - custodyAuthority: this.custodyAuthorityAddress(), custody: await this.custodyAccountAddress(config) }) .instruction() @@ -640,9 +635,9 @@ export class NTT { */ async custodyAccountAddress(configOrMint: Config | PublicKey): Promise { if (configOrMint instanceof PublicKey) { - return associatedAddress({ mint: configOrMint, owner: this.custodyAuthorityAddress() }) + return associatedAddress({ mint: configOrMint, owner: this.tokenAuthorityAddress() }) } else { - return associatedAddress({ mint: await this.mintAccountAddress(configOrMint), owner: this.custodyAuthorityAddress() }) + return associatedAddress({ mint: await this.mintAccountAddress(configOrMint), owner: this.tokenAuthorityAddress() }) } } } From 996b62335e9ae765d51e707e462a4fb79f00aa58 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 14 Feb 2024 03:50:18 +0400 Subject: [PATCH 36/90] solana: solana-program-test this makes it possible to test both modes in the same context (and much faster) --- solana/Anchor.toml | 3 + solana/Cargo.lock | 3894 +++++++++++++++-- .../example-native-token-transfers/Cargo.toml | 7 + .../src/instructions/initialize.rs | 2 +- .../src/queue/outbox.rs | 2 +- .../tests/common/account_utils.rs | 93 + .../tests/common/mod.rs | 1 + .../tests/lib.rs | 364 ++ .../tests/sdk/accounts.rs | 86 + .../tests/sdk/instructions/admin.rs | 32 + .../tests/sdk/instructions/initialize.rs | 37 + .../tests/sdk/instructions/mod.rs | 3 + .../tests/sdk/instructions/transfer.rs | 64 + .../tests/sdk/mod.rs | 2 + solana/ts/sdk/index.ts | 4 - 15 files changed, 4324 insertions(+), 270 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/tests/common/account_utils.rs create mode 100644 solana/programs/example-native-token-transfers/tests/common/mod.rs create mode 100644 solana/programs/example-native-token-transfers/tests/lib.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/accounts.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/mod.rs diff --git a/solana/Anchor.toml b/solana/Anchor.toml index 59a10d0cd..c41a96026 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -17,6 +17,9 @@ test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" [test.validator] url = "https://api.mainnet-beta.solana.com" +### At 160 ticks/s, 64 ticks per slot implies that leader rotation and voting will happen +### every 400 ms. A fast voting cadence ensures faster finality and convergence +ticks_per_slot = 16 ### Wormhole Core Bridge (Mainnet) -- Program [[test.genesis]] diff --git a/solana/Cargo.lock b/solana/Cargo.lock index cfbe46953..2fe115db1 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -2,6 +2,31 @@ # 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" +dependencies = [ + "lazy_static", + "regex", +] + +[[package]] +name = "addr2line" +version = "0.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +dependencies = [ + "gimli", +] + +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + [[package]] name = "aead" version = "0.4.3" @@ -71,6 +96,27 @@ dependencies = [ "memchr", ] +[[package]] +name = "aliasable" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" + +[[package]] +name = "alloc-no-stdlib" +version = "2.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cc7bb162ec39d46ab1ca8c77bf72e890535becd1751bb45f64c597edb4c8c6b3" + +[[package]] +name = "alloc-stdlib" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94fb8275041c72129eb51b7d0322c29b8387a0386127718b096429201a5d6ece" +dependencies = [ + "alloc-no-stdlib", +] + [[package]] name = "anchor-attribute-access-control" version = "0.29.0" @@ -223,7 +269,7 @@ checksum = "d9101b84702fed2ea57bd22992f75065da5648017135b844283a2f6d74f27825" dependencies = [ "anyhow", "bs58 0.5.0", - "heck", + "heck 0.3.3", "proc-macro2", "quote", "serde", @@ -233,6 +279,30 @@ dependencies = [ "thiserror", ] +[[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 = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" version = "1.0.79" @@ -280,7 +350,7 @@ dependencies = [ "derivative", "digest 0.10.7", "itertools", - "num-bigint", + "num-bigint 0.4.4", "num-traits", "paste", "rustc_version", @@ -303,7 +373,7 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" dependencies = [ - "num-bigint", + "num-bigint 0.4.4", "num-traits", "proc-macro2", "quote", @@ -332,7 +402,7 @@ dependencies = [ "ark-serialize-derive", "ark-std", "digest 0.10.7", - "num-bigint", + "num-bigint 0.4.4", ] [[package]] @@ -356,12 +426,6 @@ dependencies = [ "rand 0.8.5", ] -[[package]] -name = "array-bytes" -version = "1.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ad284aeb45c13f2fb4f084de4a420ebf447423bdf9386c0540ce33cb3ef4b8c" - [[package]] name = "arrayref" version = "0.3.7" @@ -374,19 +438,109 @@ version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "asn1-rs" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" +dependencies = [ + "asn1-rs-derive", + "asn1-rs-impl", + "displaydoc", + "nom", + "num-traits", + "rusticata-macros", + "thiserror", + "time", +] + +[[package]] +name = "asn1-rs-derive" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "synstructure", +] + +[[package]] +name = "asn1-rs-impl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "assert_matches" version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9" +[[package]] +name = "async-channel" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" +dependencies = [ + "concurrent-queue", + "event-listener", + "futures-core", +] + +[[package]] +name = "async-compression" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +dependencies = [ + "brotli", + "flate2", + "futures-core", + "memchr", + "pin-project-lite", + "tokio", +] + +[[package]] +name = "async-mutex" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +dependencies = [ + "event-listener", +] + +[[package]] +name = "async-trait" +version = "0.1.77" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi", + "hermit-abi 0.1.19", "libc", "winapi", ] @@ -397,6 +551,21 @@ 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", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] + [[package]] name = "base64" version = "0.12.3" @@ -415,6 +584,12 @@ 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 = "bincode" version = "1.3.3" @@ -430,6 +605,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +dependencies = [ + "serde", +] + [[package]] name = "bitmaps" version = "2.1.0" @@ -568,6 +752,27 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "brotli" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", + "brotli-decompressor", +] + +[[package]] +name = "brotli-decompressor" +version = "2.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +dependencies = [ + "alloc-no-stdlib", + "alloc-stdlib", +] + [[package]] name = "bs58" version = "0.4.0" @@ -625,6 +830,43 @@ 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 = "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 = "caps" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +dependencies = [ + "libc", + "thiserror", +] + [[package]] name = "cc" version = "1.0.83" @@ -647,7 +889,22 @@ version = "0.4.33" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9f13690e35a5e4ace198e7beea2895d29f3a9cc55015fcebe6336bd2010af9eb" dependencies = [ + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", + "serde", + "wasm-bindgen", + "windows-targets 0.52.0", +] + +[[package]] +name = "chrono-humanize" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" +dependencies = [ + "chrono", ] [[package]] @@ -659,6 +916,81 @@ dependencies = [ "generic-array", ] +[[package]] +name = "clap" +version = "2.34.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" +dependencies = [ + "ansi_term", + "atty", + "bitflags 1.3.2", + "strsim 0.8.0", + "textwrap 0.11.0", + "unicode-width", + "vec_map", +] + +[[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_lex", + "indexmap 1.9.3", + "once_cell", + "strsim 0.10.0", + "termcolor", + "textwrap 0.16.0", +] + +[[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 = "combine" +version = "3.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" +dependencies = [ + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", +] + +[[package]] +name = "concurrent-queue" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "console" +version = "0.15.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +dependencies = [ + "encode_unicode", + "lazy_static", + "libc", + "unicode-width", + "windows-sys 0.52.0", +] + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -679,12 +1011,34 @@ dependencies = [ "web-sys", ] +[[package]] +name = "const-oid" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" + [[package]] name = "constant_time_eq" version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +[[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" @@ -694,6 +1048,24 @@ dependencies = [ "libc", ] +[[package]] +name = "crc32fast" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "crossbeam-deque" version = "0.8.5" @@ -788,7 +1160,7 @@ dependencies = [ "ident_case", "proc-macro2", "quote", - "strsim", + "strsim 0.10.0", "syn 2.0.48", ] @@ -804,29 +1176,90 @@ dependencies = [ ] [[package]] -name = "derivation-path" -version = "0.2.0" +name = "dashmap" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" +checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +dependencies = [ + "cfg-if", + "num_cpus", + "rayon", +] [[package]] -name = "derivative" -version = "2.2.0" +name = "data-encoding" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" [[package]] -name = "digest" -version = "0.9.0" +name = "der" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" dependencies = [ - "generic-array", + "const-oid", +] + +[[package]] +name = "der-parser" +version = "8.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" +dependencies = [ + "asn1-rs", + "displaydoc", + "nom", + "num-bigint 0.4.4", + "num-traits", + "rusticata-macros", +] + +[[package]] +name = "deranged" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "dialoguer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" +dependencies = [ + "console", + "shell-words", + "tempfile", + "zeroize", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", ] [[package]] @@ -840,6 +1273,55 @@ dependencies = [ "subtle", ] +[[package]] +name = "dir-diff" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" +dependencies = [ + "walkdir", +] + +[[package]] +name = "displaydoc" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "dlopen2" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" +dependencies = [ + "dlopen2_derive", + "libc", + "once_cell", + "winapi", +] + +[[package]] +name = "dlopen2_derive" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + [[package]] name = "ed25519" version = "1.5.3" @@ -875,12 +1357,72 @@ dependencies = [ "sha2 0.10.8", ] +[[package]] +name = "educe" +version = "0.4.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "either" version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +[[package]] +name = "encode_unicode" +version = "0.3.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" + +[[package]] +name = "encoding_rs" +version = "0.8.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "enum-ordinalize" +version = "3.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" +dependencies = [ + "num-bigint 0.4.4", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.48", +] + [[package]] name = "env_logger" version = "0.9.3" @@ -900,6 +1442,22 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + +[[package]] +name = "event-listener" +version = "2.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" + [[package]] name = "example-native-token-transfers" version = "0.1.0" @@ -907,23 +1465,165 @@ dependencies = [ "ahash 0.8.6", "anchor-lang", "anchor-spl", + "base64 0.21.7", "hex", + "serde", + "serde_json", + "solana-program-test", + "solana-sdk", + "spl-associated-token-account", + "spl-token", "wormhole-anchor-sdk", "wormhole-io", ] +[[package]] +name = "fastrand" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" + [[package]] name = "feature-probe" version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" +[[package]] +name = "filetime" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "windows-sys 0.52.0", +] + +[[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 = "form_urlencoded" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "fs-err" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +dependencies = [ + "autocfg", +] + +[[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-executor", + "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-macro" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[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-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + [[package]] name = "generic-array" version = "0.14.7" @@ -935,6 +1635,16 @@ dependencies = [ "version_check", ] +[[package]] +name = "gethostname" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1ebd34e35c46e00bb73e81363248d627782724609fe1b6396f553f68fe3862e" +dependencies = [ + "libc", + "winapi", +] + [[package]] name = "getrandom" version = "0.1.16" @@ -961,6 +1671,51 @@ dependencies = [ "wasm-bindgen", ] +[[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", +] + +[[package]] +name = "h2" +version = "0.3.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +dependencies = [ + "bytes", + "fnv", + "futures-core", + "futures-sink", + "futures-util", + "http", + "indexmap 2.1.0", + "slab", + "tokio", + "tokio-util 0.7.10", + "tracing", +] + +[[package]] +name = "hash32" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +dependencies = [ + "byteorder", +] + [[package]] name = "hashbrown" version = "0.11.2" @@ -970,6 +1725,15 @@ dependencies = [ "ahash 0.7.7", ] +[[package]] +name = "hashbrown" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +dependencies = [ + "ahash 0.7.7", +] + [[package]] name = "hashbrown" version = "0.13.2" @@ -994,6 +1758,12 @@ dependencies = [ "unicode-segmentation", ] +[[package]] +name = "heck" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1003,12 +1773,24 @@ dependencies = [ "libc", ] +[[package]] +name = "hermit-abi" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0c62115964e08cb8039170eb33c1d0e2388a256930279edca206fff675f82c3" + [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" +[[package]] +name = "histogram" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" + [[package]] name = "hmac" version = "0.8.1" @@ -1040,17 +1822,122 @@ dependencies = [ ] [[package]] -name = "humantime" -version = "2.1.0" +name = "http" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +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-rustls" +version = "0.24.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +dependencies = [ + "futures-util", + "http", + "hyper", + "rustls", + "tokio", + "tokio-rustls", +] + +[[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 = "im" version = "15.1.0" @@ -1067,6 +1954,22 @@ dependencies = [ "version_check", ] +[[package]] +name = "index_list" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70891286cb8e844fdfcf1178b47569699f9e20b5ecc4b45a6240a64771444638" + +[[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", +] + [[package]] name = "indexmap" version = "2.1.0" @@ -1077,6 +1980,34 @@ dependencies = [ "hashbrown 0.14.3", ] +[[package]] +name = "indicatif" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" +dependencies = [ + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", +] + +[[package]] +name = "instant" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "ipnet" +version = "2.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" + [[package]] name = "itertools" version = "0.10.5" @@ -1110,6 +2041,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "jsonrpc-core" +version = "18.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "14f7f76aef2d054868398427f6c54943cf3d1caa9a7ec7d0c38d69df97a965eb" +dependencies = [ + "futures", + "futures-executor", + "futures-util", + "log", + "serde", + "serde_derive", + "serde_json", +] + [[package]] name = "keccak" version = "0.1.5" @@ -1179,6 +2125,24 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint 0.4.4", + "thiserror", +] + +[[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" @@ -1195,6 +2159,35 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +[[package]] +name = "lru" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e999beba7b6e8345721bd280141ed958096a2e4abdf74f67ff4ce49b4b54e47a" +dependencies = [ + "hashbrown 0.12.3", +] + +[[package]] +name = "lz4" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +dependencies = [ + "libc", + "lz4-sys", +] + +[[package]] +name = "lz4-sys" +version = "1.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +dependencies = [ + "cc", + "libc", +] + [[package]] name = "memchr" version = "2.7.1" @@ -1210,6 +2203,15 @@ dependencies = [ "libc", ] +[[package]] +name = "memoffset" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + [[package]] name = "memoffset" version = "0.9.0" @@ -1231,6 +2233,107 @@ dependencies = [ "zeroize", ] +[[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.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +dependencies = [ + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", +] + +[[package]] +name = "modular-bitfield" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a53d79ba8304ac1c4f9eb3b9d281f21f7be9d4626f72ce7df4ad8fbde4f38a74" +dependencies = [ + "modular-bitfield-impl", + "static_assertions", +] + +[[package]] +name = "modular-bitfield-impl" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "nix" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +dependencies = [ + "bitflags 1.3.2", + "cfg-if", + "libc", + "memoffset 0.7.1", + "pin-utils", +] + +[[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 = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + [[package]] name = "num-bigint" version = "0.4.4" @@ -1242,6 +2345,22 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.3.3" @@ -1274,6 +2393,29 @@ 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.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + [[package]] name = "num-traits" version = "0.2.17" @@ -1283,6 +2425,16 @@ 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.5", + "libc", +] + [[package]] name = "num_enum" version = "0.6.1" @@ -1325,6 +2477,30 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "number_prefix" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" + +[[package]] +name = "object" +version = "0.32.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +dependencies = [ + "memchr", +] + +[[package]] +name = "oid-registry" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +dependencies = [ + "asn1-rs", +] + [[package]] name = "once_cell" version = "1.19.0" @@ -1338,30 +2514,84 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" [[package]] -name = "parking_lot" -version = "0.12.1" +name = "openssl-probe" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" -dependencies = [ - "lock_api", - "parking_lot_core", -] +checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" [[package]] -name = "parking_lot_core" -version = "0.9.9" +name = "opentelemetry" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "6105e89802af13fdf48c49d7646d3b533a70e536d818aae7e78ba0433d01acb8" dependencies = [ - "cfg-if", - "libc", - "redox_syscall", - "smallvec", - "windows-targets", + "async-trait", + "crossbeam-channel", + "futures-channel", + "futures-executor", + "futures-util", + "js-sys", + "lazy_static", + "percent-encoding", + "pin-project", + "rand 0.8.5", + "thiserror", ] [[package]] -name = "paste" +name = "os_str_bytes" +version = "6.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" + +[[package]] +name = "ouroboros" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" +dependencies = [ + "aliasable", + "ouroboros_macro", +] + +[[package]] +name = "ouroboros_macro" +version = "0.15.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" +dependencies = [ + "Inflector", + "proc-macro-error", + "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", + "libc", + "redox_syscall", + "smallvec", + "windows-targets 0.48.5", +] + +[[package]] +name = "paste" version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" @@ -1384,12 +2614,85 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "pem" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" +dependencies = [ + "base64 0.13.1", +] + [[package]] name = "percent-encoding" version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[package]] +name = "pin-project" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0302c4a0442c456bd56f841aee5c3bfd17967563f6fadc9ceb9f9c23cf3807e0" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "266c042b60c9c76b8d53061e52b2e0d1116abc57cefc8c5cd671619a56ac3690" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[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 = "pkcs8" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +dependencies = [ + "der", + "spki", + "zeroize", +] + +[[package]] +name = "pkg-config" +version = "0.3.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" + +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "polyval" version = "0.5.3" @@ -1402,6 +2705,18 @@ dependencies = [ "universal-hash", ] +[[package]] +name = "portable-atomic" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" + +[[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" @@ -1427,6 +2742,30 @@ dependencies = [ "toml_edit", ] +[[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.78" @@ -1445,6 +2784,65 @@ dependencies = [ "percent-encoding", ] +[[package]] +name = "qualifier_attr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "quinn" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +dependencies = [ + "bytes", + "pin-project-lite", + "quinn-proto", + "quinn-udp", + "rustc-hash", + "rustls", + "thiserror", + "tokio", + "tracing", +] + +[[package]] +name = "quinn-proto" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +dependencies = [ + "bytes", + "rand 0.8.5", + "ring 0.16.20", + "rustc-hash", + "rustls", + "rustls-native-certs", + "slab", + "thiserror", + "tinyvec", + "tracing", +] + +[[package]] +name = "quinn-udp" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +dependencies = [ + "bytes", + "libc", + "socket2", + "tracing", + "windows-sys 0.48.0", +] + [[package]] name = "quote" version = "1.0.35" @@ -1473,6 +2871,7 @@ 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", ] @@ -1553,13 +2952,25 @@ dependencies = [ "crossbeam-utils", ] +[[package]] +name = "rcgen" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +dependencies = [ + "pem", + "ring 0.16.20", + "time", + "yasna", +] + [[package]] name = "redox_syscall" version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -1592,140 +3003,398 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" [[package]] -name = "rustc-hash" -version = "1.1.0" +name = "reqwest" +version = "0.11.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "c6920094eb85afde5e4a138be3f2de8bbdf28000f0029e72c45025a56b042251" +dependencies = [ + "async-compression", + "base64 0.21.7", + "bytes", + "encoding_rs", + "futures-core", + "futures-util", + "h2", + "http", + "http-body", + "hyper", + "hyper-rustls", + "ipnet", + "js-sys", + "log", + "mime", + "once_cell", + "percent-encoding", + "pin-project-lite", + "rustls", + "rustls-pemfile", + "serde", + "serde_json", + "serde_urlencoded", + "sync_wrapper", + "system-configuration", + "tokio", + "tokio-rustls", + "tokio-util 0.7.10", + "tower-service", + "url", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "webpki-roots 0.25.4", + "winreg", +] [[package]] -name = "rustc_version" -version = "0.4.0" +name = "ring" +version = "0.16.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" dependencies = [ - "semver", + "cc", + "libc", + "once_cell", + "spin 0.5.2", + "untrusted 0.7.1", + "web-sys", + "winapi", ] [[package]] -name = "rustversion" -version = "1.0.14" +name = "ring" +version = "0.17.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +dependencies = [ + "cc", + "getrandom 0.2.12", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.48.0", +] [[package]] -name = "ryu" -version = "1.0.16" +name = "rpassword" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" +dependencies = [ + "libc", + "rtoolbox", + "windows-sys 0.48.0", +] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "rtoolbox" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] [[package]] -name = "semver" -version = "1.0.21" +name = "rustc-demangle" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" [[package]] -name = "serde" -version = "1.0.195" +name = "rustc-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63261df402c67811e9ac6def069e4786148c4563f4b50fd4bf30aa370d626b02" -dependencies = [ - "serde_derive", -] +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] -name = "serde_bytes" -version = "0.11.14" +name = "rustc_version" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" dependencies = [ - "serde", + "semver", ] [[package]] -name = "serde_derive" -version = "1.0.195" +name = "rusticata-macros" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46fe8f8603d81ba86327b23a2e9cdf49e1255fb94a4c5f297f6ee0547178ea2c" +checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", + "nom", ] [[package]] -name = "serde_json" -version = "1.0.111" +name = "rustix" +version = "0.38.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" dependencies = [ - "itoa", - "ryu", - "serde", + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", ] [[package]] -name = "serde_with" -version = "2.3.3" +name = "rustls" +version = "0.21.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" dependencies = [ - "serde", - "serde_with_macros", + "log", + "ring 0.17.7", + "rustls-webpki", + "sct", ] [[package]] -name = "serde_with_macros" -version = "2.3.3" +name = "rustls-native-certs" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ - "darling", - "proc-macro2", - "quote", - "syn 2.0.48", + "openssl-probe", + "rustls-pemfile", + "schannel", + "security-framework", ] [[package]] -name = "sha2" -version = "0.9.9" +name = "rustls-pemfile" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "block-buffer 0.9.0", - "cfg-if", - "cpufeatures", - "digest 0.9.0", - "opaque-debug", + "base64 0.21.7", ] [[package]] -name = "sha2" -version = "0.10.8" +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "ring 0.17.7", + "untrusted 0.9.0", ] [[package]] -name = "sha3" -version = "0.9.1" +name = "rustversion" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" -dependencies = [ - "block-buffer 0.9.0", - "digest 0.9.0", - "keccak", - "opaque-debug", +checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "schannel" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +dependencies = [ + "windows-sys 0.52.0", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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.48", +] + +[[package]] +name = "sct" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" +dependencies = [ + "ring 0.17.7", + "untrusted 0.9.0", +] + +[[package]] +name = "security-framework" +version = "2.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +dependencies = [ + "bitflags 1.3.2", + "core-foundation", + "core-foundation-sys", + "libc", + "security-framework-sys", +] + +[[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.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" + +[[package]] +name = "serde" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.196" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "serde_json" +version = "1.0.113" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69801b70b1c3dac963ecb03a364ba0ceda9cf60c71cfe475e99864759c8b8a79" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_urlencoded" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3491c14715ca2294c4d6a88f15e84739788c1d030eed8c110436aafdaa2f3fd" +dependencies = [ + "form_urlencoded", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "serde_with" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe" +dependencies = [ + "serde", + "serde_with_macros", +] + +[[package]] +name = "serde_with_macros" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "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", + "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", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809" +dependencies = [ + "block-buffer 0.9.0", + "digest 0.9.0", + "keccak", + "opaque-debug", ] [[package]] @@ -1739,148 +3408,868 @@ dependencies = [ ] [[package]] -name = "signature" -version = "1.6.4" +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shell-words" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" + +[[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 = "1.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" + +[[package]] +name = "siphasher" +version = "0.3.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" + +[[package]] +name = "sized-chunks" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +dependencies = [ + "bitmaps", + "typenum", +] + +[[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 = "socket2" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +dependencies = [ + "libc", + "windows-sys 0.48.0", +] + +[[package]] +name = "solana-account-decoder" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48541b782c0fbb15ac202f2487353c3649fbf868afacae6ca1c9fe0f7df0b4a" +dependencies = [ + "Inflector", + "base64 0.21.7", + "bincode", + "bs58 0.4.0", + "bv", + "lazy_static", + "serde", + "serde_derive", + "serde_json", + "solana-config-program", + "solana-sdk", + "spl-token", + "spl-token-2022", + "spl-token-metadata-interface", + "thiserror", + "zstd", +] + +[[package]] +name = "solana-accounts-db" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a5a48e3dfffb0699a7b2c6a0714f4c6dd974a8fd744b4e4ac67238ed3fc3ba0" +dependencies = [ + "arrayref", + "bincode", + "blake3", + "bv", + "bytemuck", + "byteorder", + "bzip2", + "crossbeam-channel", + "dashmap", + "flate2", + "fnv", + "fs-err", + "im", + "index_list", + "itertools", + "lazy_static", + "log", + "lz4", + "memmap2", + "modular-bitfield", + "num-derive 0.3.3", + "num-traits", + "num_cpus", + "num_enum 0.6.1", + "ouroboros", + "percentage", + "qualifier_attr", + "rand 0.8.5", + "rayon", + "regex", + "rustc_version", + "serde", + "serde_derive", + "solana-bucket-map", + "solana-config-program", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-measure", + "solana-metrics", + "solana-program-runtime", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", + "static_assertions", + "strum", + "strum_macros", + "tar", + "tempfile", + "thiserror", +] + +[[package]] +name = "solana-address-lookup-table-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918eaf2c89e92960ab5fa7c21921fb3921ace134770c371b5d25b13569e2993f" +dependencies = [ + "bincode", + "bytemuck", + "log", + "num-derive 0.3.3", + "num-traits", + "rustc_version", + "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-program", + "solana-program-runtime", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-banks-client" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c565499d7fdb92ac2dc6ad2de23c9b8e9cedd54630953e8fcdd98a03a898b8e6" +dependencies = [ + "borsh 0.10.3", + "futures", + "solana-banks-interface", + "solana-program", + "solana-sdk", + "tarpc", + "thiserror", + "tokio", + "tokio-serde", +] + +[[package]] +name = "solana-banks-interface" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b88919cc1dc06b78da78d2f82b0afd094926981d7538ed68fe204201c5f60d72" +dependencies = [ + "serde", + "solana-sdk", + "tarpc", +] + +[[package]] +name = "solana-banks-server" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fcf6f5a00e3e30b33a6f72c4e5b02a0933dfdf294efabf47dfed4d6a1640928" +dependencies = [ + "bincode", + "crossbeam-channel", + "futures", + "solana-accounts-db", + "solana-banks-interface", + "solana-client", + "solana-runtime", + "solana-sdk", + "solana-send-transaction-service", + "tarpc", + "tokio", + "tokio-serde", +] + +[[package]] +name = "solana-bpf-loader-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b1f0c6b35b805f7bf31d08b3c609fb37eb13031d675e2e4db227873e1050c27" +dependencies = [ + "bincode", + "byteorder", + "libsecp256k1", + "log", + "scopeguard", + "solana-measure", + "solana-program-runtime", + "solana-sdk", + "solana-zk-token-sdk", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-bucket-map" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f4038e5bf34bcca677fd749512fbca8db2db21ca629b6b1095e502d11e4265" +dependencies = [ + "bv", + "bytemuck", + "log", + "memmap2", + "modular-bitfield", + "num_enum 0.6.1", + "rand 0.8.5", + "solana-measure", + "solana-sdk", + "tempfile", +] + +[[package]] +name = "solana-clap-utils" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3a78952f057a7d4f87b3a6a5f4a8705cefbb67bbc00ecffc2c75b168a54c931" +dependencies = [ + "chrono", + "clap 2.34.0", + "rpassword", + "solana-remote-wallet", + "solana-sdk", + "thiserror", + "tiny-bip39", + "uriparse", + "url", +] + +[[package]] +name = "solana-client" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e85b1d68bce244750bd02c4d71ed0df415c9b8d91a4b0f1e7ce6b97748db46c" +dependencies = [ + "async-trait", + "bincode", + "dashmap", + "futures", + "futures-util", + "indexmap 2.1.0", + "indicatif", + "log", + "quinn", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-pubsub-client", + "solana-quic-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", + "solana-sdk", + "solana-streamer", + "solana-thin-client", + "solana-tpu-client", + "solana-udp-client", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-compute-budget-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1cc2978cf6a5335576b2c12ce4bb3cf6c95178a9e2f1f110a39c17c7ca79ba94" +dependencies = [ + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-config-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c66c9c5bbc148affd42127061af9c0e7e5901b5e5142e951912f165272203c1" +dependencies = [ + "bincode", + "chrono", + "serde", + "serde_derive", + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-connection-cache" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4180686b6384013f062242ee9f18ea6ea68268e9b35fa9aa0206c2a622d1773f" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap 2.1.0", + "log", + "rand 0.8.5", + "rayon", + "rcgen", + "solana-measure", + "solana-metrics", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-cost-model" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ad4fb3639f3d1751fad91bfbfc07d99427633705328d2e123fe578ca9dedf67" +dependencies = [ + "lazy_static", + "log", + "rustc_version", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-compute-budget-program", + "solana-config-program", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-loader-v4-program", + "solana-metrics", + "solana-program-runtime", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-vote-program", +] + +[[package]] +name = "solana-frozen-abi" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "174a53486f9e0774680c2b6a53568a15c11ccc5cef1263a7e7d42958bfd61792" +dependencies = [ + "ahash 0.8.6", + "blake3", + "block-buffer 0.10.4", + "bs58 0.4.0", + "bv", + "byteorder", + "cc", + "either", + "generic-array", + "im", + "lazy_static", + "log", + "memmap2", + "rustc_version", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "solana-frozen-abi-macro", + "subtle", + "thiserror", +] + +[[package]] +name = "solana-frozen-abi-macro" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e69b9bc56d9f92bd194569091d655be239a51a934df1db247e0c8bd2a9352909" +dependencies = [ + "proc-macro2", + "quote", + "rustc_version", + "syn 2.0.48", +] + +[[package]] +name = "solana-loader-v4-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21a62b38cd73c136635f9e8e56185b56d006a508bab67d4a06764efd1f3b0ef7" +dependencies = [ + "log", + "solana-measure", + "solana-program-runtime", + "solana-sdk", + "solana_rbpf", +] + +[[package]] +name = "solana-logger" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccb457626944fd2f192285c8281e887081dc346920c181aaf165426dbf081859" +dependencies = [ + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "solana-measure" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b2a8bb3ec59a415b1c30827001c38af358a0c244e00a3d5280ca0b0ed264036" +dependencies = [ + "log", + "solana-sdk", +] + +[[package]] +name = "solana-metrics" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c89e3237a73f781e0156fe419831c554f6807eb4f4bffea42535be9627d6fc1" +dependencies = [ + "crossbeam-channel", + "gethostname", + "lazy_static", + "log", + "reqwest", + "solana-sdk", + "thiserror", +] + +[[package]] +name = "solana-net-utils" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec445e2d9dbfab7360bc0d846a676e318c13eb4d1e0359ef199187d07795d02" +dependencies = [ + "bincode", + "clap 3.2.25", + "crossbeam-channel", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-logger", + "solana-sdk", + "solana-version", + "tokio", + "url", +] + +[[package]] +name = "solana-perf" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7b58cc4a2f4f450361bc8c1a24a94383c659e6212a74e6080a410f7d87e05a6" +dependencies = [ + "ahash 0.8.6", + "bincode", + "bv", + "caps", + "curve25519-dalek", + "dlopen2", + "fnv", + "lazy_static", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "rustc_version", + "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-metrics", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-vote-program", +] + +[[package]] +name = "solana-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c183d16916dd70ce2b59a4b39088f5094649a592e475fb9ebfc3cfe78b3a192c" +dependencies = [ + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.21.7", + "bincode", + "bitflags 2.4.2", + "blake3", + "borsh 0.10.3", + "borsh 0.9.3", + "bs58 0.4.0", + "bv", + "bytemuck", + "cc", + "console_error_panic_hook", + "console_log", + "curve25519-dalek", + "getrandom 0.2.12", + "itertools", + "js-sys", + "lazy_static", + "libc", + "libsecp256k1", + "light-poseidon", + "log", + "memoffset 0.9.0", + "num-bigint 0.4.4", + "num-derive 0.3.3", + "num-traits", + "parking_lot", + "rand 0.8.5", + "rustc_version", + "rustversion", + "serde", + "serde_bytes", + "serde_derive", + "serde_json", + "sha2 0.10.8", + "sha3 0.10.8", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk-macro", + "thiserror", + "tiny-bip39", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "solana-program-runtime" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fca7d79b03e54e108069f32cf553c863838b647be7f7135644f8a1d2bdcd3a1" +dependencies = [ + "base64 0.21.7", + "bincode", + "eager", + "enum-iterator", + "itertools", + "libc", + "log", + "num-derive 0.3.3", + "num-traits", + "percentage", + "rand 0.8.5", + "rustc_version", + "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-measure", + "solana-metrics", + "solana-sdk", + "solana_rbpf", + "thiserror", +] + +[[package]] +name = "solana-program-test" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5c27258c216a68f7fe927da2392d23cf1d1a329fccd888f3287cbf922614772" +dependencies = [ + "assert_matches", + "async-trait", + "base64 0.21.7", + "bincode", + "chrono-humanize", + "crossbeam-channel", + "log", + "serde", + "solana-accounts-db", + "solana-banks-client", + "solana-banks-interface", + "solana-banks-server", + "solana-bpf-loader-program", + "solana-logger", + "solana-program-runtime", + "solana-runtime", + "solana-sdk", + "solana-vote-program", + "solana_rbpf", + "test-case", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-pubsub-client" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d90c6e27f0d1e627728f137db688c45accb1b7ae839021b978d1dcceff40d7a3" +dependencies = [ + "crossbeam-channel", + "futures-util", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +checksum = "f340646d1bdd7b7c8e0c71f1f817a4eaeba35c06f025944c52df8f82bb565c79" +dependencies = [ + "async-mutex", + "async-trait", + "futures", + "itertools", + "lazy_static", + "log", + "quinn", + "quinn-proto", + "rcgen", + "rustls", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-net-utils", + "solana-rpc-client-api", + "solana-sdk", + "solana-streamer", + "thiserror", + "tokio", +] [[package]] -name = "sized-chunks" -version = "0.6.5" +name = "solana-rayon-threadlimit" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" +checksum = "7effa9e68a7ab9883f7fb4a91c083970223e8e8e355979eb605279608fafa6b7" dependencies = [ - "bitmaps", - "typenum", + "lazy_static", + "num_cpus", ] [[package]] -name = "smallvec" -version = "1.13.1" +name = "solana-remote-wallet" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "e59fee3edad929473b7178f84ae58dbb3feb004a26873c8ab557b3aecfaa6d87" +dependencies = [ + "console", + "dialoguer", + "log", + "num-derive 0.3.3", + "num-traits", + "parking_lot", + "qstring", + "semver", + "solana-sdk", + "thiserror", + "uriparse", +] [[package]] -name = "solana-frozen-abi" -version = "1.16.25" +name = "solana-rpc-client" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7077f6495ccc313dff49c3e3f3ed03e49058258bae7fee77ac29ba0a474ba82" +checksum = "94ae66b579851b5142ace6133b95192b38f9a72fb4a81ce936f0af92977c062f" dependencies = [ - "ahash 0.8.6", - "blake3", - "block-buffer 0.10.4", + "async-trait", + "base64 0.21.7", + "bincode", "bs58 0.4.0", - "bv", - "byteorder", - "cc", - "either", - "generic-array", - "getrandom 0.1.16", - "im", - "lazy_static", + "indicatif", "log", - "memmap2", - "once_cell", - "rand_core 0.6.4", - "rustc_version", + "reqwest", + "semver", "serde", - "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.8", - "solana-frozen-abi-macro", - "subtle", - "thiserror", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status", + "solana-version", + "solana-vote-program", + "tokio", ] [[package]] -name = "solana-frozen-abi-macro" -version = "1.16.25" +name = "solana-rpc-client-api" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f516f992211a2ab70de5c367190575c97e02d156f9f1d8b76886d673f30e88a2" +checksum = "e0a62a61c8c5989f2b5e4b75bda30b4647ad4affbcfe4a2890b1adb05e2b54c8" dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.48", + "base64 0.21.7", + "bs58 0.4.0", + "jsonrpc-core", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-sdk", + "solana-transaction-status", + "solana-version", + "spl-token-2022", + "thiserror", ] [[package]] -name = "solana-logger" -version = "1.16.25" +name = "solana-rpc-client-nonce-utils" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b64def674bfaa4a3f8be7ba19c03c9caec4ec028ba62b9a427ec1bf608a2486" +checksum = "9db51df524aceb35e305b735086191db052dc163d09b6d5d9be65e216ab7413b" dependencies = [ - "env_logger", - "lazy_static", - "log", + "clap 2.34.0", + "solana-clap-utils", + "solana-rpc-client", + "solana-sdk", + "thiserror", ] [[package]] -name = "solana-program" -version = "1.16.25" +name = "solana-runtime" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e92350aa5b42564681655331e7e0b9d5c99a442de317ceeb4741efbbe9a6c05" +checksum = "ba17961673c7ca5ac090d4e413d6d8b59956f03c36e1a20597b1d13ea4513077" dependencies = [ - "ark-bn254", - "ark-ec", - "ark-ff", - "ark-serialize", - "array-bytes", + "arrayref", "base64 0.21.7", "bincode", - "bitflags", "blake3", - "borsh 0.10.3", - "borsh 0.9.3", - "bs58 0.4.0", "bv", "bytemuck", - "cc", - "console_error_panic_hook", - "console_log", - "curve25519-dalek", - "getrandom 0.2.12", + "byteorder", + "bzip2", + "crossbeam-channel", + "dashmap", + "dir-diff", + "flate2", + "fnv", + "fs-err", + "im", + "index_list", "itertools", - "js-sys", "lazy_static", - "libc", - "libsecp256k1", "log", - "memoffset", - "num-bigint", + "lru", + "lz4", + "memmap2", + "modular-bitfield", "num-derive 0.3.3", "num-traits", - "parking_lot", - "rand 0.7.3", - "rand_chacha 0.2.2", + "num_cpus", + "num_enum 0.6.1", + "ouroboros", + "percentage", + "qualifier_attr", + "rand 0.8.5", + "rayon", + "regex", "rustc_version", - "rustversion", "serde", - "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.8", - "sha3 0.10.8", + "siphasher", + "solana-accounts-db", + "solana-address-lookup-table-program", + "solana-bpf-loader-program", + "solana-bucket-map", + "solana-compute-budget-program", + "solana-config-program", + "solana-cost-model", "solana-frozen-abi", "solana-frozen-abi-macro", - "solana-sdk-macro", + "solana-loader-v4-program", + "solana-measure", + "solana-metrics", + "solana-perf", + "solana-program-runtime", + "solana-rayon-threadlimit", + "solana-sdk", + "solana-stake-program", + "solana-system-program", + "solana-version", + "solana-vote", + "solana-vote-program", + "solana-zk-token-proof-program", + "solana-zk-token-sdk", + "static_assertions", + "strum", + "strum_macros", + "symlink", + "tar", + "tempfile", "thiserror", - "tiny-bip39", - "wasm-bindgen", - "zeroize", + "zstd", ] [[package]] name = "solana-sdk" -version = "1.16.25" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2087e15c92d4d6b3f085dc12fbe9614141c811f90a54cc418240ac30b608133f" +checksum = "284587e20a7256621b6061589a6d7f9fc1c1bcb9f25d183555034f7817ec49a6" dependencies = [ "assert_matches", "base64 0.21.7", "bincode", - "bitflags", + "bitflags 2.4.2", "borsh 0.10.3", "bs58 0.4.0", "bytemuck", @@ -1903,8 +4292,9 @@ dependencies = [ "num_enum 0.6.1", "pbkdf2 0.11.0", "qstring", + "qualifier_attr", "rand 0.7.3", - "rand_chacha 0.2.2", + "rand 0.8.5", "rustc_version", "rustversion", "serde", @@ -1916,32 +4306,259 @@ dependencies = [ "sha3 0.10.8", "solana-frozen-abi", "solana-frozen-abi-macro", - "solana-logger", + "solana-logger", + "solana-program", + "solana-sdk-macro", + "thiserror", + "uriparse", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk-macro" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fee7090babd8fe6cedd2e377366979464d29fa958bf5fc6554f6c7577b73fd4" +dependencies = [ + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn 2.0.48", +] + +[[package]] +name = "solana-send-transaction-service" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9d89f6816738de42436b6cb08798b8023a5106effc4f0c37ddca9ee8b10fe32" +dependencies = [ + "crossbeam-channel", + "log", + "solana-client", + "solana-measure", + "solana-metrics", + "solana-runtime", + "solana-sdk", + "solana-tpu-client", +] + +[[package]] +name = "solana-stake-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e46cec174bb995bb71ea3c875d17662d4c34f6e6ab853a08e9c3ddc06f0927c" +dependencies = [ + "bincode", + "log", + "rustc_version", + "solana-config-program", + "solana-program-runtime", + "solana-sdk", + "solana-vote-program", +] + +[[package]] +name = "solana-streamer" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4219f40db983a290ea75212b9e47013a47715eb224ca18e05bd094d86baefc37" +dependencies = [ + "async-channel", + "bytes", + "crossbeam-channel", + "futures-util", + "histogram", + "indexmap 2.1.0", + "itertools", + "libc", + "log", + "nix", + "pem", + "percentage", + "pkcs8", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rcgen", + "rustls", + "solana-metrics", + "solana-perf", + "solana-sdk", + "thiserror", + "tokio", + "x509-parser", +] + +[[package]] +name = "solana-system-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b9d710ecc45f8bb0219e46237df572efdf63fa2a1016d0a62e3b4a74f471863" +dependencies = [ + "bincode", + "log", + "serde", + "serde_derive", + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-thin-client" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f8d9eb19550425cbb6a96fdea18171a2e44529414fe09f8cf7a238a78fd9a37" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", +] + +[[package]] +name = "solana-tpu-client" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "795d4d7e76f87640d7a3d1ab6ebc2376d9b9d76a7c2664653628dc6f4bc64ecc" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 2.1.0", + "indicatif", + "log", + "rayon", + "solana-connection-cache", + "solana-measure", + "solana-metrics", + "solana-pubsub-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-transaction-status" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176b554ca42e29abd21d56f31c01599f9b334e65b22911bcdb691b9b02706636" +dependencies = [ + "Inflector", + "base64 0.21.7", + "bincode", + "borsh 0.10.3", + "bs58 0.4.0", + "lazy_static", + "log", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-sdk", + "spl-associated-token-account", + "spl-memo", + "spl-token", + "spl-token-2022", + "thiserror", +] + +[[package]] +name = "solana-udp-client" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a60895d452a9e2de1115d4ebaef537fb608b9a6e206cb7b24c82881a35348e3" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-net-utils", + "solana-sdk", + "solana-streamer", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-version" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "572a7a0f49ee43473c2f235432f98b2594c3a4e8cc9a1befd7a085be8192f5bd" +dependencies = [ + "log", + "rustc_version", + "semver", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk", +] + +[[package]] +name = "solana-vote" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d11054cc7d40221e3b80aded18b4436c57d0ae8a586aff88e32e22099e99298" +dependencies = [ + "crossbeam-channel", + "itertools", + "log", + "rustc_version", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-sdk", + "solana-vote-program", + "thiserror", +] + +[[package]] +name = "solana-vote-program" +version = "1.17.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89cffa52ab296ccc95ced7ae7875534cb4fd1cbb0bd9b8ad20e7ec55f15bcd5d" +dependencies = [ + "bincode", + "log", + "num-derive 0.3.3", + "num-traits", + "rustc_version", + "serde", + "serde_derive", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-metrics", "solana-program", - "solana-sdk-macro", + "solana-program-runtime", + "solana-sdk", "thiserror", - "uriparse", - "wasm-bindgen", ] [[package]] -name = "solana-sdk-macro" -version = "1.16.25" +name = "solana-zk-token-proof-program" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e0e0e7ee984b0f9179a1d4f4e9e67ce675de2324b5a98b61d2bdb61be3c19bb" +checksum = "83089a1e9b5ceef00ac0d399922604b12e925667fc6c3f0024398bb805a4ae27" dependencies = [ - "bs58 0.4.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.48", + "bytemuck", + "num-derive 0.3.3", + "num-traits", + "solana-program-runtime", + "solana-sdk", + "solana-zk-token-sdk", ] [[package]] name = "solana-zk-token-sdk" -version = "1.16.25" +version = "1.17.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1457c85ab70a518438b9ac2b0c56037b9f6693060dfb617bbb93c7116e4f0c22" +checksum = "a3e8e2f6c0d78bc9eb07efc1fcd034dd0fcc508af8809343ac861096aab84876" dependencies = [ "aes-gcm-siv", "base64 0.21.7", @@ -1966,6 +4583,47 @@ dependencies = [ "zeroize", ] +[[package]] +name = "solana_rbpf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" +dependencies = [ + "byteorder", + "combine", + "goblin", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "scroll", + "thiserror", + "winapi", +] + +[[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 = "spki" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "spl-associated-token-account" version = "2.2.0" @@ -2158,18 +4816,58 @@ dependencies = [ "spl-program-error", ] +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" + [[package]] name = "strsim" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[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 0.4.1", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + [[package]] name = "subtle" version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +[[package]] +name = "symlink" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" + [[package]] name = "syn" version = "1.0.109" @@ -2185,75 +4883,372 @@ dependencies = [ name = "syn" version = "2.0.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + +[[package]] +name = "synstructure" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-xid", +] + +[[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 = "tar" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +dependencies = [ + "filetime", + "libc", + "xattr", +] + +[[package]] +name = "tarpc" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1c38a012bed6fb9681d3bf71ffaa4f88f3b4b9ed3198cda6e4c8462d24d4bb80" +dependencies = [ + "anyhow", + "fnv", + "futures", + "humantime", + "opentelemetry", + "pin-project", + "rand 0.8.5", + "serde", + "static_assertions", + "tarpc-plugins", + "thiserror", + "tokio", + "tokio-serde", + "tokio-util 0.6.10", + "tracing", + "tracing-opentelemetry", +] + +[[package]] +name = "tarpc-plugins" +version = "0.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "tempfile" +version = "3.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a365e8cd18e44762ef95d87f284f4b5cd04107fec2ff3052bd6a3e6069669e67" +dependencies = [ + "cfg-if", + "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 = "test-case" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" +dependencies = [ + "test-case-macros", +] + +[[package]] +name = "test-case-core" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "test-case-macros" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", + "test-case-core", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +dependencies = [ + "unicode-width", +] + +[[package]] +name = "textwrap" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" + +[[package]] +name = "thiserror" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[package]] +name = "thread_local" +version = "1.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +dependencies = [ + "cfg-if", + "once_cell", +] + +[[package]] +name = "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-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac 0.8.1", + "once_cell", + "pbkdf2 0.4.0", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[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-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ "proc-macro2", "quote", - "unicode-ident", + "syn 2.0.48", ] [[package]] -name = "termcolor" -version = "1.4.1" +name = "tokio-rustls" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "winapi-util", + "rustls", + "tokio", ] [[package]] -name = "thiserror" -version = "1.0.56" +name = "tokio-serde" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" dependencies = [ - "thiserror-impl", + "bincode", + "bytes", + "educe", + "futures-core", + "futures-sink", + "pin-project", + "serde", + "serde_json", ] [[package]] -name = "thiserror-impl" -version = "1.0.56" +name = "tokio-stream" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", + "futures-core", + "pin-project-lite", + "tokio", ] [[package]] -name = "tiny-bip39" -version = "0.8.2" +name = "tokio-tungstenite" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ - "anyhow", - "hmac 0.8.1", - "once_cell", - "pbkdf2 0.4.0", - "rand 0.7.3", - "rustc-hash", - "sha2 0.9.9", - "thiserror", - "unicode-normalization", - "wasm-bindgen", - "zeroize", + "futures-util", + "log", + "rustls", + "tokio", + "tokio-rustls", + "tungstenite", + "webpki-roots 0.25.4", ] [[package]] -name = "tinyvec" -version = "1.6.0" +name = "tokio-util" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ - "tinyvec_macros", + "bytes", + "futures-core", + "futures-sink", + "log", + "pin-project-lite", + "slab", + "tokio", ] [[package]] -name = "tinyvec_macros" -version = "0.1.1" +name = "tokio-util" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" +checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +dependencies = [ + "bytes", + "futures-core", + "futures-sink", + "pin-project-lite", + "tokio", + "tracing", +] [[package]] name = "toml" @@ -2276,17 +5271,113 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap", + "indexmap 2.1.0", "toml_datetime", "winnow", ] +[[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-attributes" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.48", +] + +[[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-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-subscriber", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +dependencies = [ + "sharded-slab", + "thread_local", + "tracing-core", +] + +[[package]] +name = "try-lock" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" + +[[package]] +name = "tungstenite" +version = "0.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" +dependencies = [ + "byteorder", + "bytes", + "data-encoding", + "http", + "httparse", + "log", + "rand 0.8.5", + "rustls", + "sha1", + "thiserror", + "url", + "utf-8", + "webpki-roots 0.24.0", +] + [[package]] name = "typenum" version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +[[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" @@ -2308,6 +5399,18 @@ version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1dd624098567895118886609431a7c3b8f516e41d30e0643f03d94592a147e36" +[[package]] +name = "unicode-width" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + [[package]] name = "universal-hash" version = "0.4.1" @@ -2318,6 +5421,27 @@ dependencies = [ "subtle", ] +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "untrusted" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" + +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "uriparse" version = "0.6.4" @@ -2328,12 +5452,66 @@ dependencies = [ "lazy_static", ] +[[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", +] + +[[package]] +name = "utf-8" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" + +[[package]] +name = "valuable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" + [[package]] name = "version_check" version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "want" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" +dependencies = [ + "try-lock", +] + [[package]] name = "wasi" version = "0.9.0+wasi-snapshot-preview1" @@ -2371,6 +5549,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +dependencies = [ + "cfg-if", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.90" @@ -2410,6 +5600,21 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" +dependencies = [ + "rustls-webpki", +] + +[[package]] +name = "webpki-roots" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + [[package]] name = "winapi" version = "0.3.9" @@ -2441,19 +5646,61 @@ 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.0", +] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets 0.48.5", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.0", +] + [[package]] name = "windows-targets" version = "0.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", + "windows_aarch64_gnullvm 0.48.5", + "windows_aarch64_msvc 0.48.5", + "windows_i686_gnu 0.48.5", + "windows_i686_msvc 0.48.5", + "windows_x86_64_gnu 0.48.5", + "windows_x86_64_gnullvm 0.48.5", + "windows_x86_64_msvc 0.48.5", +] + +[[package]] +name = "windows-targets" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +dependencies = [ + "windows_aarch64_gnullvm 0.52.0", + "windows_aarch64_msvc 0.52.0", + "windows_i686_gnu 0.52.0", + "windows_i686_msvc 0.52.0", + "windows_x86_64_gnu 0.52.0", + "windows_x86_64_gnullvm 0.52.0", + "windows_x86_64_msvc 0.52.0", ] [[package]] @@ -2462,42 +5709,84 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" + [[package]] name = "windows_aarch64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" + [[package]] name = "windows_i686_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +[[package]] +name = "windows_i686_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" + [[package]] name = "windows_i686_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +[[package]] +name = "windows_i686_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" + [[package]] name = "windows_x86_64_gnu" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" + [[package]] name = "windows_x86_64_gnullvm" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" + [[package]] name = "windows_x86_64_msvc" version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" + [[package]] name = "winnow" version = "0.5.34" @@ -2507,6 +5796,16 @@ dependencies = [ "memchr", ] +[[package]] +name = "winreg" +version = "0.50.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" +dependencies = [ + "cfg-if", + "windows-sys 0.48.0", +] + [[package]] name = "wormhole-anchor-sdk" version = "0.29.0-alpha.1" @@ -2524,6 +5823,44 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b021a14ea7bcef9517ed9f81d4466c4a663dd90e726c5724707a976fa83ad8f3" +[[package]] +name = "x509-parser" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" +dependencies = [ + "asn1-rs", + "base64 0.13.1", + "data-encoding", + "der-parser", + "lazy_static", + "nom", + "oid-registry", + "rusticata-macros", + "thiserror", + "time", +] + +[[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 = "yasna" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +dependencies = [ + "time", +] + [[package]] name = "zerocopy" version = "0.7.32" @@ -2563,3 +5900,32 @@ dependencies = [ "quote", "syn 2.0.48", ] + +[[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/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index a9c762765..c21e09c5a 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -29,3 +29,10 @@ wormhole-io = "0.1.3" [dev-dependencies] hex = "0.4.3" +solana-program-test = "1.17.2" +serde_json = "1.0.113" +serde = "1.0.196" +base64 = "0.21.7" +solana-sdk = "1.17.2" +spl-token = "4" +spl-associated-token-account = "2.2.0" diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index ea596b602..ef8a4c6e2 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -29,7 +29,7 @@ pub struct Initialize<'info> { #[account( constraint = - args.mode == crate::config::Mode::Burning + args.mode == crate::config::Mode::Locking || mint.mint_authority.unwrap() == token_authority.key() @ NTTError::InvalidMintAuthority, )] diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 6b4d653f8..915a16e0f 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -10,7 +10,7 @@ use crate::{ use super::rate_limit::RateLimitState; #[account] -#[derive(InitSpace)] +#[derive(InitSpace, Debug, PartialEq, Eq)] // TODO: generalise this to arbitrary outbound messages (via a generic parameter in place of amount and recipient info) pub struct OutboxItem { pub sequence: u64, diff --git a/solana/programs/example-native-token-transfers/tests/common/account_utils.rs b/solana/programs/example-native-token-transfers/tests/common/account_utils.rs new file mode 100644 index 000000000..ac0fac5aa --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/common/account_utils.rs @@ -0,0 +1,93 @@ +use std::{io::Error, str::FromStr}; + +use anchor_lang::{prelude::Pubkey, AnchorDeserialize}; +use base64::Engine; +use serde::{Deserialize, Serialize}; +use solana_program_test::ProgramTest; + +#[derive(Deserialize, Serialize, Debug)] +#[serde(rename_all = "camelCase")] +pub struct Account { + pub pubkey: String, + pub account: AccountData, +} + +#[derive(Deserialize, Serialize, Debug)] +// camelcase +#[serde(rename_all = "camelCase")] +pub struct AccountData { + pub lamports: u64, + pub data: A, + pub owner: String, + pub executable: bool, + pub rent_epoch: u64, + pub space: u64, +} + +pub trait AccountLoadable: AnchorDeserialize { + fn add_account(program_test: &mut ProgramTest, path: &str) -> Result, Error>; +} + +impl AccountLoadable for T { + fn add_account(program_test: &mut ProgramTest, path: &str) -> Result, Error> { + let account = add_account_unchecked(program_test, path)?; + let decoded = AnchorDeserialize::deserialize(&mut account.account.data.as_slice())?; + Ok(Account { + pubkey: account.pubkey, + account: AccountData { + data: decoded, + ..account.account + }, + }) + } +} + +/// Adds an account to the program test without checking the account data. +/// Returns the account data as a byte array. +pub fn add_account_unchecked( + program_test: &mut ProgramTest, + path: &str, +) -> Result>, Error> { + let account = + serde_json::from_str::>(&std::fs::read_to_string(path)?)?; + if account.account.data.1 != "base64" { + return Err(Error::new( + std::io::ErrorKind::InvalidData, + "Expected base64 account data", + )); + } + program_test.add_account_with_base64_data( + Pubkey::from_str(&account.pubkey).map_err(|e| { + Error::new( + std::io::ErrorKind::InvalidData, + format!("Failed to parse pubkey: {}", e), + ) + })?, + account.account.lamports, + Pubkey::from_str(&account.account.owner).map_err(|e| { + Error::new( + std::io::ErrorKind::InvalidData, + format!("Failed to parse owner: {}", e), + ) + })?, + &account.account.data.0, + ); + + let decoded = base64::engine::general_purpose::STANDARD + .decode(account.account.data.0.as_bytes()) + .map_err(|e| { + Error::new( + std::io::ErrorKind::InvalidData, + format!("Failed to decode base64 account data: {}", e), + ) + })?; + + let result = Account { + pubkey: account.pubkey, + account: AccountData { + data: decoded, + ..account.account + }, + }; + Ok(result) +} diff --git a/solana/programs/example-native-token-transfers/tests/common/mod.rs b/solana/programs/example-native-token-transfers/tests/common/mod.rs new file mode 100644 index 000000000..ec051e3a5 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/common/mod.rs @@ -0,0 +1 @@ +pub mod account_utils; diff --git a/solana/programs/example-native-token-transfers/tests/lib.rs b/solana/programs/example-native-token-transfers/tests/lib.rs new file mode 100644 index 000000000..bb44e7a10 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/lib.rs @@ -0,0 +1,364 @@ +#![feature(type_changing_struct_update)] +#![feature(async_fn_in_trait)] +use std::io::Error; + +use anchor_lang::{ + prelude::{Clock, Pubkey}, + AccountDeserialize, Id, +}; +use anchor_spl::token::{Mint, Token}; +use common::account_utils::{add_account_unchecked, AccountLoadable}; +use example_native_token_transfers::{ + chain_id::ChainId, + config::Mode, + instructions::{InitializeArgs, SetSiblingArgs, TransferArgs}, + normalized_amount::NormalizedAmount, + queue::outbox::OutboxItem, +}; +use solana_program_test::*; +use solana_sdk::{ + instruction::Instruction, signature::Keypair, signer::Signer, signers::Signers, + system_instruction, transaction::Transaction, +}; +use spl_associated_token_account::get_associated_token_address_with_program_id; +use spl_token::instruction::AuthorityType; +use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector}; + +use crate::sdk::{ + accounts::NTT, + instructions::{ + admin::{set_sibling, SetSibling}, + initialize::{initialize, Initialize}, + transfer::{transfer_burn, transfer_lock, Transfer}, + }, +}; + +pub mod common; +// TODO: move this outside of the test module +pub mod sdk; + +pub async fn setup() -> Result { + let mut program_test = ProgramTest::default(); + program_test.add_program( + "example_native_token_transfers", + example_native_token_transfers::ID, + None, + ); + + program_test.add_program( + "mainnet_core_bridge", + wormhole_anchor_sdk::wormhole::program::ID, + None, + ); + + BridgeData::add_account( + &mut program_test, + "../../tests/accounts/mainnet/core_bridge_config.json", + )?; + + FeeCollector::add_account( + &mut program_test, + "../../tests/accounts/mainnet/core_bridge_fee_collector.json", + )?; + + // TODO: GuardianSet struct is not exposed in the wormhole sdk + add_account_unchecked( + &mut program_test, + "../../tests/accounts/mainnet/guardian_set_0.json", + )?; + + Ok(program_test) +} + +struct TestData { + pub ntt: NTT, + pub program_owner: Keypair, + pub mint_authority: Keypair, + pub mint: Pubkey, + pub user: Keypair, + pub user_token_account: Pubkey, +} + +const MINT_AMOUNT: u64 = 100000; + +/// Set up test accounts, and mint MINT_AMOUNT to the user's token account +async fn setup_accounts(ctx: &mut ProgramTestContext) -> TestData { + // create mint + let program_owner = Keypair::new(); + + let mint = Keypair::new(); + let mint_authority = Keypair::new(); + + let user = Keypair::new(); + let payer = ctx.payer.pubkey(); + + create_mint(ctx, &mint, &mint_authority.pubkey(), 9) + .await + .submit(ctx) + .await + .unwrap(); + + // create associated token account for user + let user_token_account = + get_associated_token_address_with_program_id(&user.pubkey(), &mint.pubkey(), &Token::id()); + + spl_associated_token_account::instruction::create_associated_token_account( + &payer, + &user.pubkey(), + &mint.pubkey(), + &Token::id(), + ) + .submit(ctx) + .await + .unwrap(); + + spl_token::instruction::mint_to( + &Token::id(), + &mint.pubkey(), + &user_token_account, + &mint_authority.pubkey(), + &[], + MINT_AMOUNT, + ) + .unwrap() + .submit_with_signers(&[&mint_authority], ctx) + .await + .unwrap(); + + TestData { + ntt: NTT { + program: example_native_token_transfers::ID, + }, + program_owner, + mint_authority, + mint: mint.pubkey(), + user, + user_token_account, + } +} + +/// Set up the program for locking mode, and registers a sibling +async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mode) { + if mode == Mode::Burning { + // we set the mint authority to the ntt contract in burn/mint mode + spl_token::instruction::set_authority( + &spl_token::ID, + &test_data.mint, + Some(&test_data.ntt.token_authority()), + AuthorityType::MintTokens, + &test_data.mint_authority.pubkey(), + &[], + ) + .unwrap() + .submit_with_signers(&[&test_data.mint_authority], ctx) + .await + .unwrap(); + } + + initialize( + &test_data.ntt, + Initialize { + payer: ctx.payer.pubkey(), + owner: test_data.program_owner.pubkey(), + mint: test_data.mint, + }, + InitializeArgs { + // TODO: use sdk + chain_id: 1, + limit: 10000, + mode, + }, + ) + .submit_with_signers(&[&test_data.program_owner], ctx) + .await + .unwrap(); + + set_sibling( + &test_data.ntt, + SetSibling { + payer: ctx.payer.pubkey(), + owner: test_data.program_owner.pubkey(), + mint: test_data.mint, + }, + SetSiblingArgs { + chain_id: ChainId { id: 2 }, + address: [7u8; 32], + limit: 10000, + }, + ) + .submit_with_signers(&[&test_data.program_owner], ctx) + .await + .unwrap(); +} + +#[tokio::test] +async fn tests() { + test_transfer_locking().await; + test_transfer_burning().await; +} + +async fn test_transfer_locking() { + let program_test = setup().await.unwrap(); + let mut ctx = program_test.start_with_context().await; + + let test_data = setup_accounts(&mut ctx).await; + setup_ntt(&mut ctx, &test_data, Mode::Locking).await; + + test_transfer_helper(&mut ctx, &test_data, Mode::Locking).await; +} + +async fn test_transfer_burning() { + let program_test = setup().await.unwrap(); + let mut ctx = program_test.start_with_context().await; + + let test_data = setup_accounts(&mut ctx).await; + setup_ntt(&mut ctx, &test_data, Mode::Burning).await; + + test_transfer_helper(&mut ctx, &test_data, Mode::Burning).await; +} + +async fn test_transfer_helper(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mode) { + let outbox_item = Keypair::new(); + + let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); + + let transfer = Transfer { + payer: ctx.payer.pubkey(), + mint: test_data.mint, + from: test_data.user_token_account, + from_authority: test_data.user.pubkey(), + outbox_item: outbox_item.pubkey(), + }; + + let args = TransferArgs { + amount: 100, + recipient_chain: ChainId { id: 2 }, + recipient_address: [1u8; 32], + should_queue: false, + }; + + match mode { + Mode::Burning => transfer_burn(&test_data.ntt, transfer, args) + .submit_with_signers(&[&test_data.user, &outbox_item], ctx) + .await + .unwrap(), + Mode::Locking => transfer_lock(&test_data.ntt, transfer, args) + .submit_with_signers(&[&test_data.user, &outbox_item], ctx) + .await + .unwrap(), + } + + let outbox_item_account: OutboxItem = ctx + .banks_client + .get_account_data_anchor(outbox_item.pubkey()) + .await + .unwrap(); + + assert_eq!( + outbox_item_account, + OutboxItem { + sequence: 0, + amount: NormalizedAmount { + amount: 10, + decimals: 8 + }, + recipient_chain: ChainId { id: 2 }, + recipient_address: [1u8; 32], + release_timestamp: clock.unix_timestamp, + released: false + } + ); +} + +/////////// Utils + +trait GetAccountDataAnchor { + async fn get_account_data_anchor( + &mut self, + pubkey: Pubkey, + ) -> Result; +} + +impl GetAccountDataAnchor for BanksClient { + async fn get_account_data_anchor( + &mut self, + pubkey: Pubkey, + ) -> Result { + let data = self.get_account(pubkey).await?.unwrap(); + Ok(T::try_deserialize(&mut data.data.as_ref()).unwrap()) + } +} + +trait Submittable { + async fn submit(self, ctx: &mut ProgramTestContext) -> Result<(), BanksClientError> + where + Self: Sized, + { + let no_signers: &[&Keypair] = &[]; + self.submit_with_signers(no_signers, ctx).await + } + async fn submit_with_signers( + self, + signers: &T, + ctx: &mut ProgramTestContext, + ) -> Result<(), BanksClientError>; +} + +impl Submittable for Instruction { + async fn submit_with_signers( + self, + signers: &T, + ctx: &mut ProgramTestContext, + ) -> Result<(), BanksClientError> { + let mut transaction = Transaction::new_with_payer(&[self], Some(&ctx.payer.pubkey())); + transaction.partial_sign(&[&ctx.payer], ctx.last_blockhash); + transaction.partial_sign(signers, ctx.last_blockhash); + + ctx.banks_client.process_transaction(transaction).await + } +} + +impl Submittable for Transaction { + async fn submit_with_signers( + mut self, + signers: &T, + ctx: &mut ProgramTestContext, + ) -> Result<(), BanksClientError> { + self.partial_sign(&[&ctx.payer], ctx.last_blockhash); + self.partial_sign(signers, ctx.last_blockhash); + ctx.banks_client.process_transaction(self).await + } +} + +pub async fn create_mint( + ctx: &mut ProgramTestContext, + mint: &Keypair, + mint_authority: &Pubkey, + decimals: u8, +) -> Transaction { + let rent = ctx.banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + + Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &ctx.payer.pubkey(), + &mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &spl_token::ID, + ), + spl_token::instruction::initialize_mint2( + &spl_token::ID, + &mint.pubkey(), + mint_authority, + None, + decimals, + ) + .unwrap(), + ], + Some(&ctx.payer.pubkey()), + &[&ctx.payer, mint], + ctx.last_blockhash, + ) +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs new file mode 100644 index 000000000..c44f2d34b --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -0,0 +1,86 @@ +use anchor_lang::prelude::Pubkey; +use example_native_token_transfers::{ + config::Config, + queue::{ + inbox::{InboxItem, InboxRateLimit}, + outbox::OutboxRateLimit, + }, sequence::Sequence, +}; + +pub struct NTT { + pub program: Pubkey, +} + +impl NTT { + pub fn config(&self) -> Pubkey { + let (config, _) = Pubkey::find_program_address(&[Config::SEED_PREFIX], &self.program); + config + } + + pub fn sequence(&self) -> Pubkey { + let (sequence, _) = + Pubkey::find_program_address(&[Sequence::SEED_PREFIX], &self.program); + sequence + } + + pub fn outbox_rate_limit(&self) -> Pubkey { + let (outbox_rate_limit, _) = + Pubkey::find_program_address(&[OutboxRateLimit::SEED_PREFIX], &self.program); + outbox_rate_limit + } + + pub fn inbox_rate_limit(&self, chain: u16) -> Pubkey { + let (inbox_rate_limit, _) = Pubkey::find_program_address( + &[InboxRateLimit::SEED_PREFIX, &chain.to_be_bytes()], + &self.program, + ); + inbox_rate_limit + } + + pub fn inbox_item(&self, chain: u16, sequence: u64) -> Pubkey { + let (inbox_item, _) = Pubkey::find_program_address( + &[ + InboxItem::SEED_PREFIX, + &chain.to_be_bytes(), + &sequence.to_be_bytes(), + ], + &self.program, + ); + inbox_item + } + + pub fn token_authority(&self) -> Pubkey { + let (token_authority, _) = + Pubkey::find_program_address(&[b"token_authority".as_ref()], &self.program); + token_authority + } + + pub fn emitter(&self) -> Pubkey { + let (emitter, _) = Pubkey::find_program_address(&[b"emitter".as_ref()], &self.program); + emitter + } + + pub fn wormhole_message(&self, outbox_item: &Pubkey) -> Pubkey { + let (wormhole_message, _) = Pubkey::find_program_address( + &[b"message".as_ref(), outbox_item.as_ref()], + &self.program, + ); + wormhole_message + } + + pub fn sibling(&self, chain: u16) -> Pubkey { + let (sibling, _) = Pubkey::find_program_address( + &[b"sibling".as_ref(), &chain.to_be_bytes()], + &self.program, + ); + sibling + } + + pub fn custody(&self, mint: &Pubkey) -> Pubkey { + anchor_spl::associated_token::get_associated_token_address_with_program_id( + &self.token_authority(), + &mint, + &spl_token::ID, + ) + } +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs new file mode 100644 index 000000000..29c284f7a --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs @@ -0,0 +1,32 @@ +use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; +use example_native_token_transfers::instructions::SetSiblingArgs; +use solana_sdk::instruction::Instruction; + +use crate::sdk::accounts::NTT; + +pub struct SetSibling { + pub payer: Pubkey, + pub owner: Pubkey, + pub mint: Pubkey, +} + +pub fn set_sibling(ntt: &NTT, accounts: SetSibling, args: SetSiblingArgs) -> Instruction { + let chain_id = args.chain_id.id; + let data = example_native_token_transfers::instruction::SetSibling { args }; + + let accounts = example_native_token_transfers::accounts::SetSibling { + config: ntt.config(), + owner: accounts.owner, + payer: accounts.payer, + sibling: ntt.sibling(chain_id), + inbox_rate_limit: ntt.inbox_rate_limit(chain_id), + mint: accounts.mint, + system_program: System::id(), + }; + + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs new file mode 100644 index 000000000..651a2e8cc --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs @@ -0,0 +1,37 @@ +use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; +use anchor_spl::{associated_token::AssociatedToken, token::Token}; +use example_native_token_transfers::instructions::InitializeArgs; +use solana_sdk::instruction::Instruction; + +use crate::sdk::accounts::NTT; + +pub struct Initialize { + pub payer: Pubkey, + pub owner: Pubkey, + pub mint: Pubkey, +} + +pub fn initialize(ntt: &NTT, accounts: Initialize, args: InitializeArgs) -> Instruction { + let data = example_native_token_transfers::instruction::Initialize { args }; + + let accounts = example_native_token_transfers::accounts::Initialize { + payer: accounts.payer, + owner: accounts.owner, + config: ntt.config(), + mint: accounts.mint, + seq: ntt.sequence(), + rate_limit: ntt.outbox_rate_limit(), + token_authority: ntt.token_authority(), + custody: ntt.custody(&accounts.mint), + token_program: Token::id(), + associated_token_program: AssociatedToken::id(), + system_program: System::id(), + }; + + // fetch account + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs new file mode 100644 index 000000000..1d09a3717 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs @@ -0,0 +1,3 @@ +pub mod initialize; +pub mod transfer; +pub mod admin; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs new file mode 100644 index 000000000..d40ed8b87 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs @@ -0,0 +1,64 @@ +use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; +use anchor_spl::token::Token; +use example_native_token_transfers::{accounts::NotPausedConfig, instructions::TransferArgs}; +use solana_sdk::instruction::Instruction; + +use crate::sdk::accounts::NTT; + +pub struct Transfer { + pub payer: Pubkey, + pub mint: Pubkey, + pub from: Pubkey, + pub from_authority: Pubkey, + pub outbox_item: Pubkey, +} + +pub fn transfer_burn(ntt: &NTT, transfer: Transfer, args: TransferArgs) -> Instruction { + let chain_id = args.recipient_chain.id; + let data = example_native_token_transfers::instruction::TransferBurn { args }; + + let accounts = example_native_token_transfers::accounts::TransferBurn { + common: common(ntt, &transfer), + inbox_rate_limit: ntt.inbox_rate_limit(chain_id), + }; + + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} + +pub fn transfer_lock(ntt: &NTT, transfer: Transfer, args: TransferArgs) -> Instruction { + let chain_id = args.recipient_chain.id; + let data = example_native_token_transfers::instruction::TransferLock { args }; + + let accounts = example_native_token_transfers::accounts::TransferLock { + common: common(ntt, &transfer), + inbox_rate_limit: ntt.inbox_rate_limit(chain_id), + token_authority: ntt.token_authority(), + custody: ntt.custody(&transfer.mint), + }; + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} + +fn common(ntt: &NTT, transfer: &Transfer) -> example_native_token_transfers::accounts::Transfer { + example_native_token_transfers::accounts::Transfer { + payer: transfer.payer, + config: NotPausedConfig { + config: ntt.config(), + }, + mint: transfer.mint, + from: transfer.from, + from_authority: transfer.from_authority, + token_program: Token::id(), + seq: ntt.sequence(), + outbox_item: transfer.outbox_item, + outbox_rate_limit: ntt.outbox_rate_limit(), + system_program: System::id(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs new file mode 100644 index 000000000..2e8410a09 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs @@ -0,0 +1,2 @@ +pub mod instructions; +pub mod accounts; diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 333ba7967..8e1a88278 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -620,10 +620,6 @@ export class NTT { return (await this.getConfig(config)).tokenProgram } - async nextSequence(): Promise { - return (await this.program.account.sequence.fetch(this.sequenceTrackerAccountAddress())).sequence - } - async getInboxItem(chain: ChainName | ChainId, sequence: BN): Promise { return await this.program.account.inboxItem.fetch(this.inboxItemAccountAddress(chain, sequence)) } From b9560dc65445d34ddd333a53f91ca6841185c277 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 14 Feb 2024 13:34:53 +0400 Subject: [PATCH 37/90] solana: test release_outbound in solana-program-test --- .../src/instructions/release_outbound.rs | 2 +- .../src/instructions/transfer.rs | 3 + .../src/queue/outbox.rs | 1 + .../tests/lib.rs | 150 ++++++++++++++++-- .../tests/sdk/accounts.rs | 38 ++++- .../tests/sdk/instructions/mod.rs | 3 +- .../sdk/instructions/release_outbound.rs | 41 +++++ 7 files changed, 224 insertions(+), 14 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index e8482fe7b..66388082e 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -88,7 +88,7 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs chain_id: accs.config.chain_id, sequence: accs.outbox_item.sequence, source_manager: accs.outbox_item.to_account_info().owner.to_bytes(), - sender: accs.emitter.key().to_bytes(), + sender: accs.outbox_item.sender.to_bytes(), payload: NativeTokenTransfer { amount: accs.outbox_item.amount, source_token: accs.config.mint.to_bytes(), diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 6b2f72805..0ba138d85 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -225,6 +225,9 @@ fn insert_into_outbox( common.outbox_item.set_inner(OutboxItem { sequence, amount, + // TODO: this is the token account itself. should we use the authority + // instead? (and enforce ATAs) + sender: common.from.key(), recipient_chain, recipient_address, release_timestamp, diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 915a16e0f..234045b9a 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -15,6 +15,7 @@ use super::rate_limit::RateLimitState; pub struct OutboxItem { pub sequence: u64, pub amount: NormalizedAmount, + pub sender: Pubkey, pub recipient_chain: ChainId, pub recipient_address: [u8; 32], pub release_timestamp: i64, diff --git a/solana/programs/example-native-token-transfers/tests/lib.rs b/solana/programs/example-native-token-transfers/tests/lib.rs index bb44e7a10..90044b4b7 100644 --- a/solana/programs/example-native-token-transfers/tests/lib.rs +++ b/solana/programs/example-native-token-transfers/tests/lib.rs @@ -11,24 +11,33 @@ use common::account_utils::{add_account_unchecked, AccountLoadable}; use example_native_token_transfers::{ chain_id::ChainId, config::Mode, - instructions::{InitializeArgs, SetSiblingArgs, TransferArgs}, + error::NTTError, + instructions::{InitializeArgs, ReleaseOutboundArgs, SetSiblingArgs, TransferArgs}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, normalized_amount::NormalizedAmount, queue::outbox::OutboxItem, + sequence::Sequence, }; +use sdk::accounts::Wormhole; use solana_program_test::*; use solana_sdk::{ - instruction::Instruction, signature::Keypair, signer::Signer, signers::Signers, - system_instruction, transaction::Transaction, + instruction::{Instruction, InstructionError}, + signature::Keypair, + signer::Signer, + signers::Signers, + system_instruction, + transaction::{Transaction, TransactionError}, }; use spl_associated_token_account::get_associated_token_address_with_program_id; use spl_token::instruction::AuthorityType; -use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector}; +use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector, PostedVaa}; use crate::sdk::{ accounts::NTT, instructions::{ admin::{set_sibling, SetSibling}, initialize::{initialize, Initialize}, + release_outbound::{release_outbound, ReleaseOutbound}, transfer::{transfer_burn, transfer_lock, Transfer}, }, }; @@ -128,6 +137,9 @@ async fn setup_accounts(ctx: &mut ProgramTestContext) -> TestData { TestData { ntt: NTT { program: example_native_token_transfers::ID, + wormhole: Wormhole { + program: wormhole_anchor_sdk::wormhole::program::ID, + }, }, program_owner, mint_authority, @@ -193,6 +205,7 @@ async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mod #[tokio::test] async fn tests() { + // NOTE: these can't be run concurrently, as they cause deadlocks test_transfer_locking().await; test_transfer_burning().await; } @@ -222,6 +235,12 @@ async fn test_transfer_helper(ctx: &mut ProgramTestContext, test_data: &TestData let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); + let sequence: Sequence = ctx + .banks_client + .get_account_data_anchor(test_data.ntt.sequence()) + .await + .unwrap(); + let transfer = Transfer { payer: ctx.payer.pubkey(), mint: test_data.mint, @@ -262,12 +281,106 @@ async fn test_transfer_helper(ctx: &mut ProgramTestContext, test_data: &TestData amount: 10, decimals: 8 }, + sender: test_data.user_token_account, recipient_chain: ChainId { id: 2 }, recipient_address: [1u8; 32], release_timestamp: clock.unix_timestamp, released: false } ); + + release_outbound( + &test_data.ntt, + ReleaseOutbound { + payer: ctx.payer.pubkey(), + outbox_item: outbox_item.pubkey(), + }, + ReleaseOutboundArgs { + revert_on_delay: true, + }, + ) + .submit(ctx) + .await + .unwrap(); + + let outbox_item_account_after: OutboxItem = ctx + .banks_client + .get_account_data_anchor(outbox_item.pubkey()) + .await + .unwrap(); + + // make sure the outbox item is now released, but nothing else has changed + assert_eq!( + OutboxItem { + released: true, + ..outbox_item_account + }, + outbox_item_account_after, + ); + + // make sure we can't send again + let err = release_outbound( + &test_data.ntt, + ReleaseOutbound { + payer: ctx.payer.pubkey(), + outbox_item: outbox_item.pubkey(), + }, + ReleaseOutboundArgs { + revert_on_delay: true, + }, + ) + .submit(ctx) + .await + .unwrap_err(); + + assert_eq!( + err.unwrap(), + TransactionError::InstructionError( + 0, + InstructionError::Custom(NTTError::MessageAlreadySent.into()) + ) + ); + + let wh_message = test_data.ntt.wormhole_message(&outbox_item.pubkey()); + + // NOTE: technically this is not a PostedVAA but a PostedMessage, but the + // sdk does not export that type, so we parse it as a PostedVAA instead. + // They are identical modulo the discriminator, which we just skip by using + // the unchecked deserialiser. + // TODO: update the sdk to export PostedMessage + let msg: PostedVaa> = ctx + .banks_client + .get_account_data_anchor_unchecked(wh_message) + .await + .unwrap(); + + let endpoint_message = msg.data(); + + assert_eq!( + endpoint_message, + &EndpointMessage::new(ManagerMessage { + chain_id: ChainId { id: 1 }, + sequence: sequence.sequence, + source_manager: example_native_token_transfers::ID.to_bytes(), + sender: test_data.user_token_account.to_bytes(), + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount: 10, + decimals: 8 + }, + source_token: test_data.mint.to_bytes(), + to: [1u8; 32], + to_chain: ChainId { id: 2 }, + } + }) + ); + + let next_sequence: Sequence = ctx + .banks_client + .get_account_data_anchor(test_data.ntt.sequence()) + .await + .unwrap(); + assert_eq!(next_sequence.sequence, sequence.sequence + 1); } /////////// Utils @@ -277,6 +390,11 @@ trait GetAccountDataAnchor { &mut self, pubkey: Pubkey, ) -> Result; + + async fn get_account_data_anchor_unchecked( + &mut self, + pubkey: Pubkey, + ) -> Result; } impl GetAccountDataAnchor for BanksClient { @@ -287,6 +405,14 @@ impl GetAccountDataAnchor for BanksClient { let data = self.get_account(pubkey).await?.unwrap(); Ok(T::try_deserialize(&mut data.data.as_ref()).unwrap()) } + + async fn get_account_data_anchor_unchecked( + &mut self, + pubkey: Pubkey, + ) -> Result { + let data = self.get_account(pubkey).await?.unwrap(); + Ok(T::try_deserialize_unchecked(&mut data.data.as_ref()).unwrap()) + } } trait Submittable { @@ -310,9 +436,11 @@ impl Submittable for Instruction { signers: &T, ctx: &mut ProgramTestContext, ) -> Result<(), BanksClientError> { + let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); + let mut transaction = Transaction::new_with_payer(&[self], Some(&ctx.payer.pubkey())); - transaction.partial_sign(&[&ctx.payer], ctx.last_blockhash); - transaction.partial_sign(signers, ctx.last_blockhash); + transaction.partial_sign(&[&ctx.payer], blockhash); + transaction.partial_sign(signers, blockhash); ctx.banks_client.process_transaction(transaction).await } @@ -324,8 +452,10 @@ impl Submittable for Transaction { signers: &T, ctx: &mut ProgramTestContext, ) -> Result<(), BanksClientError> { - self.partial_sign(&[&ctx.payer], ctx.last_blockhash); - self.partial_sign(signers, ctx.last_blockhash); + let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); + + self.partial_sign(&[&ctx.payer], blockhash); + self.partial_sign(signers, blockhash); ctx.banks_client.process_transaction(self).await } } @@ -339,6 +469,8 @@ pub async fn create_mint( let rent = ctx.banks_client.get_rent().await.unwrap(); let mint_rent = rent.minimum_balance(Mint::LEN); + let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); + Transaction::new_signed_with_payer( &[ system_instruction::create_account( @@ -359,6 +491,6 @@ pub async fn create_mint( ], Some(&ctx.payer.pubkey()), &[&ctx.payer, mint], - ctx.last_blockhash, + blockhash, ) } diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index c44f2d34b..825c49426 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -4,11 +4,40 @@ use example_native_token_transfers::{ queue::{ inbox::{InboxItem, InboxRateLimit}, outbox::OutboxRateLimit, - }, sequence::Sequence, + }, + sequence::Sequence, }; +use wormhole_anchor_sdk::wormhole; + +pub struct Wormhole { + pub program: Pubkey, +} + +impl Wormhole { + pub fn bridge(&self) -> Pubkey { + let (bridge, _) = + Pubkey::find_program_address(&[wormhole::BridgeData::SEED_PREFIX], &self.program); + bridge + } + + pub fn fee_collector(&self) -> Pubkey { + let (fee_collector, _) = + Pubkey::find_program_address(&[wormhole::FeeCollector::SEED_PREFIX], &self.program); + fee_collector + } + + pub fn sequence(&self, emitter: &Pubkey) -> Pubkey { + let (sequence, _) = Pubkey::find_program_address( + &[wormhole::SequenceTracker::SEED_PREFIX, emitter.as_ref()], + &self.program, + ); + sequence + } +} pub struct NTT { pub program: Pubkey, + pub wormhole: Wormhole, } impl NTT { @@ -18,8 +47,7 @@ impl NTT { } pub fn sequence(&self) -> Pubkey { - let (sequence, _) = - Pubkey::find_program_address(&[Sequence::SEED_PREFIX], &self.program); + let (sequence, _) = Pubkey::find_program_address(&[Sequence::SEED_PREFIX], &self.program); sequence } @@ -83,4 +111,8 @@ impl NTT { &spl_token::ID, ) } + + pub fn wormhole_sequence(&self) -> Pubkey { + self.wormhole.sequence(&self.emitter()) + } } diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs index 1d09a3717..25361f827 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs @@ -1,3 +1,4 @@ +pub mod admin; pub mod initialize; +pub mod release_outbound; pub mod transfer; -pub mod admin; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs new file mode 100644 index 000000000..a71a27b1a --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs @@ -0,0 +1,41 @@ +use anchor_lang::{prelude::*, InstructionData}; +use example_native_token_transfers::{ + accounts::NotPausedConfig, instructions::ReleaseOutboundArgs, +}; +use solana_sdk::{instruction::Instruction, sysvar::SysvarId}; + +use crate::sdk::accounts::NTT; + +pub struct ReleaseOutbound { + pub payer: Pubkey, + pub outbox_item: Pubkey, +} + +pub fn release_outbound( + ntt: &NTT, + release_outbound: ReleaseOutbound, + args: ReleaseOutboundArgs, +) -> Instruction { + let data = example_native_token_transfers::instruction::ReleaseOutbound { args }; + let accounts = example_native_token_transfers::accounts::ReleaseOutbound { + payer: release_outbound.payer, + config: NotPausedConfig { + config: ntt.config(), + }, + outbox_item: release_outbound.outbox_item, + wormhole_message: ntt.wormhole_message(&release_outbound.outbox_item), + emitter: ntt.emitter(), + wormhole_bridge: ntt.wormhole.bridge(), + wormhole_fee_collector: ntt.wormhole.fee_collector(), + wormhole_sequence: ntt.wormhole_sequence(), + wormhole_program: ntt.wormhole.program, + system_program: System::id(), + clock: Clock::id(), + rent: Rent::id(), + }; + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} From d7629c35bb5a833163f4ffc8fa57301d7d65d557 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 14 Feb 2024 19:54:24 +0400 Subject: [PATCH 38/90] solana: more transfer tests --- .../src/config.rs | 2 +- .../src/instructions/transfer.rs | 2 +- .../src/queue/outbox.rs | 2 +- .../src/queue/rate_limit.rs | 18 +- ...account_utils.rs => account_json_utils.rs} | 0 .../tests/common/mod.rs | 6 +- .../tests/common/query.rs | 45 ++ .../tests/common/setup.rs | 233 ++++++++ .../tests/common/submit.rs | 51 ++ .../tests/lib.rs | 496 ----------------- .../tests/sdk/instructions/transfer.rs | 12 +- .../tests/transfer.rs | 505 ++++++++++++++++++ 12 files changed, 865 insertions(+), 507 deletions(-) rename solana/programs/example-native-token-transfers/tests/common/{account_utils.rs => account_json_utils.rs} (100%) create mode 100644 solana/programs/example-native-token-transfers/tests/common/query.rs create mode 100644 solana/programs/example-native-token-transfers/tests/common/setup.rs create mode 100644 solana/programs/example-native-token-transfers/tests/common/submit.rs delete mode 100644 solana/programs/example-native-token-transfers/tests/lib.rs create mode 100644 solana/programs/example-native-token-transfers/tests/transfer.rs diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index f691b654b..2a81c136e 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -55,7 +55,7 @@ impl<'info> DerefMut for NotPausedConfig<'info> { } } -#[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone, PartialEq, Eq)] +#[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone, PartialEq, Eq, Copy)] pub enum Mode { Burning, Locking, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 0ba138d85..416150649 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -62,7 +62,7 @@ pub struct Transfer<'info> { pub system_program: Program<'info, System>, } -#[derive(AnchorSerialize, AnchorDeserialize)] +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] pub struct TransferArgs { pub amount: u64, pub recipient_chain: ChainId, diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 234045b9a..8a4c09cf5 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -46,7 +46,7 @@ impl OutboxItem { } #[account] -#[derive(InitSpace)] +#[derive(InitSpace, PartialEq, Eq, Debug)] pub struct OutboxRateLimit { pub rate_limit: RateLimitState, } diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index 2ff9e64ac..97c578854 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -2,19 +2,19 @@ use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}; use crate::{clock::current_timestamp, normalized_amount::NormalizedAmount}; -#[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace)] +#[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace, PartialEq, Eq, Debug)] pub struct RateLimitState { /// The maximum capacity of the rate limiter. - limit: NormalizedAmount, + pub limit: NormalizedAmount, /// The capacity of the rate limiter at `last_tx_timestamp`. /// The actual current capacity is calculated in `capacity_at`, by /// accounting for the time that has passed since `last_tx_timestamp` and /// the refill rate. - capacity_at_last_tx: NormalizedAmount, + pub capacity_at_last_tx: NormalizedAmount, /// The timestamp of the last transaction that counted towards the current /// capacity. Transactions that exceeded the capacity do not count, they are /// just delayed. - last_tx_timestamp: i64, + pub last_tx_timestamp: i64, } /// The result of attempting to consume from a rate limiter. @@ -39,9 +39,15 @@ impl RateLimitState { pub const RATE_LIMIT_DURATION: i64 = 60 * 60 * 24; // 24 hours - /// Returns the capacity of the rate limiter. pub fn capacity(&self) -> NormalizedAmount { - let now = current_timestamp(); + self.capacity_at(current_timestamp()) + } + + /// Returns the capacity of the rate limiter. + /// On-chain programs and unit tests should always use [`capacity`]. + /// This function is useful in solana-program-test, where the clock sysvar + /// + pub fn capacity_at(&self, now: UnixTimestamp) -> NormalizedAmount { assert!(self.last_tx_timestamp <= now); let limit = self.limit.amount() as u128; diff --git a/solana/programs/example-native-token-transfers/tests/common/account_utils.rs b/solana/programs/example-native-token-transfers/tests/common/account_json_utils.rs similarity index 100% rename from solana/programs/example-native-token-transfers/tests/common/account_utils.rs rename to solana/programs/example-native-token-transfers/tests/common/account_json_utils.rs diff --git a/solana/programs/example-native-token-transfers/tests/common/mod.rs b/solana/programs/example-native-token-transfers/tests/common/mod.rs index ec051e3a5..5c1f8f0ca 100644 --- a/solana/programs/example-native-token-transfers/tests/common/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/common/mod.rs @@ -1 +1,5 @@ -pub mod account_utils; +#![allow(async_fn_in_trait)] +pub mod account_json_utils; +pub mod query; +pub mod setup; +pub mod submit; diff --git a/solana/programs/example-native-token-transfers/tests/common/query.rs b/solana/programs/example-native-token-transfers/tests/common/query.rs new file mode 100644 index 000000000..e6215466c --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/common/query.rs @@ -0,0 +1,45 @@ +use anchor_lang::{prelude::Pubkey, AccountDeserialize}; +use solana_program_test::{BanksClient, ProgramTestContext}; + +// These are all partial functions, but we use them in a non-result context (in tests) so +// just unwrap inline here. +// Might revisit this later. + +pub trait GetAccountDataAnchor { + async fn get_account_data_anchor(&mut self, pubkey: Pubkey) -> T; + + async fn get_account_data_anchor_unchecked( + &mut self, + pubkey: Pubkey, + ) -> T; +} + +impl GetAccountDataAnchor for BanksClient { + async fn get_account_data_anchor(&mut self, pubkey: Pubkey) -> T { + let data = self.get_account(pubkey).await.unwrap().unwrap(); + T::try_deserialize(&mut data.data.as_ref()).unwrap() + } + + async fn get_account_data_anchor_unchecked( + &mut self, + pubkey: Pubkey, + ) -> T { + let data = self.get_account(pubkey).await.unwrap().unwrap(); + T::try_deserialize_unchecked(&mut data.data.as_ref()).unwrap() + } +} + +impl GetAccountDataAnchor for ProgramTestContext { + async fn get_account_data_anchor(&mut self, pubkey: Pubkey) -> T { + self.banks_client.get_account_data_anchor::(pubkey).await + } + + async fn get_account_data_anchor_unchecked( + &mut self, + pubkey: Pubkey, + ) -> T { + self.banks_client + .get_account_data_anchor_unchecked::(pubkey) + .await + } +} diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs new file mode 100644 index 000000000..3d515fa92 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -0,0 +1,233 @@ +use anchor_lang::prelude::{Error, Id, Pubkey}; +use anchor_spl::token::{Mint, Token}; +use example_native_token_transfers::{ + chain_id::ChainId, + config::Mode, + instructions::{InitializeArgs, SetSiblingArgs}, +}; +use solana_program_test::{ProgramTest, ProgramTestContext}; +use solana_sdk::{ + signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, +}; +use spl_associated_token_account::get_associated_token_address_with_program_id; +use spl_token::instruction::AuthorityType; +use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector}; + +use crate::sdk::{ + accounts::{Wormhole, NTT}, + instructions::{ + admin::{set_sibling, SetSibling}, + initialize::{initialize, Initialize}, + }, +}; + +use super::{ + account_json_utils::{add_account_unchecked, AccountLoadable}, + submit::Submittable, +}; + +// TODO: maybe make these configurable? I think it's fine like this: +// the mint amount is more than the limits, so we can test the rate limits +pub const MINT_AMOUNT: u64 = 100000; +pub const OUTBOUND_LIMIT: u64 = 10000; +pub const INBOUND_LIMIT: u64 = 50000; + +pub struct TestData { + pub ntt: NTT, + pub program_owner: Keypair, + pub mint_authority: Keypair, + pub mint: Pubkey, + pub user: Keypair, + pub user_token_account: Pubkey, +} + +pub async fn setup(mode: Mode) -> (ProgramTestContext, TestData) { + let program_test = setup_programs().await.unwrap(); + let mut ctx = program_test.start_with_context().await; + + let test_data = setup_accounts(&mut ctx).await; + setup_ntt(&mut ctx, &test_data, mode).await; + + return (ctx, test_data); +} + +pub async fn setup_programs() -> Result { + let mut program_test = ProgramTest::default(); + program_test.add_program( + "example_native_token_transfers", + example_native_token_transfers::ID, + None, + ); + + program_test.add_program( + "mainnet_core_bridge", + wormhole_anchor_sdk::wormhole::program::ID, + None, + ); + + BridgeData::add_account( + &mut program_test, + "../../tests/accounts/mainnet/core_bridge_config.json", + )?; + + FeeCollector::add_account( + &mut program_test, + "../../tests/accounts/mainnet/core_bridge_fee_collector.json", + )?; + + // TODO: GuardianSet struct is not exposed in the wormhole sdk + add_account_unchecked( + &mut program_test, + "../../tests/accounts/mainnet/guardian_set_0.json", + )?; + + Ok(program_test) +} + +/// Set up test accounts, and mint MINT_AMOUNT to the user's token account +/// Set up the program for locking mode, and registers a sibling +pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mode) { + if mode == Mode::Burning { + // we set the mint authority to the ntt contract in burn/mint mode + spl_token::instruction::set_authority( + &spl_token::ID, + &test_data.mint, + Some(&test_data.ntt.token_authority()), + AuthorityType::MintTokens, + &test_data.mint_authority.pubkey(), + &[], + ) + .unwrap() + .submit_with_signers(&[&test_data.mint_authority], ctx) + .await + .unwrap(); + } + + initialize( + &test_data.ntt, + Initialize { + payer: ctx.payer.pubkey(), + owner: test_data.program_owner.pubkey(), + mint: test_data.mint, + }, + InitializeArgs { + // TODO: use sdk + chain_id: 1, + limit: OUTBOUND_LIMIT, + mode, + }, + ) + .submit_with_signers(&[&test_data.program_owner], ctx) + .await + .unwrap(); + + set_sibling( + &test_data.ntt, + SetSibling { + payer: ctx.payer.pubkey(), + owner: test_data.program_owner.pubkey(), + mint: test_data.mint, + }, + SetSiblingArgs { + chain_id: ChainId { id: 2 }, + address: [7u8; 32], + limit: INBOUND_LIMIT, + }, + ) + .submit_with_signers(&[&test_data.program_owner], ctx) + .await + .unwrap(); +} + +pub async fn setup_accounts(ctx: &mut ProgramTestContext) -> TestData { + // create mint + let program_owner = Keypair::new(); + + let mint = Keypair::new(); + let mint_authority = Keypair::new(); + + let user = Keypair::new(); + let payer = ctx.payer.pubkey(); + + create_mint(ctx, &mint, &mint_authority.pubkey(), 9) + .await + .submit(ctx) + .await + .unwrap(); + + // create associated token account for user + let user_token_account = + get_associated_token_address_with_program_id(&user.pubkey(), &mint.pubkey(), &Token::id()); + + spl_associated_token_account::instruction::create_associated_token_account( + &payer, + &user.pubkey(), + &mint.pubkey(), + &Token::id(), + ) + .submit(ctx) + .await + .unwrap(); + + spl_token::instruction::mint_to( + &Token::id(), + &mint.pubkey(), + &user_token_account, + &mint_authority.pubkey(), + &[], + MINT_AMOUNT, + ) + .unwrap() + .submit_with_signers(&[&mint_authority], ctx) + .await + .unwrap(); + + TestData { + ntt: NTT { + program: example_native_token_transfers::ID, + wormhole: Wormhole { + program: wormhole_anchor_sdk::wormhole::program::ID, + }, + }, + program_owner, + mint_authority, + mint: mint.pubkey(), + user, + user_token_account, + } +} + +pub async fn create_mint( + ctx: &mut ProgramTestContext, + mint: &Keypair, + mint_authority: &Pubkey, + decimals: u8, +) -> Transaction { + let rent = ctx.banks_client.get_rent().await.unwrap(); + let mint_rent = rent.minimum_balance(Mint::LEN); + + let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); + + Transaction::new_signed_with_payer( + &[ + system_instruction::create_account( + &ctx.payer.pubkey(), + &mint.pubkey(), + mint_rent, + Mint::LEN as u64, + &spl_token::ID, + ), + spl_token::instruction::initialize_mint2( + &spl_token::ID, + &mint.pubkey(), + mint_authority, + None, + decimals, + ) + .unwrap(), + ], + Some(&ctx.payer.pubkey()), + &[&ctx.payer, mint], + blockhash, + ) +} diff --git a/solana/programs/example-native-token-transfers/tests/common/submit.rs b/solana/programs/example-native-token-transfers/tests/common/submit.rs new file mode 100644 index 000000000..d81fbe4bb --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/common/submit.rs @@ -0,0 +1,51 @@ +use solana_program_test::{BanksClientError, ProgramTestContext}; +use solana_sdk::{ + instruction::Instruction, signature::Keypair, signer::Signer, signers::Signers, + transaction::Transaction, +}; + +pub trait Submittable { + async fn submit(self, ctx: &mut ProgramTestContext) -> Result<(), BanksClientError> + where + Self: Sized, + { + let no_signers: &[&Keypair] = &[]; + self.submit_with_signers(no_signers, ctx).await + } + + async fn submit_with_signers( + self, + signers: &T, + ctx: &mut ProgramTestContext, + ) -> Result<(), BanksClientError>; +} + +impl Submittable for Instruction { + async fn submit_with_signers( + self, + signers: &T, + ctx: &mut ProgramTestContext, + ) -> Result<(), BanksClientError> { + let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); + + let mut transaction = Transaction::new_with_payer(&[self], Some(&ctx.payer.pubkey())); + transaction.partial_sign(&[&ctx.payer], blockhash); + transaction.partial_sign(signers, blockhash); + + ctx.banks_client.process_transaction(transaction).await + } +} + +impl Submittable for Transaction { + async fn submit_with_signers( + mut self, + signers: &T, + ctx: &mut ProgramTestContext, + ) -> Result<(), BanksClientError> { + let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); + + self.partial_sign(&[&ctx.payer], blockhash); + self.partial_sign(signers, blockhash); + ctx.banks_client.process_transaction(self).await + } +} diff --git a/solana/programs/example-native-token-transfers/tests/lib.rs b/solana/programs/example-native-token-transfers/tests/lib.rs deleted file mode 100644 index 90044b4b7..000000000 --- a/solana/programs/example-native-token-transfers/tests/lib.rs +++ /dev/null @@ -1,496 +0,0 @@ -#![feature(type_changing_struct_update)] -#![feature(async_fn_in_trait)] -use std::io::Error; - -use anchor_lang::{ - prelude::{Clock, Pubkey}, - AccountDeserialize, Id, -}; -use anchor_spl::token::{Mint, Token}; -use common::account_utils::{add_account_unchecked, AccountLoadable}; -use example_native_token_transfers::{ - chain_id::ChainId, - config::Mode, - error::NTTError, - instructions::{InitializeArgs, ReleaseOutboundArgs, SetSiblingArgs, TransferArgs}, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, - normalized_amount::NormalizedAmount, - queue::outbox::OutboxItem, - sequence::Sequence, -}; -use sdk::accounts::Wormhole; -use solana_program_test::*; -use solana_sdk::{ - instruction::{Instruction, InstructionError}, - signature::Keypair, - signer::Signer, - signers::Signers, - system_instruction, - transaction::{Transaction, TransactionError}, -}; -use spl_associated_token_account::get_associated_token_address_with_program_id; -use spl_token::instruction::AuthorityType; -use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector, PostedVaa}; - -use crate::sdk::{ - accounts::NTT, - instructions::{ - admin::{set_sibling, SetSibling}, - initialize::{initialize, Initialize}, - release_outbound::{release_outbound, ReleaseOutbound}, - transfer::{transfer_burn, transfer_lock, Transfer}, - }, -}; - -pub mod common; -// TODO: move this outside of the test module -pub mod sdk; - -pub async fn setup() -> Result { - let mut program_test = ProgramTest::default(); - program_test.add_program( - "example_native_token_transfers", - example_native_token_transfers::ID, - None, - ); - - program_test.add_program( - "mainnet_core_bridge", - wormhole_anchor_sdk::wormhole::program::ID, - None, - ); - - BridgeData::add_account( - &mut program_test, - "../../tests/accounts/mainnet/core_bridge_config.json", - )?; - - FeeCollector::add_account( - &mut program_test, - "../../tests/accounts/mainnet/core_bridge_fee_collector.json", - )?; - - // TODO: GuardianSet struct is not exposed in the wormhole sdk - add_account_unchecked( - &mut program_test, - "../../tests/accounts/mainnet/guardian_set_0.json", - )?; - - Ok(program_test) -} - -struct TestData { - pub ntt: NTT, - pub program_owner: Keypair, - pub mint_authority: Keypair, - pub mint: Pubkey, - pub user: Keypair, - pub user_token_account: Pubkey, -} - -const MINT_AMOUNT: u64 = 100000; - -/// Set up test accounts, and mint MINT_AMOUNT to the user's token account -async fn setup_accounts(ctx: &mut ProgramTestContext) -> TestData { - // create mint - let program_owner = Keypair::new(); - - let mint = Keypair::new(); - let mint_authority = Keypair::new(); - - let user = Keypair::new(); - let payer = ctx.payer.pubkey(); - - create_mint(ctx, &mint, &mint_authority.pubkey(), 9) - .await - .submit(ctx) - .await - .unwrap(); - - // create associated token account for user - let user_token_account = - get_associated_token_address_with_program_id(&user.pubkey(), &mint.pubkey(), &Token::id()); - - spl_associated_token_account::instruction::create_associated_token_account( - &payer, - &user.pubkey(), - &mint.pubkey(), - &Token::id(), - ) - .submit(ctx) - .await - .unwrap(); - - spl_token::instruction::mint_to( - &Token::id(), - &mint.pubkey(), - &user_token_account, - &mint_authority.pubkey(), - &[], - MINT_AMOUNT, - ) - .unwrap() - .submit_with_signers(&[&mint_authority], ctx) - .await - .unwrap(); - - TestData { - ntt: NTT { - program: example_native_token_transfers::ID, - wormhole: Wormhole { - program: wormhole_anchor_sdk::wormhole::program::ID, - }, - }, - program_owner, - mint_authority, - mint: mint.pubkey(), - user, - user_token_account, - } -} - -/// Set up the program for locking mode, and registers a sibling -async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mode) { - if mode == Mode::Burning { - // we set the mint authority to the ntt contract in burn/mint mode - spl_token::instruction::set_authority( - &spl_token::ID, - &test_data.mint, - Some(&test_data.ntt.token_authority()), - AuthorityType::MintTokens, - &test_data.mint_authority.pubkey(), - &[], - ) - .unwrap() - .submit_with_signers(&[&test_data.mint_authority], ctx) - .await - .unwrap(); - } - - initialize( - &test_data.ntt, - Initialize { - payer: ctx.payer.pubkey(), - owner: test_data.program_owner.pubkey(), - mint: test_data.mint, - }, - InitializeArgs { - // TODO: use sdk - chain_id: 1, - limit: 10000, - mode, - }, - ) - .submit_with_signers(&[&test_data.program_owner], ctx) - .await - .unwrap(); - - set_sibling( - &test_data.ntt, - SetSibling { - payer: ctx.payer.pubkey(), - owner: test_data.program_owner.pubkey(), - mint: test_data.mint, - }, - SetSiblingArgs { - chain_id: ChainId { id: 2 }, - address: [7u8; 32], - limit: 10000, - }, - ) - .submit_with_signers(&[&test_data.program_owner], ctx) - .await - .unwrap(); -} - -#[tokio::test] -async fn tests() { - // NOTE: these can't be run concurrently, as they cause deadlocks - test_transfer_locking().await; - test_transfer_burning().await; -} - -async fn test_transfer_locking() { - let program_test = setup().await.unwrap(); - let mut ctx = program_test.start_with_context().await; - - let test_data = setup_accounts(&mut ctx).await; - setup_ntt(&mut ctx, &test_data, Mode::Locking).await; - - test_transfer_helper(&mut ctx, &test_data, Mode::Locking).await; -} - -async fn test_transfer_burning() { - let program_test = setup().await.unwrap(); - let mut ctx = program_test.start_with_context().await; - - let test_data = setup_accounts(&mut ctx).await; - setup_ntt(&mut ctx, &test_data, Mode::Burning).await; - - test_transfer_helper(&mut ctx, &test_data, Mode::Burning).await; -} - -async fn test_transfer_helper(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mode) { - let outbox_item = Keypair::new(); - - let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); - - let sequence: Sequence = ctx - .banks_client - .get_account_data_anchor(test_data.ntt.sequence()) - .await - .unwrap(); - - let transfer = Transfer { - payer: ctx.payer.pubkey(), - mint: test_data.mint, - from: test_data.user_token_account, - from_authority: test_data.user.pubkey(), - outbox_item: outbox_item.pubkey(), - }; - - let args = TransferArgs { - amount: 100, - recipient_chain: ChainId { id: 2 }, - recipient_address: [1u8; 32], - should_queue: false, - }; - - match mode { - Mode::Burning => transfer_burn(&test_data.ntt, transfer, args) - .submit_with_signers(&[&test_data.user, &outbox_item], ctx) - .await - .unwrap(), - Mode::Locking => transfer_lock(&test_data.ntt, transfer, args) - .submit_with_signers(&[&test_data.user, &outbox_item], ctx) - .await - .unwrap(), - } - - let outbox_item_account: OutboxItem = ctx - .banks_client - .get_account_data_anchor(outbox_item.pubkey()) - .await - .unwrap(); - - assert_eq!( - outbox_item_account, - OutboxItem { - sequence: 0, - amount: NormalizedAmount { - amount: 10, - decimals: 8 - }, - sender: test_data.user_token_account, - recipient_chain: ChainId { id: 2 }, - recipient_address: [1u8; 32], - release_timestamp: clock.unix_timestamp, - released: false - } - ); - - release_outbound( - &test_data.ntt, - ReleaseOutbound { - payer: ctx.payer.pubkey(), - outbox_item: outbox_item.pubkey(), - }, - ReleaseOutboundArgs { - revert_on_delay: true, - }, - ) - .submit(ctx) - .await - .unwrap(); - - let outbox_item_account_after: OutboxItem = ctx - .banks_client - .get_account_data_anchor(outbox_item.pubkey()) - .await - .unwrap(); - - // make sure the outbox item is now released, but nothing else has changed - assert_eq!( - OutboxItem { - released: true, - ..outbox_item_account - }, - outbox_item_account_after, - ); - - // make sure we can't send again - let err = release_outbound( - &test_data.ntt, - ReleaseOutbound { - payer: ctx.payer.pubkey(), - outbox_item: outbox_item.pubkey(), - }, - ReleaseOutboundArgs { - revert_on_delay: true, - }, - ) - .submit(ctx) - .await - .unwrap_err(); - - assert_eq!( - err.unwrap(), - TransactionError::InstructionError( - 0, - InstructionError::Custom(NTTError::MessageAlreadySent.into()) - ) - ); - - let wh_message = test_data.ntt.wormhole_message(&outbox_item.pubkey()); - - // NOTE: technically this is not a PostedVAA but a PostedMessage, but the - // sdk does not export that type, so we parse it as a PostedVAA instead. - // They are identical modulo the discriminator, which we just skip by using - // the unchecked deserialiser. - // TODO: update the sdk to export PostedMessage - let msg: PostedVaa> = ctx - .banks_client - .get_account_data_anchor_unchecked(wh_message) - .await - .unwrap(); - - let endpoint_message = msg.data(); - - assert_eq!( - endpoint_message, - &EndpointMessage::new(ManagerMessage { - chain_id: ChainId { id: 1 }, - sequence: sequence.sequence, - source_manager: example_native_token_transfers::ID.to_bytes(), - sender: test_data.user_token_account.to_bytes(), - payload: NativeTokenTransfer { - amount: NormalizedAmount { - amount: 10, - decimals: 8 - }, - source_token: test_data.mint.to_bytes(), - to: [1u8; 32], - to_chain: ChainId { id: 2 }, - } - }) - ); - - let next_sequence: Sequence = ctx - .banks_client - .get_account_data_anchor(test_data.ntt.sequence()) - .await - .unwrap(); - assert_eq!(next_sequence.sequence, sequence.sequence + 1); -} - -/////////// Utils - -trait GetAccountDataAnchor { - async fn get_account_data_anchor( - &mut self, - pubkey: Pubkey, - ) -> Result; - - async fn get_account_data_anchor_unchecked( - &mut self, - pubkey: Pubkey, - ) -> Result; -} - -impl GetAccountDataAnchor for BanksClient { - async fn get_account_data_anchor( - &mut self, - pubkey: Pubkey, - ) -> Result { - let data = self.get_account(pubkey).await?.unwrap(); - Ok(T::try_deserialize(&mut data.data.as_ref()).unwrap()) - } - - async fn get_account_data_anchor_unchecked( - &mut self, - pubkey: Pubkey, - ) -> Result { - let data = self.get_account(pubkey).await?.unwrap(); - Ok(T::try_deserialize_unchecked(&mut data.data.as_ref()).unwrap()) - } -} - -trait Submittable { - async fn submit(self, ctx: &mut ProgramTestContext) -> Result<(), BanksClientError> - where - Self: Sized, - { - let no_signers: &[&Keypair] = &[]; - self.submit_with_signers(no_signers, ctx).await - } - async fn submit_with_signers( - self, - signers: &T, - ctx: &mut ProgramTestContext, - ) -> Result<(), BanksClientError>; -} - -impl Submittable for Instruction { - async fn submit_with_signers( - self, - signers: &T, - ctx: &mut ProgramTestContext, - ) -> Result<(), BanksClientError> { - let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); - - let mut transaction = Transaction::new_with_payer(&[self], Some(&ctx.payer.pubkey())); - transaction.partial_sign(&[&ctx.payer], blockhash); - transaction.partial_sign(signers, blockhash); - - ctx.banks_client.process_transaction(transaction).await - } -} - -impl Submittable for Transaction { - async fn submit_with_signers( - mut self, - signers: &T, - ctx: &mut ProgramTestContext, - ) -> Result<(), BanksClientError> { - let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); - - self.partial_sign(&[&ctx.payer], blockhash); - self.partial_sign(signers, blockhash); - ctx.banks_client.process_transaction(self).await - } -} - -pub async fn create_mint( - ctx: &mut ProgramTestContext, - mint: &Keypair, - mint_authority: &Pubkey, - decimals: u8, -) -> Transaction { - let rent = ctx.banks_client.get_rent().await.unwrap(); - let mint_rent = rent.minimum_balance(Mint::LEN); - - let blockhash = ctx.banks_client.get_latest_blockhash().await.unwrap(); - - Transaction::new_signed_with_payer( - &[ - system_instruction::create_account( - &ctx.payer.pubkey(), - &mint.pubkey(), - mint_rent, - Mint::LEN as u64, - &spl_token::ID, - ), - spl_token::instruction::initialize_mint2( - &spl_token::ID, - &mint.pubkey(), - mint_authority, - None, - decimals, - ) - .unwrap(), - ], - Some(&ctx.payer.pubkey()), - &[&ctx.payer, mint], - blockhash, - ) -} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs index d40ed8b87..6780ab28b 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs @@ -1,10 +1,13 @@ use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; use anchor_spl::token::Token; -use example_native_token_transfers::{accounts::NotPausedConfig, instructions::TransferArgs}; +use example_native_token_transfers::{ + accounts::NotPausedConfig, config::Mode, instructions::TransferArgs, +}; use solana_sdk::instruction::Instruction; use crate::sdk::accounts::NTT; +#[derive(Debug, Clone)] pub struct Transfer { pub payer: Pubkey, pub mint: Pubkey, @@ -13,6 +16,13 @@ pub struct Transfer { pub outbox_item: Pubkey, } +pub fn transfer(ntt: &NTT, transfer: Transfer, args: TransferArgs, mode: Mode) -> Instruction { + match mode { + Mode::Burning => transfer_burn(ntt, transfer, args), + Mode::Locking => transfer_lock(ntt, transfer, args), + } +} + pub fn transfer_burn(ntt: &NTT, transfer: Transfer, args: TransferArgs) -> Instruction { let chain_id = args.recipient_chain.id; let data = example_native_token_transfers::instruction::TransferBurn { args }; diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs new file mode 100644 index 000000000..14b613f11 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -0,0 +1,505 @@ +#![feature(type_changing_struct_update)] +#![feature(async_fn_in_trait)] + +use anchor_lang::prelude::{Clock, Pubkey}; +use anchor_spl::token::{Mint, TokenAccount}; +use common::setup::TestData; +use example_native_token_transfers::{ + chain_id::ChainId, + config::Mode, + error::NTTError, + instructions::{ReleaseOutboundArgs, TransferArgs}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, + normalized_amount::NormalizedAmount, + queue::outbox::{OutboxItem, OutboxRateLimit}, + sequence::Sequence, +}; +use solana_program_test::*; +use solana_sdk::{ + instruction::InstructionError, signature::Keypair, signer::Signer, + transaction::TransactionError, +}; +use wormhole_anchor_sdk::wormhole::PostedVaa; + +use crate::{common::submit::Submittable, sdk::instructions::transfer::transfer}; +use crate::{ + common::{query::GetAccountDataAnchor, setup::OUTBOUND_LIMIT}, + sdk::instructions::{ + release_outbound::{release_outbound, ReleaseOutbound}, + transfer::Transfer, + }, +}; + +pub mod common; +pub mod sdk; + +use crate::common::setup::setup; + +// TODO: some more tests +// - unregistered sibling can't transfer +// - can't transfer more than balance +// - cancel flows +// - wrong inbox accounts + +/// Helper function for setting up transfer accounts and args. +/// It sets the accounts up properly, so for negative testing we just modify the +/// result. +fn init_accs_args( + ctx: &mut ProgramTestContext, + test_data: &TestData, + outbox_item: Pubkey, + amount: u64, + should_queue: bool, +) -> (Transfer, TransferArgs) { + let accs = Transfer { + payer: ctx.payer.pubkey(), + mint: test_data.mint, + from: test_data.user_token_account, + from_authority: test_data.user.pubkey(), + outbox_item, + }; + + let args = TransferArgs { + amount, + recipient_chain: ChainId { id: 2 }, + recipient_address: [1u8; 32], + should_queue, + }; + + (accs, args) +} + +#[tokio::test] +pub async fn test_transfer_locking() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + test_transfer(&mut ctx, &test_data, Mode::Locking).await; +} + +#[tokio::test] +pub async fn test_transfer_burning() { + let (mut ctx, test_data) = setup(Mode::Burning).await; + test_transfer(&mut ctx, &test_data, Mode::Burning).await; +} + +/// This tests the happy path of a transfer, with all the relevant account checks. +/// Written as a helper function so both modes can be tested. +async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: Mode) { + let outbox_item = Keypair::new(); + + let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); + + let sequence: Sequence = ctx.get_account_data_anchor(test_data.ntt.sequence()).await; + + let (accs, args) = init_accs_args(ctx, test_data, outbox_item.pubkey(), 100, false); + + transfer(&test_data.ntt, accs, args, mode) + .submit_with_signers(&[&test_data.user, &outbox_item], ctx) + .await + .unwrap(); + + let outbox_item_account: OutboxItem = ctx.get_account_data_anchor(outbox_item.pubkey()).await; + + assert_eq!( + outbox_item_account, + OutboxItem { + sequence: sequence.sequence, + amount: NormalizedAmount { + amount: 10, + decimals: 8 + }, + sender: test_data.user_token_account, + recipient_chain: ChainId { id: 2 }, + recipient_address: [1u8; 32], + release_timestamp: clock.unix_timestamp, + released: false + } + ); + + release_outbound( + &test_data.ntt, + ReleaseOutbound { + payer: ctx.payer.pubkey(), + outbox_item: outbox_item.pubkey(), + }, + ReleaseOutboundArgs { + revert_on_delay: true, + }, + ) + .submit(ctx) + .await + .unwrap(); + + let outbox_item_account_after: OutboxItem = + ctx.get_account_data_anchor(outbox_item.pubkey()).await; + + // make sure the outbox item is now released, but nothing else has changed + assert_eq!( + OutboxItem { + released: true, + ..outbox_item_account + }, + outbox_item_account_after, + ); + + let wh_message = test_data.ntt.wormhole_message(&outbox_item.pubkey()); + + // NOTE: technically this is not a PostedVAA but a PostedMessage, but the + // sdk does not export that type, so we parse it as a PostedVAA instead. + // They are identical modulo the discriminator, which we just skip by using + // the unchecked deserialiser. + // TODO: update the sdk to export PostedMessage + let msg: PostedVaa> = + ctx.get_account_data_anchor_unchecked(wh_message).await; + + let endpoint_message = msg.data(); + + assert_eq!( + endpoint_message, + &EndpointMessage::new(ManagerMessage { + chain_id: ChainId { id: 1 }, + sequence: sequence.sequence, + source_manager: example_native_token_transfers::ID.to_bytes(), + sender: test_data.user_token_account.to_bytes(), + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount: 10, + decimals: 8 + }, + source_token: test_data.mint.to_bytes(), + to: [1u8; 32], + to_chain: ChainId { id: 2 }, + } + }) + ); + + let next_sequence: Sequence = ctx.get_account_data_anchor(test_data.ntt.sequence()).await; + assert_eq!(next_sequence.sequence, sequence.sequence + 1); +} + +#[tokio::test] +async fn test_burn_mode_burns_tokens() { + let (mut ctx, test_data) = setup(Mode::Burning).await; + + let outbox_item = Keypair::new(); + + let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 105, false); + + let mint_before: Mint = ctx.get_account_data_anchor(test_data.mint).await; + + let token_account_before: TokenAccount = ctx + .get_account_data_anchor(test_data.user_token_account) + .await; + + transfer(&test_data.ntt, accs, args, Mode::Burning) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); + + let mint_after: Mint = ctx.get_account_data_anchor(test_data.mint).await; + + let token_account_after: TokenAccount = ctx + .get_account_data_anchor(test_data.user_token_account) + .await; + + // NOTE: we transfer 105, but only 100 gets burned (token is 9 decimals, and + // gets normalised to 8) + // TODO: should we just revert if there's dust? + assert_eq!(mint_before.supply - 100, mint_after.supply); + assert_eq!( + token_account_before.amount - 100, + token_account_after.amount + ); +} + +#[tokio::test] +async fn locking_mode_locks_tokens() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let outbox_item = Keypair::new(); + + let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 105, false); + + let token_account_before: TokenAccount = ctx + .get_account_data_anchor(test_data.user_token_account) + .await; + + let custody_account_before: TokenAccount = ctx + .get_account_data_anchor(test_data.ntt.custody(&test_data.mint)) + .await; + + let mint_before: Mint = ctx.get_account_data_anchor(test_data.mint).await; + + transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); + + let token_account_after: TokenAccount = ctx + .get_account_data_anchor(test_data.user_token_account) + .await; + + let custody_account_after: TokenAccount = ctx + .get_account_data_anchor(test_data.ntt.custody(&test_data.mint)) + .await; + + let mint_after: Mint = ctx.get_account_data_anchor(test_data.mint).await; + + // NOTE: we transfer 105, but only 100 gets locked (token is 9 decimals, and + // gets normalised to 8) + + assert_eq!( + token_account_before.amount - 100, + token_account_after.amount + ); + + assert_eq!( + custody_account_before.amount + 100, + custody_account_after.amount + ); + + assert_eq!(mint_before.supply, mint_after.supply); +} + +#[tokio::test] +async fn test_rate_limit() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let outbox_item = Keypair::new(); + let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); + + let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 100, false); + + let outbound_limit_before: OutboxRateLimit = ctx + .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) + .await; + + transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); + + let outbound_limit_after: OutboxRateLimit = ctx + .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) + .await; + + assert_eq!(NormalizedAmount::normalize(100, 9).amount, 10); + + assert_eq!( + outbound_limit_before.capacity_at(clock.unix_timestamp) + - NormalizedAmount::normalize(100, 9), + outbound_limit_after.capacity_at(clock.unix_timestamp) + ); +} + +#[tokio::test] +async fn test_transfer_wrong_mode() { + let (mut ctx, test_data) = setup(Mode::Burning).await; + let outbox_item = Keypair::new(); + + let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 100, false); + + // make sure we can't transfer in the wrong mode + let err = transfer(&test_data.ntt, accs.clone(), args.clone(), Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap_err(); + + assert_eq!( + err.unwrap(), + TransactionError::InstructionError( + 0, + InstructionError::Custom(NTTError::InvalidMode.into()) + ) + ); +} + +async fn assert_queued(ctx: &mut ProgramTestContext, outbox_item: Pubkey) { + let outbox_item_account: OutboxItem = ctx.get_account_data_anchor(outbox_item).await; + + let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); + + assert!(!outbox_item_account.released); + assert!(outbox_item_account.release_timestamp > clock.unix_timestamp); +} + +#[tokio::test] +async fn test_large_tx_queue() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let outbox_item = Keypair::new(); + + let too_much = OUTBOUND_LIMIT + 1000; + let should_queue = true; + let (accs, args) = init_accs_args( + &mut ctx, + &test_data, + outbox_item.pubkey(), + too_much, + should_queue, + ); + + let outbound_limit_before: OutboxRateLimit = ctx + .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) + .await; + + transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); + + let outbound_limit_after: OutboxRateLimit = ctx + .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) + .await; + + assert_queued(&mut ctx, outbox_item.pubkey()).await; + + // queued transfers don't change the rate limit + assert_eq!(outbound_limit_before, outbound_limit_after); +} + +#[tokio::test] +async fn test_large_tx_no_queue() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let outbox_item = Keypair::new(); + + let too_much = OUTBOUND_LIMIT + 1000; + let should_queue = false; + let (accs, args) = init_accs_args( + &mut ctx, + &test_data, + outbox_item.pubkey(), + too_much, + should_queue, + ); + + let err = transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap_err(); + + assert_eq!( + err.unwrap(), + TransactionError::InstructionError( + 0, + InstructionError::Custom(NTTError::TransferExceedsRateLimit.into()) + ) + ); +} + +#[tokio::test] +async fn test_cant_release_queued() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let outbox_item = Keypair::new(); + + let too_much = OUTBOUND_LIMIT + 1000; + let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), too_much, true); + + transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); + + assert_queued(&mut ctx, outbox_item.pubkey()).await; + + // check that 'revert_on_delay = true' returns correct error + let err = release_outbound( + &test_data.ntt, + ReleaseOutbound { + payer: ctx.payer.pubkey(), + outbox_item: outbox_item.pubkey(), + }, + ReleaseOutboundArgs { + revert_on_delay: true, + }, + ) + .submit(&mut ctx) + .await + .unwrap_err(); + + assert_eq!( + err.unwrap(), + TransactionError::InstructionError( + 0, + InstructionError::Custom(NTTError::ReleaseTimestampNotReached.into()) + ) + ); + + // check that 'revert_on_delay = false' succeeds but does not release + release_outbound( + &test_data.ntt, + ReleaseOutbound { + payer: ctx.payer.pubkey(), + outbox_item: outbox_item.pubkey(), + }, + ReleaseOutboundArgs { + revert_on_delay: false, + }, + ) + .submit(&mut ctx) + .await + .unwrap(); + + assert_queued(&mut ctx, outbox_item.pubkey()).await; + + // just to be safe, let's make sure the wormhole message account wasn't initialised + let wh_message = test_data.ntt.wormhole_message(&outbox_item.pubkey()); + assert!(ctx + .banks_client + .get_account(wh_message) + .await + .unwrap() + .is_none()); +} + +#[tokio::test] +async fn test_cant_release_twice() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let outbox_item = Keypair::new(); + + let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 100, false); + + transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); + + release_outbound( + &test_data.ntt, + ReleaseOutbound { + payer: ctx.payer.pubkey(), + outbox_item: outbox_item.pubkey(), + }, + ReleaseOutboundArgs { + revert_on_delay: true, + }, + ) + .submit(&mut ctx) + .await + .unwrap(); + + // make sure we can't release again + let err = release_outbound( + &test_data.ntt, + ReleaseOutbound { + payer: ctx.payer.pubkey(), + outbox_item: outbox_item.pubkey(), + }, + ReleaseOutboundArgs { + revert_on_delay: true, + }, + ) + .submit(&mut ctx) + .await + .unwrap_err(); + + assert_eq!( + err.unwrap(), + TransactionError::InstructionError( + 0, + InstructionError::Custom(NTTError::MessageAlreadySent.into()) + ) + ); +} From 7837e463e18d17170e1c9ba842c3fc09f2c3ca8b Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 14 Feb 2024 22:54:53 +0400 Subject: [PATCH 39/90] solana: sender/recipient is token authority the actual token account is the ATA instead of allowing any token account to be specified --- .../src/instructions/release_inbound.rs | 6 ++---- .../src/instructions/transfer.rs | 4 +--- .../tests/transfer.rs | 4 ++-- solana/tests/example-native-token-transfer.ts | 2 +- solana/ts/sdk/index.ts | 13 +++++++++---- 5 files changed, 15 insertions(+), 14 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index c7d758244..b6ea0679c 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -18,11 +18,9 @@ pub struct ReleaseInbound<'info> { #[account( mut, - address = inbox_item.recipient_address, + associated_token::authority = inbox_item.recipient_address, + associated_token::mint = mint )] - /// CHECK: the address is checked to match the recipient address in the - /// inbox item - /// TODO: send to ATA? pub recipient: InterfaceAccount<'info, token_interface::TokenAccount>, #[account( diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 416150649..96f3da2c9 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -225,9 +225,7 @@ fn insert_into_outbox( common.outbox_item.set_inner(OutboxItem { sequence, amount, - // TODO: this is the token account itself. should we use the authority - // instead? (and enforce ATAs) - sender: common.from.key(), + sender: common.from_authority.key(), recipient_chain, recipient_address, release_timestamp, diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 14b613f11..f3e4c500d 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -107,7 +107,7 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: amount: 10, decimals: 8 }, - sender: test_data.user_token_account, + sender: test_data.user.pubkey(), recipient_chain: ChainId { id: 2 }, recipient_address: [1u8; 32], release_timestamp: clock.unix_timestamp, @@ -159,7 +159,7 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: chain_id: ChainId { id: 1 }, sequence: sequence.sequence, source_manager: example_native_token_transfers::ID.to_bytes(), - sender: test_data.user_token_account.to_bytes(), + sender: test_data.user.pubkey().to_bytes(), payload: NativeTokenTransfer { amount: NormalizedAmount { amount: 10, diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index 09d793131..d494edb33 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -145,7 +145,7 @@ describe('example-native-token-transfers', () => { Buffer.from('FAFA'.padStart(64, '0'), 'hex'), new NormalizedAmount(BigInt(10000), 8), toChainId('solana'), - tokenAccount.toBuffer() + user.publicKey.toBuffer() ) ) } diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 8e1a88278..505a1ba5e 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -2,6 +2,7 @@ import { type ChainName, toChainId, coalesceChainId, type ChainId, SignedVaa, pa import { derivePostedVaaKey, getWormholeDerivedAccounts } from '@certusone/wormhole-sdk/lib/cjs/solana/wormhole' import { BN, translateError, type IdlAccounts, type Program } from '@coral-xyz/anchor' import { associatedAddress } from '@coral-xyz/anchor/dist/cjs/utils/token' +import { getAssociatedTokenAddressSync } from '@solana/spl-token' import { type PublicKeyInitData, PublicKey, Keypair, @@ -363,6 +364,8 @@ export class NTT { const recipientAddress = args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress + const mint = await this.mintAccountAddress(config) + return await this.program.methods .releaseInboundMint({ revertOnDelay: args.revertOnDelay @@ -372,8 +375,8 @@ export class NTT { payer: args.payer, config: { config: this.configAccountAddress() }, inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), - recipient: recipientAddress, - mint: await this.mintAccountAddress(config), + recipient: getAssociatedTokenAddressSync(mint, recipientAddress), + mint, tokenAuthority: this.tokenAuthorityAddress(), }, }) @@ -420,6 +423,8 @@ export class NTT { const recipientAddress = args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress + const mint = await this.mintAccountAddress(config) + return await this.program.methods .releaseInboundUnlock({ revertOnDelay: args.revertOnDelay @@ -429,8 +434,8 @@ export class NTT { payer: args.payer, config: { config: this.configAccountAddress() }, inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), - recipient: recipientAddress, - mint: await this.mintAccountAddress(config), + recipient: getAssociatedTokenAddressSync(mint, recipientAddress), + mint, tokenAuthority: this.tokenAuthorityAddress(), }, custody: await this.custodyAccountAddress(config) From 3aafc9837134d49cbd9c6baacd06a22f38725e0e Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 14 Feb 2024 23:35:38 +0400 Subject: [PATCH 40/90] solana: fix denormalisation when the normalised decimals are less than 8 --- .../src/normalized_amount.rs | 21 +++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index 389d285a1..e4d5865f5 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -65,24 +65,24 @@ impl NormalizedAmount { } } - fn scaling_factor(orig_decimals: u8, norm_decimals: u8) -> u64 { - if orig_decimals > norm_decimals { - 10u64.pow((orig_decimals - norm_decimals).into()) + fn scale(amount: u64, from_decimals: u8, to_decimals: u8) -> u64 { + if from_decimals > to_decimals { + amount / 10u64.pow((from_decimals - to_decimals).into()) } else { - 1 + amount * 10u64.pow((to_decimals - from_decimals).into()) } } pub fn normalize(amount: u64, from_decimals: u8) -> NormalizedAmount { let to_decimals = NORMALIZED_DECIMALS.min(from_decimals); Self { - amount: amount / Self::scaling_factor(from_decimals, to_decimals), + amount: Self::scale(amount, from_decimals, to_decimals), decimals: to_decimals, } } pub fn denormalize(&self, to_decimals: u8) -> u64 { - self.amount * Self::scaling_factor(to_decimals, self.decimals) + Self::scale(self.amount, self.decimals, to_decimals) } pub fn amount(&self) -> u64 { @@ -142,5 +142,14 @@ mod test { NormalizedAmount::normalize(100_555_555_555_555_555, 18).denormalize(18), 100_555_550_000_000_000 ); + + assert_eq!( + NormalizedAmount { + amount: 1, + decimals: 6, + } + .denormalize(13), + 10000000 + ); } } From 5a0de113bd42e73e126a6a2f860b34797f976e4e Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 14 Feb 2024 23:49:28 +0400 Subject: [PATCH 41/90] solana: allow redeeming when paused --- .../example-native-token-transfers/src/instructions/redeem.rs | 3 ++- solana/ts/sdk/index.ts | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index f9cd53328..54d89aef1 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -20,7 +20,8 @@ pub struct Redeem<'info> { #[account(mut)] pub payer: Signer<'info>, - pub config: NotPausedConfig<'info>, + // NOTE: this works when the contract is paused + pub config: Account<'info, Config>, #[account( seeds = [Sibling::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 505a1ba5e..27b8cd587 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -521,7 +521,7 @@ export class NTT { .redeem({}) .accounts({ payer: args.payer, - config: { config: this.configAccountAddress() }, + config: this.configAccountAddress(), sibling, vaa: derivePostedVaaKey(this.wormholeId, parseVaa(args.vaa).hash), inboxItem: this.inboxItemAccountAddress(chainId, new BN(managerMessage.sequence.toString())), From cddc661129d5ae8fcd3723b1bac161e28cb85a0b Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 02:28:07 +0400 Subject: [PATCH 42/90] solana: adjust decimals instead of assert equality in operations on normalized amounts --- .../src/instructions/redeem.rs | 2 + .../src/normalized_amount.rs | 59 ++++++++++++++++--- 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 54d89aef1..f0ee70747 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -81,6 +81,8 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let message: ManagerMessage = accs.vaa.message().manager_payload.clone(); let amount = message.payload.amount; + let amount = amount.change_decimals(accs.outbox_rate_limit.rate_limit.limit.decimals); + let recipient_address = Pubkey::try_from(message.payload.to).map_err(|_| NTTError::InvalidRecipientAddress)?; diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index e4d5865f5..87884a2fd 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -18,11 +18,6 @@ pub const NORMALIZED_DECIMALS: u8 = 8; Debug, Clone, Copy, - PartialEq, - Eq, - // TODO: manually write this and make sure the decimals are the same - PartialOrd, - Ord, AnchorSerialize, AnchorDeserialize, InitSpace, @@ -32,11 +27,32 @@ pub struct NormalizedAmount { pub decimals: u8, } +impl PartialEq for NormalizedAmount { + fn eq(&self, other: &Self) -> bool { + self.amount == other.change_decimals(self.decimals).amount + } +} + +impl Eq for NormalizedAmount {} + +impl PartialOrd for NormalizedAmount { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for NormalizedAmount { + fn cmp(&self, other: &Self) -> std::cmp::Ordering { + let other = other.change_decimals(self.decimals); + self.amount.cmp(&other.amount) + } +} + impl Sub for NormalizedAmount { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { - assert_eq!(self.decimals, rhs.decimals); + let rhs = rhs.change_decimals(self.decimals); Self { amount: self.amount - rhs.amount, decimals: self.decimals, @@ -50,7 +66,7 @@ impl NormalizedAmount { } pub fn saturating_sub(self, rhs: Self) -> Self { - assert_eq!(self.decimals, rhs.decimals); + let rhs = rhs.change_decimals(self.decimals); Self { amount: self.amount.saturating_sub(rhs.amount), decimals: self.decimals, @@ -58,14 +74,27 @@ impl NormalizedAmount { } pub fn saturating_add(self, rhs: Self) -> Self { - assert_eq!(self.decimals, rhs.decimals); + let rhs = rhs.change_decimals(self.decimals); Self { amount: self.amount.saturating_add(rhs.amount), decimals: self.decimals, } } + pub fn change_decimals(&self, new_decimals: u8) -> Self { + if new_decimals == self.decimals { + return *self; + } + Self { + amount: self.denormalize(new_decimals), + decimals: new_decimals, + } + } + fn scale(amount: u64, from_decimals: u8, to_decimals: u8) -> u64 { + if from_decimals == to_decimals { + return amount; + } if from_decimals > to_decimals { amount / 10u64.pow((from_decimals - to_decimals).into()) } else { @@ -151,5 +180,19 @@ mod test { .denormalize(13), 10000000 ); + + assert_eq!( + NormalizedAmount { + amount: 2, + decimals: 5, + } - NormalizedAmount { + amount: 10, + decimals: 6, + }, + NormalizedAmount { + amount: 1, + decimals: 5, + } + ); } } From 22b583caf01536ab03e3346d4145998d60d5d5dc Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 02:46:49 +0400 Subject: [PATCH 43/90] solana: test cancel flows --- .../src/instructions/admin.rs | 1 + .../src/instructions/redeem.rs | 1 + .../src/queue/rate_limit.rs | 2 +- .../tests/cancel_flow.rs | 231 ++++++++++++++++++ .../tests/common/hack.rs | 44 ++++ .../tests/common/mod.rs | 1 + .../tests/common/setup.rs | 19 +- .../tests/sdk/instructions/mod.rs | 1 + .../tests/sdk/instructions/redeem.rs | 35 +++ .../tests/transfer.rs | 2 +- 10 files changed, 332 insertions(+), 5 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/tests/cancel_flow.rs create mode 100644 solana/programs/example-native-token-transfers/tests/common/hack.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index c2e8d7818..5c79461f1 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -57,6 +57,7 @@ pub fn claim_ownership(ctx: Context) -> Result<()> { // TODO: update siblings? should that be a separate instruction? take timestamp // for modification? (for total ordering) +// TODO: this should set the *manager* sibling, not the endpoint one #[derive(Accounts)] #[instruction(args: SetSiblingArgs)] pub struct SetSibling<'info> { diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index f0ee70747..52203cb84 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -67,6 +67,7 @@ pub struct Redeem<'info> { )] pub inbox_rate_limit: Account<'info, InboxRateLimit>, + #[account(mut)] pub outbox_rate_limit: Account<'info, OutboxRateLimit>, pub system_program: Program<'info, System>, diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index 97c578854..b13c12d3f 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -98,7 +98,7 @@ impl RateLimitState { /// This is used to replenish the capacity via backflows. pub fn refill(&mut self, amount: NormalizedAmount) { self.capacity_at_last_tx = self - .capacity_at_last_tx + .capacity() .saturating_add(amount) .min(self.limit); self.last_tx_timestamp = current_timestamp(); diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs new file mode 100644 index 000000000..b34d02e76 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -0,0 +1,231 @@ +#![feature(type_changing_struct_update)] +#![feature(async_fn_in_trait)] + +use anchor_lang::{ + prelude::{Clock, Pubkey}, + AccountSerialize, +}; +use common::setup::TestData; +use example_native_token_transfers::{ + chain_id::ChainId, + config::Mode, + instructions::{RedeemArgs, TransferArgs}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, + normalized_amount::NormalizedAmount, + queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit}, +}; +use solana_program_test::*; +use solana_sdk::{account::Account, signature::Keypair, signer::Signer}; +use wormhole_io::TypePrefixedPayload; + +use crate::{ + common::{hack::PostedVaaHack, query::GetAccountDataAnchor}, + sdk::instructions::{ + redeem::{redeem, Redeem}, + transfer::Transfer, + }, +}; +use crate::{ + common::{setup::setup_with_extra_accounts, submit::Submittable}, + sdk::instructions::transfer::transfer, +}; + +pub mod common; +pub mod sdk; + +const THIS_CHAIN: u16 = 1; +const OTHER_CHAIN: u16 = 2; + +fn init_transfer_accs_args( + ctx: &mut ProgramTestContext, + test_data: &TestData, + outbox_item: Pubkey, + amount: u64, + should_queue: bool, +) -> (Transfer, TransferArgs) { + let accs = Transfer { + payer: ctx.payer.pubkey(), + mint: test_data.mint, + from: test_data.user_token_account, + from_authority: test_data.user.pubkey(), + outbox_item, + }; + + let args = TransferArgs { + amount, + recipient_chain: ChainId { id: OTHER_CHAIN }, + recipient_address: [1u8; 32], + should_queue, + }; + + (accs, args) +} + +fn init_redeem_accs( + ctx: &mut ProgramTestContext, + test_data: &TestData, + vaa: Pubkey, + chain_id: u16, + sequence: u64, +) -> Redeem { + let accs = Redeem { + payer: ctx.payer.pubkey(), + sibling: test_data.ntt.sibling(chain_id), + vaa, + inbox_item: test_data.ntt.inbox_item(chain_id, sequence), + inbox_rate_limit: test_data.ntt.inbox_rate_limit(chain_id), + }; + + accs +} + +/// helper function to write into vaa accounts. +/// this is mostly to avoid having to go through the process of posting the vaa +/// via the wormhole program +/// TODO: in an ideal world it should be very easy to do that, but the sdk +/// doesn't support posting vaas yet. +/// TODO: in an ideal world, writing into these accounts should be even easier, but +/// the sdk doesn't have a working serializer implementation for the vaa account either +fn make_vaa(sequence: u64, amount: u64, recipient: &Keypair) -> (Pubkey, Account) { + let vaa = Keypair::new(); + let endpoint_message: EndpointMessage = + EndpointMessage::new(ManagerMessage { + chain_id: ChainId { id: OTHER_CHAIN }, + sequence, + source_manager: [5u8; 32], + sender: [4u8; 32], + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount, + decimals: 9, + }, + source_token: [3u8; 32], + to_chain: ChainId { id: THIS_CHAIN }, + to: recipient.pubkey().to_bytes(), + }, + }); + + let payload = endpoint_message.to_vec_payload(); + + let vaa_data = PostedVaaHack { + vaa_version: 1, + consistency_level: 32, + vaa_time: 0, + vaa_signature_account: Keypair::new().pubkey(), + submission_time: 0, + nonce: 0, + sequence, + emitter_chain: OTHER_CHAIN, + emitter_address: [7u8; 32], + payload, + }; + + let mut serialized = vec![]; + vaa_data.try_serialize(&mut serialized).unwrap(); + + let vaa_account: Account = Account { + lamports: 1000000, + data: serialized, + owner: wormhole_anchor_sdk::wormhole::program::id(), + executable: false, + rent_epoch: u64::MAX, + }; + + (vaa.pubkey(), vaa_account) +} + +async fn outbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> u64 { + let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); + let rate_limit: OutboxRateLimit = ctx + .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) + .await; + + rate_limit + .rate_limit + .capacity_at(clock.unix_timestamp) + .denormalize(9) +} + +async fn inbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> u64 { + let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); + let rate_limit: InboxRateLimit = ctx + .get_account_data_anchor(test_data.ntt.inbox_rate_limit(OTHER_CHAIN)) + .await; + + rate_limit + .rate_limit + .capacity_at(clock.unix_timestamp) + .denormalize(9) +} + +#[tokio::test] +async fn test_cancel() { + let recipient = Keypair::new(); + let (vaa0, vaa_account0) = make_vaa(0, 1000, &recipient); + let (vaa1, vaa_account1) = make_vaa(1, 2000, &recipient); + let (mut ctx, test_data) = + setup_with_extra_accounts(Mode::Locking, &[(vaa0, vaa_account0), (vaa1, vaa_account1)]) + .await; + + let inbound_limit_before = inbound_capacity(&mut ctx, &test_data).await; + let outbound_limit_before = outbound_capacity(&mut ctx, &test_data).await; + + redeem( + &test_data.ntt, + init_redeem_accs(&mut ctx, &test_data, vaa0, 2, 0), + RedeemArgs {}, + ) + .submit(&mut ctx) + .await + .unwrap(); + + assert_eq!( + outbound_limit_before, + outbound_capacity(&mut ctx, &test_data).await + ); + + assert_eq!( + inbound_limit_before - 1000, + inbound_capacity(&mut ctx, &test_data).await + ); + + let outbox_item = Keypair::new(); + + let (accs, args) = + init_transfer_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 7000, true); + + transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); + + assert_eq!( + outbound_limit_before - 7000, + outbound_capacity(&mut ctx, &test_data).await + ); + + // fully replenished + assert_eq!( + inbound_limit_before, + inbound_capacity(&mut ctx, &test_data).await + ); + + redeem( + &test_data.ntt, + init_redeem_accs(&mut ctx, &test_data, vaa1, OTHER_CHAIN, 1), + RedeemArgs {}, + ) + .submit(&mut ctx) + .await + .unwrap(); + + assert_eq!( + outbound_limit_before - 5000, + outbound_capacity(&mut ctx, &test_data).await + ); + + assert_eq!( + inbound_limit_before - 2000, + inbound_capacity(&mut ctx, &test_data).await + ); +} diff --git a/solana/programs/example-native-token-transfers/tests/common/hack.rs b/solana/programs/example-native-token-transfers/tests/common/hack.rs new file mode 100644 index 000000000..52dfdb192 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/common/hack.rs @@ -0,0 +1,44 @@ +use anchor_lang::prelude::*; + +#[derive(Debug, Default, AnchorSerialize, AnchorDeserialize, Clone)] +// TODO: copy pasted this struct as the sdk version doesn't have a working +// serializer implementation +pub struct PostedVaaHack { + /// Header of the posted VAA + pub vaa_version: u8, + + /// Level of consistency requested by the emitter + pub consistency_level: u8, + + /// Time the vaa was submitted + pub vaa_time: u32, + + /// Account where signatures are stored + pub vaa_signature_account: Pubkey, + + /// Time the posted message was created + pub submission_time: u32, + + /// Unique nonce for this message + pub nonce: u32, + + /// Sequence number of this message + pub sequence: u64, + + /// Emitter of the message + pub emitter_chain: u16, + + /// Emitter of the message + pub emitter_address: [u8; 32], + + /// Message payload + pub payload: A, +} + +impl AccountSerialize for PostedVaaHack { + fn try_serialize(&self, writer: &mut W) -> Result<()> { + writer.write(b"vaa")?; + Self::serialize(self, writer)?; + Ok(()) + } +} diff --git a/solana/programs/example-native-token-transfers/tests/common/mod.rs b/solana/programs/example-native-token-transfers/tests/common/mod.rs index 5c1f8f0ca..b430fd2c8 100644 --- a/solana/programs/example-native-token-transfers/tests/common/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/common/mod.rs @@ -3,3 +3,4 @@ pub mod account_json_utils; pub mod query; pub mod setup; pub mod submit; +pub mod hack; diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index 3d515fa92..5b21bcfa0 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -7,7 +7,8 @@ use example_native_token_transfers::{ }; use solana_program_test::{ProgramTest, ProgramTestContext}; use solana_sdk::{ - signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, + account::Account, signature::Keypair, signer::Signer, system_instruction, + transaction::Transaction, }; use spl_associated_token_account::get_associated_token_address_with_program_id; use spl_token::instruction::AuthorityType; @@ -41,8 +42,16 @@ pub struct TestData { pub user_token_account: Pubkey, } -pub async fn setup(mode: Mode) -> (ProgramTestContext, TestData) { - let program_test = setup_programs().await.unwrap(); +pub async fn setup_with_extra_accounts( + mode: Mode, + accounts: &[(Pubkey, Account)], +) -> (ProgramTestContext, TestData) { + let mut program_test = setup_programs().await.unwrap(); + + for (pubkey, account) in accounts { + program_test.add_account(*pubkey, account.clone()); + } + let mut ctx = program_test.start_with_context().await; let test_data = setup_accounts(&mut ctx).await; @@ -51,6 +60,10 @@ pub async fn setup(mode: Mode) -> (ProgramTestContext, TestData) { return (ctx, test_data); } +pub async fn setup(mode: Mode) -> (ProgramTestContext, TestData) { + setup_with_extra_accounts(mode, &[]).await +} + pub async fn setup_programs() -> Result { let mut program_test = ProgramTest::default(); program_test.add_program( diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs index 25361f827..559c09d4e 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs @@ -1,4 +1,5 @@ pub mod admin; pub mod initialize; +pub mod redeem; pub mod release_outbound; pub mod transfer; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs new file mode 100644 index 000000000..df460fdb1 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs @@ -0,0 +1,35 @@ +use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; +use example_native_token_transfers::instructions::RedeemArgs; +use solana_sdk::instruction::Instruction; + +use crate::sdk::accounts::NTT; + +#[derive(Debug, Clone)] +pub struct Redeem { + pub payer: Pubkey, + pub sibling: Pubkey, + pub vaa: Pubkey, + pub inbox_item: Pubkey, + pub inbox_rate_limit: Pubkey, +} + +pub fn redeem(ntt: &NTT, accs: Redeem, args: RedeemArgs) -> Instruction { + let data = example_native_token_transfers::instruction::Redeem { args }; + + let accounts = example_native_token_transfers::accounts::Redeem { + payer: accs.payer, + config: ntt.config(), + sibling: accs.sibling, + vaa: accs.vaa, + inbox_item: accs.inbox_item, + inbox_rate_limit: accs.inbox_rate_limit, + outbox_rate_limit: ntt.outbox_rate_limit(), + system_program: System::id(), + }; + + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index f3e4c500d..3663f1182 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -38,8 +38,8 @@ use crate::common::setup::setup; // TODO: some more tests // - unregistered sibling can't transfer // - can't transfer more than balance -// - cancel flows // - wrong inbox accounts +// - paused contracts /// Helper function for setting up transfer accounts and args. /// It sets the accounts up properly, so for negative testing we just modify the From abd423777dbcd4428a9ab2613857c2c36a75c24a Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 03:11:49 +0400 Subject: [PATCH 44/90] solana: test pausing --- .../src/config.rs | 2 +- .../src/error.rs | 2 + .../src/instructions/admin.rs | 1 + .../example-native-token-transfers/src/lib.rs | 4 ++ .../tests/sdk/instructions/admin.rs | 19 +++++++ .../tests/transfer.rs | 55 ++++++++++++++++++- 6 files changed, 81 insertions(+), 2 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 2a81c136e..de95f7411 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -36,7 +36,7 @@ impl Config { #[derive(Accounts)] pub struct NotPausedConfig<'info> { #[account( - constraint = !config.paused + constraint = !config.paused @ crate::error::NTTError::Paused, )] config: Account<'info, Config>, } diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index f6d7b2742..db19b787e 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -21,4 +21,6 @@ pub enum NTTError { InvalidMintAuthority, #[msg("TransferExceedsRateLimit")] TransferExceedsRateLimit, + #[msg("Paused")] + Paused, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 5c79461f1..468fac216 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -200,6 +200,7 @@ pub fn set_inbound_limit(ctx: Context, args: SetInboundLimitArg #[derive(Accounts)] pub struct SetPaused<'info> { #[account( + mut, has_one = owner, )] pub config: Account<'info, Config>, diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 9f6e30ac4..2ead6cea5 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -62,6 +62,10 @@ pub mod example_native_token_transfers { instructions::claim_ownership(ctx) } + pub fn set_paused(ctx: Context, pause: bool) -> Result<()> { + instructions::set_paused(ctx, pause) + } + pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> { instructions::set_sibling(ctx, args) } diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs index 29c284f7a..58c3c8fc6 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs @@ -30,3 +30,22 @@ pub fn set_sibling(ntt: &NTT, accounts: SetSibling, args: SetSiblingArgs) -> Ins data: data.data(), } } + +pub struct SetPaused { + pub owner: Pubkey, +} + +pub fn set_paused(ntt: &NTT, accounts: SetPaused, pause: bool) -> Instruction { + let data = example_native_token_transfers::instruction::SetPaused { pause }; + + let accounts = example_native_token_transfers::accounts::SetPaused { + config: ntt.config(), + owner: accounts.owner, + }; + + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 3663f1182..c2a152f12 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -21,7 +21,13 @@ use solana_sdk::{ }; use wormhole_anchor_sdk::wormhole::PostedVaa; -use crate::{common::submit::Submittable, sdk::instructions::transfer::transfer}; +use crate::{ + common::submit::Submittable, + sdk::instructions::{ + admin::{set_paused, SetPaused}, + transfer::transfer, + }, +}; use crate::{ common::{query::GetAccountDataAnchor, setup::OUTBOUND_LIMIT}, sdk::instructions::{ @@ -357,6 +363,53 @@ async fn test_large_tx_queue() { assert_eq!(outbound_limit_before, outbound_limit_after); } +#[tokio::test] +async fn test_cant_transfer_when_paused() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let outbox_item = Keypair::new(); + + let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 100, false); + + set_paused( + &test_data.ntt, + SetPaused { + owner: test_data.program_owner.pubkey(), + }, + true, + ) + .submit_with_signers(&[&test_data.program_owner], &mut ctx) + .await + .unwrap(); + + let err = transfer(&test_data.ntt, accs.clone(), args.clone(), Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap_err(); + + assert_eq!( + err.unwrap(), + TransactionError::InstructionError(0, InstructionError::Custom(NTTError::Paused.into())) + ); + + // make sure we can unpause + set_paused( + &test_data.ntt, + SetPaused { + owner: test_data.program_owner.pubkey(), + }, + false, + ) + .submit_with_signers(&[&test_data.program_owner], &mut ctx) + .await + .unwrap(); + + transfer(&test_data.ntt, accs, args, Mode::Locking) + .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) + .await + .unwrap(); +} + #[tokio::test] async fn test_large_tx_no_queue() { let (mut ctx, test_data) = setup(Mode::Locking).await; From 69d061a540692418bb40e840f88be012f79120dd Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 13:36:24 +0400 Subject: [PATCH 45/90] solana: update structs (+ wire format) to match solidity impl --- .../src/instructions/redeem.rs | 4 +- .../src/instructions/release_outbound.rs | 11 +++-- .../src/messages.rs | 47 +++++++++---------- .../tests/cancel_flow.rs | 27 ++++++----- .../tests/transfer.rs | 29 ++++++------ solana/tests/example-native-token-transfer.ts | 3 +- solana/ts/sdk/index.ts | 4 +- solana/ts/sdk/payloads/common.ts | 41 ++++++++-------- 8 files changed, 79 insertions(+), 87 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 52203cb84..734d880b5 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -31,8 +31,6 @@ pub struct Redeem<'info> { pub sibling: Account<'info, Sibling>, #[account( - // check that the VAA's emitter agrees with what's in the message - constraint = vaa.emitter_chain() == vaa.message().manager_payload.chain_id.id @ NTTError::InvalidChainId, // check that the messages is targeted to this chain constraint = vaa.message().manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, // NOTE: we don't replay protect VAAs. Instead, we replay protect @@ -46,7 +44,7 @@ pub struct Redeem<'info> { space = 8 + InboxItem::INIT_SPACE, seeds = [ InboxItem::SEED_PREFIX, - vaa.message().manager_payload.chain_id.id.to_be_bytes().as_ref(), + vaa.emitter_chain().to_be_bytes().as_ref(), vaa.message().manager_payload.sequence.to_be_bytes().as_ref(), ], bump, diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 66388082e..49efccb1f 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -83,11 +83,11 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs } assert!(accs.outbox_item.released); - let message: EndpointMessage = - EndpointMessage::new(ManagerMessage { - chain_id: accs.config.chain_id, + let message: EndpointMessage = EndpointMessage::new( + // TODO: should we just put the ntt id here statically? + accs.outbox_item.to_account_info().owner.to_bytes(), + ManagerMessage { sequence: accs.outbox_item.sequence, - source_manager: accs.outbox_item.to_account_info().owner.to_bytes(), sender: accs.outbox_item.sender.to_bytes(), payload: NativeTokenTransfer { amount: accs.outbox_item.amount, @@ -95,7 +95,8 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs to: accs.outbox_item.recipient_address.clone(), to_chain: accs.outbox_item.recipient_chain, }, - }); + }, + ); if accs.wormhole_bridge.fee() > 0 { anchor_lang::system_program::transfer( diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index baa954076..b77aceb3d 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -10,10 +10,7 @@ use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; #[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] pub struct ManagerMessage { - pub chain_id: ChainId, pub sequence: u64, - // TODO: check sibling registration at the manager level - pub source_manager: [u8; 32], pub sender: [u8; 32], pub payload: A, } @@ -30,18 +27,14 @@ impl Readable for ManagerMessage { Self: Sized, R: io::Read, { - let chain_id = Readable::read(reader)?; let sequence = Readable::read(reader)?; - let source_manager = Readable::read(reader)?; let sender = Readable::read(reader)?; // TODO: same as below for manager payload let _payload_len: u16 = Readable::read(reader)?; let payload = A::read_payload(reader)?; Ok(Self { - chain_id, sequence, - source_manager, sender, payload, }) @@ -50,9 +43,7 @@ impl Readable for ManagerMessage { impl Writeable for ManagerMessage { fn written_size(&self) -> usize { - ChainId::SIZE.unwrap() - + u64::SIZE.unwrap() - + self.source_manager.len() + u64::SIZE.unwrap() + self.sender.len() + u16::SIZE.unwrap() // payload length + self.payload.written_size() @@ -63,16 +54,12 @@ impl Writeable for ManagerMessage { W: io::Write, { let ManagerMessage { - chain_id, sequence, - source_manager, sender, payload, } = self; - chain_id.write(writer)?; sequence.write(writer)?; - writer.write_all(source_manager)?; writer.write_all(sender)?; let len: u16 = u16::try_from(payload.written_size()).expect("u16 overflow"); len.write(writer)?; @@ -173,6 +160,8 @@ impl Endpoint for WormholeEndpoint { #[derive(PartialEq, Eq)] pub struct EndpointMessage { _phantom: PhantomData, + // TODO: check sibling registration at the manager level + pub source_manager: [u8; 32], pub manager_payload: ManagerMessage, } @@ -206,15 +195,17 @@ where fn clone(&self) -> Self { Self { _phantom: PhantomData, + source_manager: self.source_manager.clone(), manager_payload: self.manager_payload.clone(), } } } impl EndpointMessage { - pub fn new(manager_payload: ManagerMessage) -> Self { + pub fn new(source_manager: [u8; 32], manager_payload: ManagerMessage) -> Self { Self { _phantom: PhantomData, + source_manager, manager_payload, } } @@ -239,20 +230,23 @@ impl Readable for EndpointMessag "Invalid prefix for EndpointMessage", )); } + + let source_manager = Readable::read(reader)?; // TODO: we need a way to easily check that decoding the payload // consumes the expected amount of bytes let _manager_payload_len: u16 = Readable::read(reader)?; let manager_payload = ManagerMessage::read(reader)?; - Ok(EndpointMessage::new(manager_payload)) + Ok(EndpointMessage::new(source_manager, manager_payload)) } } impl Writeable for EndpointMessage { fn written_size(&self) -> usize { - 4 + // prefix - u16::SIZE.unwrap() + // length prefix - self.manager_payload.written_size() + 4 // prefix + + self.source_manager.len() + + u16::SIZE.unwrap() // length prefix + + self.manager_payload.written_size() } fn write(&self, writer: &mut W) -> io::Result<()> @@ -261,10 +255,12 @@ impl Writeable for EndpointMess { let EndpointMessage { _phantom, + source_manager, manager_payload, } = self; E::PREFIX.write(writer)?; + source_manager.write(writer)?; let len: u16 = u16::try_from(manager_payload.written_size()).expect("u16 overflow"); len.write(writer)?; // TODO: review this in wormhole-io. The written_size logic is error prone. Instead, @@ -304,20 +300,19 @@ mod test { // #[test] fn test_deserialize_endpoint_message() { - let data = hex::decode("9945ff10009b0013000000367999a101042942fafabe00000000000000000000000000000000000000000000000000004667921341234300000000000000000000000000000000000000000000000000004f994e545408000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe000000000000000000000000000000000000000000000000000000000011").unwrap(); + let data = hex::decode("9945ff10042942fafabe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe000000000000000000000000000000000000000000000000000000000011").unwrap(); let mut vec = &data[..]; let message: EndpointMessage = TypePrefixedPayload::read_payload(&mut vec).unwrap(); let expected = EndpointMessage { _phantom: PhantomData::, + source_manager: [ + 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], manager_payload: ManagerMessage { - chain_id: ChainId { id: 19 }, sequence: 233968345345, - source_manager: [ - 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], sender: [ 0x46, 0x67, 0x92, 0x13, 0x41, 0x23, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -325,7 +320,7 @@ mod test { payload: NativeTokenTransfer { amount: NormalizedAmount { amount: 1234567, - decimals: 8, + decimals: 7, }, source_token: [ 0xBE, 0xEF, 0xFA, 0xCE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index b34d02e76..087bce79f 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -89,21 +89,22 @@ fn init_redeem_accs( fn make_vaa(sequence: u64, amount: u64, recipient: &Keypair) -> (Pubkey, Account) { let vaa = Keypair::new(); let endpoint_message: EndpointMessage = - EndpointMessage::new(ManagerMessage { - chain_id: ChainId { id: OTHER_CHAIN }, - sequence, - source_manager: [5u8; 32], - sender: [4u8; 32], - payload: NativeTokenTransfer { - amount: NormalizedAmount { - amount, - decimals: 9, + EndpointMessage::new( + [5u8; 32], + ManagerMessage { + sequence, + sender: [4u8; 32], + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount, + decimals: 9, + }, + source_token: [3u8; 32], + to_chain: ChainId { id: THIS_CHAIN }, + to: recipient.pubkey().to_bytes(), }, - source_token: [3u8; 32], - to_chain: ChainId { id: THIS_CHAIN }, - to: recipient.pubkey().to_bytes(), }, - }); + ); let payload = endpoint_message.to_vec_payload(); diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index c2a152f12..3057976d9 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -161,21 +161,22 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: assert_eq!( endpoint_message, - &EndpointMessage::new(ManagerMessage { - chain_id: ChainId { id: 1 }, - sequence: sequence.sequence, - source_manager: example_native_token_transfers::ID.to_bytes(), - sender: test_data.user.pubkey().to_bytes(), - payload: NativeTokenTransfer { - amount: NormalizedAmount { - amount: 10, - decimals: 8 - }, - source_token: test_data.mint.to_bytes(), - to: [1u8; 32], - to_chain: ChainId { id: 2 }, + &EndpointMessage::new( + example_native_token_transfers::ID.to_bytes(), + ManagerMessage { + sequence: sequence.sequence, + sender: test_data.user.pubkey().to_bytes(), + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount: 10, + decimals: 8 + }, + source_token: test_data.mint.to_bytes(), + to: [1u8; 32], + to_chain: ChainId { id: 2 }, + } } - }) + ) ); let next_sequence: Sequence = ctx.get_account_data_anchor(test_data.ntt.sequence()).await; diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index d494edb33..b98a6988a 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -136,10 +136,9 @@ describe('example-native-token-transfers', () => { const guardians = new MockGuardians(0, [GUARDIAN_KEY]) const sendingEndpointMessage: EndpointMessage = { + sourceManager: Buffer.from('BEEF'.padStart(64, '0'), 'hex'), managerPayload: new ManagerMessage( - toChainId('ethereum'), BigInt(0), - Buffer.from('BEEF'.padStart(64, '0'), 'hex'), Buffer.from('FACE'.padStart(64, '0'), 'hex'), new NativeTokenTransfer( Buffer.from('FAFA'.padStart(64, '0'), 'hex'), diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 27b8cd587..4d4941e31 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -512,7 +512,7 @@ export class NTT { ).managerPayload // NOTE: we do an 'as ChainId' cast here, which is generally unsafe. // TODO: explain why this is fine here - const chainId = managerMessage.chainId as ChainId + const chainId = parsedVaa.emitterChain as ChainId const sibling = this.siblingAccountAddress(chainId) const inboxRateLimit = this.inboxRateLimitAccountAddress(chainId) @@ -558,7 +558,7 @@ export class NTT { parsedVaa.payload, a => ManagerMessage.deserialize(a, NativeTokenTransfer.deserialize) ).managerPayload // TODO: explain why this is fine here - const chainId = managerMessage.chainId as ChainId + const chainId = parsedVaa.emitterChain as ChainId // Here we create a transaction with two instructions: // 1. redeem diff --git a/solana/ts/sdk/payloads/common.ts b/solana/ts/sdk/payloads/common.ts index 4bcdfdb4c..841fb9ee0 100644 --- a/solana/ts/sdk/payloads/common.ts +++ b/solana/ts/sdk/payloads/common.ts @@ -1,10 +1,13 @@ import { BN } from '@coral-xyz/anchor' +import { assert } from 'chai' export class EndpointMessage { static prefix: Buffer + sourceManager: Buffer managerPayload: ManagerMessage - constructor(managerPayload: ManagerMessage) { + constructor(sourceManager: Buffer, managerPayload: ManagerMessage) { + this.sourceManager = sourceManager this.managerPayload = managerPayload } @@ -16,49 +19,43 @@ export class EndpointMessage { if (!prefix.equals(this.prefix)) { throw new Error('Invalid prefix') } - const managerPayloadLen = data.readUInt16BE(4) - const managerPayload = deserializer(data.subarray(6, 6 + managerPayloadLen)) - return new EndpointMessage(managerPayload) + const sourceManager = data.subarray(4, 36) + const managerPayloadLen = data.readUInt16BE(36) + const managerPayload = deserializer(data.subarray(38, 38 + managerPayloadLen)) + return new EndpointMessage(sourceManager, managerPayload) } static serialize(msg: EndpointMessage, serializer: (payload: ManagerMessage) => Buffer): Buffer { const payload = serializer(msg.managerPayload) - const buffer = Buffer.concat([this.prefix, new BN(payload.length).toBuffer('be', 2), payload]) + assert(msg.sourceManager.length == 32, 'sourceManager must be 32 bytes') + const buffer = Buffer.concat([this.prefix, msg.sourceManager, new BN(payload.length).toBuffer('be', 2), payload]) return buffer } } export class ManagerMessage { - chainId: number sequence: bigint - sourceManager: Buffer sender: Buffer payload: A - constructor(chainId: number, sequence: bigint, sourceManager: Buffer, sender: Buffer, payload: A) { - this.chainId = chainId + constructor(sequence: bigint, sender: Buffer, payload: A) { this.sequence = sequence - this.sourceManager = sourceManager this.sender = sender this.payload = payload } static deserialize = (data: Buffer, deserializer: (data: Buffer) => A): ManagerMessage => { - const chainId = data.readUInt16BE(0) - const sequence = data.readBigUInt64BE(2) - const sourceManager = data.subarray(10, 42) - const sender = data.subarray(42, 74) - const payloadLen = data.readUint16BE(74) - const payload = deserializer(data.subarray(76, 76 + payloadLen)) - return new ManagerMessage(chainId, sequence, sourceManager, sender, payload) + const sequence = data.readBigUInt64BE(0) + const sender = data.subarray(8, 40) + const payloadLen = data.readUint16BE(40) + const payload = deserializer(data.subarray(42, 42 + payloadLen)) + return new ManagerMessage(sequence, sender, payload) } static serialize = (msg: ManagerMessage, serializer: (payload: A) => Buffer): Buffer => { - const buffer = Buffer.alloc(74) - buffer.writeUInt16BE(msg.chainId, 0) - buffer.writeBigUInt64BE(msg.sequence, 2) - buffer.set(msg.sourceManager, 10) - buffer.set(msg.sender, 42) + const buffer = Buffer.alloc(40) + buffer.writeBigUInt64BE(msg.sequence, 0) + buffer.set(msg.sender, 8) const payload = serializer(msg.payload) return Buffer.concat([buffer, new BN(payload.length).toBuffer('be', 2), payload]) } From cba56245cf66c070765090bc53f994b522d36eac Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 21:37:20 +0400 Subject: [PATCH 46/90] solana: multi endpoint arch --- .../src/endpoints/accounts/mod.rs | 1 + .../src/endpoints/accounts/sibling.rs | 14 ++ .../src/endpoints/mod.rs | 2 + .../endpoints/wormhole/instructions/admin.rs | 46 ++++++ .../endpoints/wormhole/instructions/mod.rs | 5 + .../wormhole/instructions/receive_message.rs | 70 ++++++++ .../endpoints/wormhole/instructions/redeem.rs | 0 .../src/endpoints/wormhole/messages.rs | 9 + .../src/endpoints/wormhole/mod.rs | 4 + .../src/error.rs | 8 +- .../src/instructions/admin.rs | 55 ++++++- .../src/instructions/redeem.rs | 30 ++-- .../src/instructions/release_outbound.rs | 3 +- .../example-native-token-transfers/src/lib.rs | 31 +++- .../src/messages.rs | 154 ++++++++++++------ .../src/registered_endpoint.rs | 39 +++++ .../src/sibling.rs | 4 +- .../tests/cancel_flow.rs | 62 +++++-- .../tests/common/setup.rs | 44 ++++- .../tests/sdk/accounts.rs | 25 +++ .../tests/sdk/endpoints/mod.rs | 1 + .../endpoints/wormhole/instructions/admin.rs | 34 ++++ .../endpoints/wormhole/instructions/mod.rs | 2 + .../wormhole/instructions/receive_message.rs | 32 ++++ .../tests/sdk/endpoints/wormhole/mod.rs | 1 + .../tests/sdk/instructions/admin.rs | 25 +++ .../tests/sdk/instructions/redeem.rs | 10 +- .../tests/sdk/mod.rs | 1 + .../tests/transfer.rs | 4 +- 29 files changed, 619 insertions(+), 97 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/mod.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/redeem.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs create mode 100644 solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs create mode 100644 solana/programs/example-native-token-transfers/src/registered_endpoint.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/endpoints/mod.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/receive_message.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/mod.rs diff --git a/solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs new file mode 100644 index 000000000..36075717f --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/accounts/mod.rs @@ -0,0 +1 @@ +pub mod sibling; diff --git a/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs b/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs new file mode 100644 index 000000000..cbc45579a --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs @@ -0,0 +1,14 @@ +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +/// A sibling on another chain. Stored in a PDA seeded by the chain id. +pub struct EndpointSibling { + pub bump: u8, + // TODO: variable address length? + pub address: [u8; 32], +} + +impl EndpointSibling { + pub const SEED_PREFIX: &'static [u8] = b"endpoint_sibling"; +} diff --git a/solana/programs/example-native-token-transfers/src/endpoints/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/mod.rs new file mode 100644 index 000000000..7ab58a710 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/mod.rs @@ -0,0 +1,2 @@ +pub mod wormhole; +pub mod accounts; diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs new file mode 100644 index 000000000..3a9d1ed32 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs @@ -0,0 +1,46 @@ +use anchor_lang::prelude::*; + +use crate::{chain_id::ChainId, config::Config, endpoints::accounts::sibling::EndpointSibling}; + +#[derive(Accounts)] +#[instruction(args: SetEndpointSiblingArgs)] +pub struct SetEndpointSibling<'info> { + #[account( + has_one = owner, + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + init, + space = 8 + EndpointSibling::INIT_SPACE, + payer = payer, + seeds = [EndpointSibling::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], + bump + )] + pub sibling: Account<'info, EndpointSibling>, + + pub system_program: Program<'info, System>, +} + +#[derive(AnchorDeserialize, AnchorSerialize)] +pub struct SetEndpointSiblingArgs { + pub chain_id: ChainId, + pub address: [u8; 32], +} + +pub fn set_endpoint_sibling( + ctx: Context, + args: SetEndpointSiblingArgs, +) -> Result<()> { + ctx.accounts.sibling.set_inner(EndpointSibling { + bump: ctx.bumps.sibling, + address: args.address, + }); + + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs new file mode 100644 index 000000000..6964147fb --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs @@ -0,0 +1,5 @@ +pub mod admin; +pub mod receive_message; + +pub use admin::*; +pub use receive_message::*; diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs new file mode 100644 index 000000000..99844bcf1 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs @@ -0,0 +1,70 @@ +use anchor_lang::prelude::*; + +use wormhole_anchor_sdk::wormhole::PostedVaa; + +use crate::{ + chain_id::ChainId, + config::*, + endpoints::{accounts::sibling::EndpointSibling, wormhole::messages::WormholeEndpoint}, + error::NTTError, + messages::{ + EndpointMessage, EndpointMessageData, NativeTokenTransfer, ValidatedEndpointMessage, + }, +}; + +#[derive(Accounts)] +pub struct ReceiveMessage<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + // NOTE: this works when the contract is paused + pub config: Account<'info, Config>, + + #[account( + seeds = [EndpointSibling::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], + constraint = sibling.address == *vaa.emitter_address() @ NTTError::InvalidEndpointSibling, + bump = sibling.bump, + )] + pub sibling: Account<'info, EndpointSibling>, + + #[account( + // check that the messages is targeted to this chain + constraint = vaa.message().manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + // NOTE: we don't replay protect VAAs. Instead, we replay protect + // executing the messages themselves with the [`released`] flag. + )] + pub vaa: Account<'info, PostedVaa>>, + + #[account( + init, + payer = payer, + space = 8 + ValidatedEndpointMessage::>::INIT_SPACE, + seeds = [ + ValidatedEndpointMessage::>::SEED_PREFIX, + vaa.emitter_chain().to_be_bytes().as_ref(), + // TODO: use hash instead of just sequence + vaa.message().manager_payload.sequence.to_be_bytes().as_ref(), + ], + bump, + )] + // NOTE: in order to handle multiple endpoints, we can just augment the + // inbox item transfer struct with a bitmap storing which endpoints have + // attested to the transfer. Then we only release it if there's quorum. + // We would need to maybe_init this account in that case. + pub endpoint_message: Account<'info, ValidatedEndpointMessage>, + + pub system_program: Program<'info, System>, +} + +pub fn receive_message(ctx: Context) -> Result<()> { + let message = ctx.accounts.vaa.message().message_data.clone(); + let chain_id = ctx.accounts.vaa.emitter_chain(); + ctx.accounts + .endpoint_message + .set_inner(ValidatedEndpointMessage { + from_chain: ChainId { id: chain_id }, + message, + }); + + Ok(()) +} diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/redeem.rs new file mode 100644 index 000000000..e69de29bb diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs new file mode 100644 index 000000000..477668610 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs @@ -0,0 +1,9 @@ +use crate::messages::Endpoint; + + +#[derive(PartialEq, Eq)] +pub struct WormholeEndpoint {} + +impl Endpoint for WormholeEndpoint { + const PREFIX: [u8; 4] = [0x99, 0x45, 0xFF, 0x10]; +} diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs new file mode 100644 index 000000000..17544562a --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs @@ -0,0 +1,4 @@ +pub mod instructions; +pub mod messages; + +pub use instructions::*; diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index db19b787e..37f6fcbf1 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -9,8 +9,10 @@ pub enum NTTError { InvalidChainId, #[msg("InvalidRecipientAddress")] InvalidRecipientAddress, - #[msg("InvalidSibling")] - InvalidSibling, + #[msg("InvalidEndpointSibling")] + InvalidEndpointSibling, + #[msg("InvalidManagerSibling")] + InvalidManagerSibling, #[msg("TransferAlreadyRedeemed")] TransferAlreadyRedeemed, #[msg("MessageAlreadySent")] @@ -23,4 +25,6 @@ pub enum NTTError { TransferExceedsRateLimit, #[msg("Paused")] Paused, + #[msg("DisabledEndpoint")] + DisabledEndpoint, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 468fac216..600347f71 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -6,7 +6,8 @@ use crate::{ config::Config, normalized_amount::NormalizedAmount, queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, - sibling::Sibling, + registered_endpoint::RegisteredEndpoint, + sibling::ManagerSibling, }; // * Transfer ownership @@ -57,7 +58,6 @@ pub fn claim_ownership(ctx: Context) -> Result<()> { // TODO: update siblings? should that be a separate instruction? take timestamp // for modification? (for total ordering) -// TODO: this should set the *manager* sibling, not the endpoint one #[derive(Accounts)] #[instruction(args: SetSiblingArgs)] pub struct SetSibling<'info> { @@ -73,12 +73,12 @@ pub struct SetSibling<'info> { #[account( init, - space = 8 + Sibling::INIT_SPACE, + space = 8 + ManagerSibling::INIT_SPACE, payer = payer, - seeds = [Sibling::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], + seeds = [ManagerSibling::SEED_PREFIX, args.chain_id.id.to_be_bytes().as_ref()], bump )] - pub sibling: Account<'info, Sibling>, + pub sibling: Account<'info, ManagerSibling>, #[account( init, @@ -110,7 +110,7 @@ pub struct SetSiblingArgs { } pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> { - ctx.accounts.sibling.set_inner(Sibling { + ctx.accounts.sibling.set_inner(ManagerSibling { bump: ctx.bumps.sibling, address: args.address, }); @@ -125,6 +125,49 @@ pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> Ok(()) } +// * Register endpoints + +#[derive(Accounts)] +pub struct RegisterEndpoint<'info> { + #[account( + has_one = owner, + )] + pub config: Account<'info, Config>, + + pub owner: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + #[account(executable)] + pub endpoint: AccountInfo<'info>, + + #[account( + init, + space = 8 + RegisteredEndpoint::INIT_SPACE, + payer = payer, + seeds = [RegisteredEndpoint::SEED_PREFIX, endpoint.key().as_ref()], + bump + )] + pub registered_endpoint: Account<'info, RegisteredEndpoint>, + + pub system_program: Program<'info, System>, +} + +pub fn register_endpoint(ctx: Context) -> Result<()> { + ctx.accounts + .registered_endpoint + .set_inner(RegisteredEndpoint { + bump: ctx.bumps.registered_endpoint, + endpoint_address: ctx.accounts.endpoint.key(), + enabled: true, + }); + + // TODO set in enabled bitmap + // TODO: set id + Ok(()) +} + // * Limit rate adjustment #[derive(Accounts)] pub struct SetOutboundLimit<'info> { diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 734d880b5..c654b648a 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -1,18 +1,17 @@ use anchor_lang::prelude::*; -use wormhole_anchor_sdk::wormhole::PostedVaa; - use crate::{ clock::current_timestamp, config::*, error::NTTError, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, + messages::{ManagerMessage, NativeTokenTransfer, ValidatedEndpointMessage}, queue::{ inbox::{InboxItem, InboxRateLimit}, outbox::OutboxRateLimit, rate_limit::RateLimitResult, }, - sibling::Sibling, + registered_endpoint::*, + sibling::ManagerSibling, }; #[derive(Accounts)] @@ -24,19 +23,22 @@ pub struct Redeem<'info> { pub config: Account<'info, Config>, #[account( - seeds = [Sibling::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref()], - constraint = sibling.address == *vaa.emitter_address() @ NTTError::InvalidSibling, + seeds = [ManagerSibling::SEED_PREFIX, endpoint_message.from_chain.id.to_be_bytes().as_ref()], + constraint = sibling.address == endpoint_message.message.source_manager @ NTTError::InvalidManagerSibling, bump = sibling.bump, )] - pub sibling: Account<'info, Sibling>, + pub sibling: Account<'info, ManagerSibling>, #[account( // check that the messages is targeted to this chain - constraint = vaa.message().manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, + constraint = endpoint_message.message.manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, // NOTE: we don't replay protect VAAs. Instead, we replay protect // executing the messages themselves with the [`released`] flag. + owner = endpoint.endpoint_address, )] - pub vaa: Account<'info, PostedVaa>>, + pub endpoint_message: Account<'info, ValidatedEndpointMessage>, + + pub endpoint: EnabledEndpoint<'info>, #[account( init, @@ -44,8 +46,9 @@ pub struct Redeem<'info> { space = 8 + InboxItem::INIT_SPACE, seeds = [ InboxItem::SEED_PREFIX, - vaa.emitter_chain().to_be_bytes().as_ref(), - vaa.message().manager_payload.sequence.to_be_bytes().as_ref(), + endpoint_message.from_chain.id.to_be_bytes().as_ref(), + // TODO: use hash instead of just sequence + endpoint_message.message.manager_payload.sequence.to_be_bytes().as_ref(), ], bump, )] @@ -59,7 +62,7 @@ pub struct Redeem<'info> { mut, seeds = [ InboxRateLimit::SEED_PREFIX, - vaa.emitter_chain().to_be_bytes().as_ref() + endpoint_message.from_chain.id.to_be_bytes().as_ref(), ], bump, )] @@ -77,7 +80,8 @@ pub struct RedeemArgs {} pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let accs = ctx.accounts; - let message: ManagerMessage = accs.vaa.message().manager_payload.clone(); + let message: ManagerMessage = + accs.endpoint_message.message.manager_payload.clone(); let amount = message.payload.amount; let amount = amount.change_decimals(accs.outbox_rate_limit.rate_limit.limit.decimals); diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 49efccb1f..18b13dc21 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -5,8 +5,9 @@ use wormhole_io::TypePrefixedPayload; use crate::{ config::*, + endpoints::wormhole::messages::WormholeEndpoint, error::NTTError, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, queue::outbox::OutboxItem, }; diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 2ead6cea5..2fe66de62 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -3,14 +3,18 @@ use anchor_lang::prelude::*; pub mod chain_id; pub mod clock; pub mod config; +pub mod endpoints; pub mod error; pub mod instructions; pub mod messages; pub mod normalized_amount; pub mod queue; +pub mod registered_endpoint; pub mod sequence; pub mod sibling; +use endpoints::wormhole::instructions::*; + use instructions::*; declare_id!("J61k8wq3PMLWmpR8meNxuQWfjHdzf8W1TZrFHoock9ou"); @@ -43,11 +47,17 @@ pub mod example_native_token_transfers { instructions::redeem(ctx, args) } - pub fn release_inbound_mint(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { + pub fn release_inbound_mint( + ctx: Context, + args: ReleaseInboundArgs, + ) -> Result<()> { instructions::release_inbound_mint(ctx, args) } - pub fn release_inbound_unlock(ctx: Context, args: ReleaseInboundArgs) -> Result<()> { + pub fn release_inbound_unlock( + ctx: Context, + args: ReleaseInboundArgs, + ) -> Result<()> { instructions::release_inbound_unlock(ctx, args) } @@ -70,6 +80,10 @@ pub mod example_native_token_transfers { instructions::set_sibling(ctx, args) } + pub fn register_endpoint(ctx: Context) -> Result<()> { + instructions::register_endpoint(ctx) + } + pub fn set_outbound_limit( ctx: Context, args: SetOutboundLimitArgs, @@ -83,4 +97,17 @@ pub mod example_native_token_transfers { ) -> Result<()> { instructions::set_inbound_limit(ctx, args) } + + // standalone endpoint stuff + + pub fn set_wormhole_sibling( + ctx: Context, + args: SetEndpointSiblingArgs, + ) -> Result<()> { + endpoints::wormhole::instructions::set_endpoint_sibling(ctx, args) + } + + pub fn receive_wormhole_message(ctx: Context) -> Result<()> { + endpoints::wormhole::instructions::receive_message(ctx) + } } diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index b77aceb3d..ea6ef6b53 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -8,18 +8,18 @@ use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; // TODO: might make sense to break this up into multiple files -#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize)] -pub struct ManagerMessage { +#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize, InitSpace)] +pub struct ManagerMessage { pub sequence: u64, pub sender: [u8; 32], pub payload: A, } -impl TypePrefixedPayload for ManagerMessage { +impl TypePrefixedPayload for ManagerMessage { const TYPE: Option = None; } -impl Readable for ManagerMessage { +impl Readable for ManagerMessage { const SIZE: Option = None; fn read(reader: &mut R) -> io::Result @@ -41,7 +41,7 @@ impl Readable for ManagerMessage { } } -impl Writeable for ManagerMessage { +impl Writeable for ManagerMessage { fn written_size(&self) -> usize { u64::SIZE.unwrap() + self.sender.len() @@ -68,7 +68,7 @@ impl Writeable for ManagerMessage { } } -#[derive(Debug, Clone, PartialEq, Eq)] +#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize, InitSpace)] pub struct NativeTokenTransfer { pub amount: NormalizedAmount, // TODO: is this needed? @@ -150,24 +150,52 @@ pub trait Endpoint { const PREFIX: [u8; 4]; } -#[derive(PartialEq, Eq)] -pub struct WormholeEndpoint {} +#[account] +#[derive(InitSpace)] +pub struct ValidatedEndpointMessage { + pub from_chain: ChainId, + pub message: EndpointMessageData, +} -impl Endpoint for WormholeEndpoint { - const PREFIX: [u8; 4] = [0x99, 0x45, 0xFF, 0x10]; +impl ValidatedEndpointMessage { + pub const SEED_PREFIX: &'static [u8] = b"endpoint_message"; } -#[derive(PartialEq, Eq)] -pub struct EndpointMessage { - _phantom: PhantomData, - // TODO: check sibling registration at the manager level +#[derive(Debug, PartialEq, Eq, InitSpace, Clone, AnchorSerialize, AnchorDeserialize)] +pub struct EndpointMessageData { pub source_manager: [u8; 32], pub manager_payload: ManagerMessage, } +#[derive(Eq, PartialEq)] +pub struct EndpointMessage { + _phantom: PhantomData, + // TODO: check sibling registration at the manager level + pub message_data: EndpointMessageData, +} + +impl std::ops::Deref + for EndpointMessage +{ + type Target = EndpointMessageData; + + fn deref(&self) -> &Self::Target { + &self.message_data + } +} + +impl std::ops::DerefMut + for EndpointMessage +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.message_data + } +} + impl fmt::Debug for EndpointMessage where E: Endpoint, + A: AnchorDeserialize + AnchorSerialize + Space + Clone, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("EndpointMessage") @@ -176,13 +204,19 @@ where } } -impl AnchorDeserialize for EndpointMessage { +impl AnchorDeserialize for EndpointMessage +where + A: AnchorDeserialize + AnchorSerialize + Space, +{ fn deserialize_reader(reader: &mut R) -> io::Result { Readable::read(reader) } } -impl AnchorSerialize for EndpointMessage { +impl AnchorSerialize for EndpointMessage +where + A: AnchorDeserialize + AnchorSerialize + Space, +{ fn serialize(&self, writer: &mut W) -> io::Result<()> { Writeable::write(self, writer) } @@ -191,31 +225,45 @@ impl AnchorSerialize for EndpointMessage Clone for EndpointMessage where E: Endpoint, + A: AnchorDeserialize + AnchorSerialize + Space, { fn clone(&self) -> Self { Self { _phantom: PhantomData, - source_manager: self.source_manager.clone(), - manager_payload: self.manager_payload.clone(), + message_data: EndpointMessageData { + source_manager: self.source_manager.clone(), + manager_payload: self.manager_payload.clone(), + }, } } } -impl EndpointMessage { +impl EndpointMessage +where + A: AnchorDeserialize + AnchorSerialize + Space + Clone, +{ pub fn new(source_manager: [u8; 32], manager_payload: ManagerMessage) -> Self { Self { _phantom: PhantomData, - source_manager, - manager_payload, + message_data: EndpointMessageData { + source_manager, + manager_payload, + }, } } } -impl TypePrefixedPayload for EndpointMessage { +impl TypePrefixedPayload for EndpointMessage +where + A: AnchorDeserialize + AnchorSerialize + Space, +{ const TYPE: Option = None; } -impl Readable for EndpointMessage { +impl Readable for EndpointMessage +where + A: AnchorDeserialize + AnchorSerialize + Space, +{ const SIZE: Option = None; fn read(reader: &mut R) -> io::Result @@ -241,7 +289,10 @@ impl Readable for EndpointMessag } } -impl Writeable for EndpointMessage { +impl Writeable for EndpointMessage +where + A: AnchorDeserialize + AnchorSerialize + Space, +{ fn written_size(&self) -> usize { 4 // prefix + self.source_manager.len() @@ -255,8 +306,11 @@ impl Writeable for EndpointMess { let EndpointMessage { _phantom, - source_manager, - manager_payload, + message_data: + EndpointMessageData { + source_manager, + manager_payload, + }, } = self; E::PREFIX.write(writer)?; @@ -296,6 +350,8 @@ impl Hack for PhantomData { #[cfg(test)] mod test { + use crate::endpoints::wormhole::messages::WormholeEndpoint; + use super::*; // #[test] @@ -307,30 +363,32 @@ mod test { let expected = EndpointMessage { _phantom: PhantomData::, - source_manager: [ - 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - manager_payload: ManagerMessage { - sequence: 233968345345, - sender: [ - 0x46, 0x67, 0x92, 0x13, 0x41, 0x23, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + message_data: EndpointMessageData { + source_manager: [ + 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], - payload: NativeTokenTransfer { - amount: NormalizedAmount { - amount: 1234567, - decimals: 7, - }, - source_token: [ - 0xBE, 0xEF, 0xFA, 0xCE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - to_chain: ChainId { id: 17 }, - to: [ - 0xFE, 0xEB, 0xCA, 0xFE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + manager_payload: ManagerMessage { + sequence: 233968345345, + sender: [ + 0x46, 0x67, 0x92, 0x13, 0x41, 0x23, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, ], + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount: 1234567, + decimals: 7, + }, + source_token: [ + 0xBE, 0xEF, 0xFA, 0xCE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + to_chain: ChainId { id: 17 }, + to: [ + 0xFE, 0xEB, 0xCA, 0xFE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }, }, }, }; diff --git a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs new file mode 100644 index 000000000..709e0dd70 --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs @@ -0,0 +1,39 @@ +use std::ops::{Deref, DerefMut}; + +use anchor_lang::prelude::*; + +#[account] +#[derive(InitSpace)] +pub struct RegisteredEndpoint { + pub bump: u8, + pub endpoint_address: Pubkey, + pub enabled: bool, +} + +impl RegisteredEndpoint { + pub const SEED_PREFIX: &'static [u8] = b"registered_endpoint"; +} + +#[derive(Accounts)] +pub struct EnabledEndpoint<'info> { + #[account( + constraint = endpoint.enabled @ crate::error::NTTError::DisabledEndpoint, + seeds = [RegisteredEndpoint::SEED_PREFIX, endpoint.endpoint_address.as_ref()], + bump = endpoint.bump, + )] + pub endpoint: Account<'info, RegisteredEndpoint>, +} + +impl<'info> Deref for EnabledEndpoint<'info> { + type Target = Account<'info, RegisteredEndpoint>; + + fn deref(&self) -> &Self::Target { + &self.endpoint + } +} + +impl<'info> DerefMut for EnabledEndpoint<'info> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.endpoint + } +} diff --git a/solana/programs/example-native-token-transfers/src/sibling.rs b/solana/programs/example-native-token-transfers/src/sibling.rs index c2bfd8af9..75b6a76bd 100644 --- a/solana/programs/example-native-token-transfers/src/sibling.rs +++ b/solana/programs/example-native-token-transfers/src/sibling.rs @@ -3,12 +3,12 @@ use anchor_lang::prelude::*; #[account] #[derive(InitSpace)] /// A sibling on another chain. Stored in a PDA seeded by the chain id. -pub struct Sibling { +pub struct ManagerSibling { pub bump: u8, // TODO: variable address length? pub address: [u8; 32], } -impl Sibling { +impl ManagerSibling { pub const SEED_PREFIX: &'static [u8] = b"sibling"; } diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 087bce79f..7efa2c947 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -5,24 +5,29 @@ use anchor_lang::{ prelude::{Clock, Pubkey}, AccountSerialize, }; -use common::setup::TestData; +use common::setup::{TestData, OTHER_CHAIN, OTHER_ENDPOINT, OTHER_MANAGER, THIS_CHAIN}; use example_native_token_transfers::{ chain_id::ChainId, config::Mode, + endpoints::wormhole::messages::WormholeEndpoint, instructions::{RedeemArgs, TransferArgs}, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, normalized_amount::NormalizedAmount, queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit}, }; +use sdk::endpoints::wormhole::instructions::receive_message::ReceiveMessage; use solana_program_test::*; use solana_sdk::{account::Account, signature::Keypair, signer::Signer}; use wormhole_io::TypePrefixedPayload; use crate::{ common::{hack::PostedVaaHack, query::GetAccountDataAnchor}, - sdk::instructions::{ - redeem::{redeem, Redeem}, - transfer::Transfer, + sdk::{ + endpoints::wormhole::instructions::receive_message::receive_message, + instructions::{ + redeem::{redeem, Redeem}, + transfer::Transfer, + }, }, }; use crate::{ @@ -33,9 +38,6 @@ use crate::{ pub mod common; pub mod sdk; -const THIS_CHAIN: u16 = 1; -const OTHER_CHAIN: u16 = 2; - fn init_transfer_accs_args( ctx: &mut ProgramTestContext, test_data: &TestData, @@ -64,14 +66,14 @@ fn init_transfer_accs_args( fn init_redeem_accs( ctx: &mut ProgramTestContext, test_data: &TestData, - vaa: Pubkey, chain_id: u16, sequence: u64, ) -> Redeem { let accs = Redeem { payer: ctx.payer.pubkey(), sibling: test_data.ntt.sibling(chain_id), - vaa, + endpoint: test_data.ntt.program, + endpoint_message: test_data.ntt.endpoint_message(chain_id, sequence), inbox_item: test_data.ntt.inbox_item(chain_id, sequence), inbox_rate_limit: test_data.ntt.inbox_rate_limit(chain_id), }; @@ -79,6 +81,22 @@ fn init_redeem_accs( accs } +fn init_receive_message_accs( + ctx: &mut ProgramTestContext, + test_data: &TestData, + vaa: Pubkey, + chain_id: u16, + sequence: u64, +) -> ReceiveMessage { + ReceiveMessage { + payer: ctx.payer.pubkey(), + sibling: test_data.ntt.endpoint_sibling(chain_id), + vaa, + chain_id, + sequence, + } +} + /// helper function to write into vaa accounts. /// this is mostly to avoid having to go through the process of posting the vaa /// via the wormhole program @@ -90,7 +108,7 @@ fn make_vaa(sequence: u64, amount: u64, recipient: &Keypair) -> (Pubkey, Account let vaa = Keypair::new(); let endpoint_message: EndpointMessage = EndpointMessage::new( - [5u8; 32], + OTHER_MANAGER, ManagerMessage { sequence, sender: [4u8; 32], @@ -117,7 +135,7 @@ fn make_vaa(sequence: u64, amount: u64, recipient: &Keypair) -> (Pubkey, Account nonce: 0, sequence, emitter_chain: OTHER_CHAIN, - emitter_address: [7u8; 32], + emitter_address: OTHER_ENDPOINT, payload, }; @@ -171,9 +189,17 @@ async fn test_cancel() { let inbound_limit_before = inbound_capacity(&mut ctx, &test_data).await; let outbound_limit_before = outbound_capacity(&mut ctx, &test_data).await; + receive_message( + &test_data.ntt, + init_receive_message_accs(&mut ctx, &test_data, vaa0, OTHER_CHAIN, 0), + ) + .submit(&mut ctx) + .await + .unwrap(); + redeem( &test_data.ntt, - init_redeem_accs(&mut ctx, &test_data, vaa0, 2, 0), + init_redeem_accs(&mut ctx, &test_data, OTHER_CHAIN, 0), RedeemArgs {}, ) .submit(&mut ctx) @@ -211,9 +237,17 @@ async fn test_cancel() { inbound_capacity(&mut ctx, &test_data).await ); + receive_message( + &test_data.ntt, + init_receive_message_accs(&mut ctx, &test_data, vaa1, OTHER_CHAIN, 1), + ) + .submit(&mut ctx) + .await + .unwrap(); + redeem( &test_data.ntt, - init_redeem_accs(&mut ctx, &test_data, vaa1, OTHER_CHAIN, 1), + init_redeem_accs(&mut ctx, &test_data, OTHER_CHAIN, 1), RedeemArgs {}, ) .submit(&mut ctx) diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index 5b21bcfa0..69d70c6d3 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -3,6 +3,7 @@ use anchor_spl::token::{Mint, Token}; use example_native_token_transfers::{ chain_id::ChainId, config::Mode, + endpoints::wormhole::SetEndpointSiblingArgs, instructions::{InitializeArgs, SetSiblingArgs}, }; use solana_program_test::{ProgramTest, ProgramTestContext}; @@ -16,8 +17,9 @@ use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector}; use crate::sdk::{ accounts::{Wormhole, NTT}, + endpoints::wormhole::instructions::admin::{set_endpoint_sibling, SetEndpointSibling}, instructions::{ - admin::{set_sibling, SetSibling}, + admin::{register_endpoint, set_sibling, RegisterEndpoint, SetSibling}, initialize::{initialize, Initialize}, }, }; @@ -33,6 +35,12 @@ pub const MINT_AMOUNT: u64 = 100000; pub const OUTBOUND_LIMIT: u64 = 10000; pub const INBOUND_LIMIT: u64 = 50000; +pub const OTHER_ENDPOINT: [u8; 32] = [7u8; 32]; +pub const OTHER_MANAGER: [u8; 32] = [9u8; 32]; + +pub const THIS_CHAIN: u16 = 1; +pub const OTHER_CHAIN: u16 = 2; + pub struct TestData { pub ntt: NTT, pub program_owner: Keypair, @@ -125,7 +133,7 @@ pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: }, InitializeArgs { // TODO: use sdk - chain_id: 1, + chain_id: THIS_CHAIN, limit: OUTBOUND_LIMIT, mode, }, @@ -134,6 +142,34 @@ pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: .await .unwrap(); + register_endpoint( + &test_data.ntt, + RegisterEndpoint { + payer: ctx.payer.pubkey(), + owner: test_data.program_owner.pubkey(), + endpoint: example_native_token_transfers::ID, // standalone manager&endpoint + }, + ) + .submit_with_signers(&[&test_data.program_owner], ctx) + .await + .unwrap(); + + set_endpoint_sibling( + &test_data.ntt, + SetEndpointSibling { + payer: ctx.payer.pubkey(), + owner: test_data.program_owner.pubkey(), + mint: test_data.mint, + }, + SetEndpointSiblingArgs { + chain_id: ChainId { id: OTHER_CHAIN }, + address: OTHER_ENDPOINT, + }, + ) + .submit_with_signers(&[&test_data.program_owner], ctx) + .await + .unwrap(); + set_sibling( &test_data.ntt, SetSibling { @@ -142,8 +178,8 @@ pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: mint: test_data.mint, }, SetSiblingArgs { - chain_id: ChainId { id: 2 }, - address: [7u8; 32], + chain_id: ChainId { id: OTHER_CHAIN }, + address: OTHER_MANAGER, limit: INBOUND_LIMIT, }, ) diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 825c49426..50bec9c88 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -5,6 +5,7 @@ use example_native_token_transfers::{ inbox::{InboxItem, InboxRateLimit}, outbox::OutboxRateLimit, }, + registered_endpoint::RegisteredEndpoint, sequence::Sequence, }; use wormhole_anchor_sdk::wormhole; @@ -83,6 +84,14 @@ impl NTT { token_authority } + pub fn registered_endpoint(&self, endpoint: &Pubkey) -> Pubkey { + let (registered_endpoint, _) = Pubkey::find_program_address( + &[RegisteredEndpoint::SEED_PREFIX, endpoint.as_ref()], + &self.program, + ); + registered_endpoint + } + pub fn emitter(&self) -> Pubkey { let (emitter, _) = Pubkey::find_program_address(&[b"emitter".as_ref()], &self.program); emitter @@ -104,6 +113,22 @@ impl NTT { sibling } + pub fn endpoint_sibling(&self, chain: u16) -> Pubkey { + let (sibling, _) = Pubkey::find_program_address( + &[b"endpoint_sibling".as_ref(), &chain.to_be_bytes()], + &self.program, + ); + sibling + } + + pub fn endpoint_message(&self, chain: u16, sequence: u64) -> Pubkey { + let (endpoint_message, _) = Pubkey::find_program_address( + &[b"endpoint_message".as_ref(), &chain.to_be_bytes(), &sequence.to_be_bytes()], + &self.program, + ); + endpoint_message + } + pub fn custody(&self, mint: &Pubkey) -> Pubkey { anchor_spl::associated_token::get_associated_token_address_with_program_id( &self.token_authority(), diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/mod.rs new file mode 100644 index 000000000..3ab4966d3 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/mod.rs @@ -0,0 +1 @@ +pub mod wormhole; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs new file mode 100644 index 000000000..8bf026eb7 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs @@ -0,0 +1,34 @@ +use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; +use example_native_token_transfers::endpoints::wormhole::SetEndpointSiblingArgs; +use solana_sdk::instruction::Instruction; + +use crate::sdk::accounts::NTT; + +pub struct SetEndpointSibling { + pub payer: Pubkey, + pub owner: Pubkey, + pub mint: Pubkey, +} + +pub fn set_endpoint_sibling( + ntt: &NTT, + accounts: SetEndpointSibling, + args: SetEndpointSiblingArgs, +) -> Instruction { + let chain_id = args.chain_id.id; + let data = example_native_token_transfers::instruction::SetWormholeSibling { args }; + + let accounts = example_native_token_transfers::accounts::SetEndpointSibling { + config: ntt.config(), + owner: accounts.owner, + payer: accounts.payer, + sibling: ntt.endpoint_sibling(chain_id), + system_program: System::id(), + }; + + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs new file mode 100644 index 000000000..f6db77f05 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs @@ -0,0 +1,2 @@ +pub mod receive_message; +pub mod admin; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/receive_message.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/receive_message.rs new file mode 100644 index 000000000..4a931f3c5 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/receive_message.rs @@ -0,0 +1,32 @@ +use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; +use solana_sdk::instruction::Instruction; + +use crate::sdk::accounts::NTT; + +#[derive(Debug, Clone)] +pub struct ReceiveMessage { + pub payer: Pubkey, + pub sibling: Pubkey, + pub vaa: Pubkey, + pub chain_id: u16, + pub sequence: u64, +} + +pub fn receive_message(ntt: &NTT, accs: ReceiveMessage) -> Instruction { + let data = example_native_token_transfers::instruction::ReceiveWormholeMessage {}; + + let accounts = example_native_token_transfers::accounts::ReceiveMessage { + payer: accs.payer, + config: ntt.config(), + sibling: accs.sibling, + vaa: accs.vaa, + endpoint_message: ntt.endpoint_message(accs.chain_id, accs.sequence), + system_program: System::id(), + }; + + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/mod.rs new file mode 100644 index 000000000..4f177196d --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/mod.rs @@ -0,0 +1 @@ +pub mod instructions; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs index 58c3c8fc6..ef586cb16 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs @@ -49,3 +49,28 @@ pub fn set_paused(ntt: &NTT, accounts: SetPaused, pause: bool) -> Instruction { data: data.data(), } } + +pub struct RegisterEndpoint { + pub payer: Pubkey, + pub owner: Pubkey, + pub endpoint: Pubkey, +} + +pub fn register_endpoint(ntt: &NTT, accounts: RegisterEndpoint) -> Instruction { + let data = example_native_token_transfers::instruction::RegisterEndpoint {}; + + let accounts = example_native_token_transfers::accounts::RegisterEndpoint { + config: ntt.config(), + owner: accounts.owner, + payer: accounts.payer, + endpoint: accounts.endpoint, + registered_endpoint: ntt.registered_endpoint(&accounts.endpoint), + system_program: System::id(), + }; + + Instruction { + program_id: example_native_token_transfers::ID, + accounts: accounts.to_account_metas(None), + data: data.data(), + } +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs index df460fdb1..6aa8cd695 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs @@ -1,5 +1,5 @@ use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; -use example_native_token_transfers::instructions::RedeemArgs; +use example_native_token_transfers::{accounts::EnabledEndpoint, instructions::RedeemArgs}; use solana_sdk::instruction::Instruction; use crate::sdk::accounts::NTT; @@ -8,7 +8,8 @@ use crate::sdk::accounts::NTT; pub struct Redeem { pub payer: Pubkey, pub sibling: Pubkey, - pub vaa: Pubkey, + pub endpoint_message: Pubkey, + pub endpoint: Pubkey, pub inbox_item: Pubkey, pub inbox_rate_limit: Pubkey, } @@ -20,7 +21,10 @@ pub fn redeem(ntt: &NTT, accs: Redeem, args: RedeemArgs) -> Instruction { payer: accs.payer, config: ntt.config(), sibling: accs.sibling, - vaa: accs.vaa, + endpoint_message: accs.endpoint_message, + endpoint: EnabledEndpoint { + endpoint: ntt.registered_endpoint(&accs.endpoint) + }, inbox_item: accs.inbox_item, inbox_rate_limit: accs.inbox_rate_limit, outbox_rate_limit: ntt.outbox_rate_limit(), diff --git a/solana/programs/example-native-token-transfers/tests/sdk/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs index 2e8410a09..f3cd5e69b 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs @@ -1,2 +1,3 @@ pub mod instructions; pub mod accounts; +pub mod endpoints; diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 3057976d9..5eeb2e5b5 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -9,10 +9,10 @@ use example_native_token_transfers::{ config::Mode, error::NTTError, instructions::{ReleaseOutboundArgs, TransferArgs}, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer, WormholeEndpoint}, + messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, normalized_amount::NormalizedAmount, queue::outbox::{OutboxItem, OutboxRateLimit}, - sequence::Sequence, + sequence::Sequence, endpoints::wormhole::messages::WormholeEndpoint, }; use solana_program_test::*; use solana_sdk::{ From 244dc54d4e8c99308460544bc727ab4423e8f5c5 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 21:47:51 +0400 Subject: [PATCH 47/90] solana: anchor keys sync I have absolutely no idea why anchor decided that the key is no longer correct. Nothing changed. --- solana/Anchor.toml | 2 +- solana/programs/example-native-token-transfers/src/lib.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/solana/Anchor.toml b/solana/Anchor.toml index c41a96026..ccc41f696 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -2,7 +2,7 @@ seeds = false skip-lint = false [programs.localnet] -solana_multi_endpoint = "J61k8wq3PMLWmpR8meNxuQWfjHdzf8W1TZrFHoock9ou" +solana_multi_endpoint = "5cR7BT9Qjs9CMCekudXKsypXrJrttUzYwgXEf3Z9RgoQ" [registry] url = "https://api.apr.dev" diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 2fe66de62..5abd99da1 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -17,7 +17,7 @@ use endpoints::wormhole::instructions::*; use instructions::*; -declare_id!("J61k8wq3PMLWmpR8meNxuQWfjHdzf8W1TZrFHoock9ou"); +declare_id!("5cR7BT9Qjs9CMCekudXKsypXrJrttUzYwgXEf3Z9RgoQ"); #[program] pub mod example_native_token_transfers { From 32aada2f72f79ab06f4f09e8724322d1308bd794 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 21:51:26 +0400 Subject: [PATCH 48/90] solana: patch idl file and add Makefile to run tests --- solana/Makefile | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 solana/Makefile diff --git a/solana/Makefile b/solana/Makefile new file mode 100644 index 000000000..7fc2d67fc --- /dev/null +++ b/solana/Makefile @@ -0,0 +1,18 @@ +# in this Makefile, ensure jq binary is available + +# remove the generics from the idl file. This is necessary as of anchor 0.29.0, because +# the javascript library does not support generics yet, and just panics +.PHONY: target/idl/example_native_token_transfers.json +target/idl/example_native_token_transfers.json: + @echo "Removing generics from $@" + @ cat $@ | jq '(.accounts, .types) |= map(select(has("generics") | not))' > temp.json && mv temp.json $@ + +.PHONY: anchor-build +_anchor-build: + @anchor build + +.PHONY: build +build: _anchor-build target/idl/example_native_token_transfers.json + +anchor-test: build target/idl/example_native_token_transfers.json + anchor test --skip-build From 9fc01e35fb5de0c808857593e452504b33d75763 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 15 Feb 2024 23:32:14 +0400 Subject: [PATCH 49/90] solana: update ts sdk to support multi endpoint arch --- .../tests/common/setup.rs | 1 - .../endpoints/wormhole/instructions/admin.rs | 1 - solana/tests/example-native-token-transfer.ts | 19 ++- solana/ts/sdk/index.ts | 109 +++++++++++++++++- 4 files changed, 119 insertions(+), 11 deletions(-) diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index 69d70c6d3..020f6f573 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -159,7 +159,6 @@ pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: SetEndpointSibling { payer: ctx.payer.pubkey(), owner: test_data.program_owner.pubkey(), - mint: test_data.mint, }, SetEndpointSiblingArgs { chain_id: ChainId { id: OTHER_CHAIN }, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs index 8bf026eb7..0566e1221 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/admin.rs @@ -7,7 +7,6 @@ use crate::sdk::accounts::NTT; pub struct SetEndpointSibling { pub payer: Pubkey, pub owner: Pubkey, - pub mint: Pubkey, } pub fn set_endpoint_sibling( diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index b98a6988a..7912c310a 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -64,11 +64,24 @@ describe('example-native-token-transfers', () => { mode: 'locking' }) + await ntt.registerEndpoint({ + payer, + owner, + endpoint: ntt.program.programId + }) + + await ntt.setWormholeEndpointSibling({ + payer, + owner, + chain: 'ethereum', + address: Buffer.from('endpoint'.padStart(32, '\0')), + }) + await ntt.setSibling({ payer, owner, chain: 'ethereum', - address: Buffer.from('BEEFFACE'.padStart(64, '0'), 'hex'), + address: Buffer.from('manager'.padStart(32, '\0')), limit: new BN(1000000) }) @@ -128,7 +141,7 @@ describe('example-native-token-transfers', () => { it('Can receive tokens', async () => { const emitter = new MockEmitter( - '00000000000000000000000000000000000000000000000000000000BEEFFACE', + Buffer.from('endpoint'.padStart(32, '\0')).toString('hex'), toChainId('ethereum'), Number(0) // sequence ) @@ -136,7 +149,7 @@ describe('example-native-token-transfers', () => { const guardians = new MockGuardians(0, [GUARDIAN_KEY]) const sendingEndpointMessage: EndpointMessage = { - sourceManager: Buffer.from('BEEF'.padStart(64, '0'), 'hex'), + sourceManager: Buffer.from('manager'.padStart(32, '\0')), managerPayload: new ManagerMessage( BigInt(0), Buffer.from('FACE'.padStart(64, '0'), 'hex'), diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 4d4941e31..cdc52b144 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -102,6 +102,25 @@ export class NTT { return this.derive_pda([Buffer.from('sibling'), new BN(chainId).toBuffer('be', 2)]) } + endpointSiblingAccountAddress(chain: ChainName | ChainId): PublicKey { + const chainId = coalesceChainId(chain) + return this.derive_pda([Buffer.from('endpoint_sibling'), new BN(chainId).toBuffer('be', 2)]) + } + + endpointMessageAccountAddress(chain: ChainName | ChainId, sequence: BN): PublicKey { + const chainId = coalesceChainId(chain) + return this.derive_pda( + [ + Buffer.from('endpoint_message'), + new BN(chainId).toBuffer('be', 2), + sequence.toBuffer('be', 8) + ]) + } + + registeredEndpointAddress(endpoint: PublicKey): PublicKey { + return this.derive_pda([Buffer.from('registered_endpoint'), endpoint.toBuffer()]) + } + // Instructions async initialize(args: { @@ -494,7 +513,45 @@ export class NTT { } - async createRedeemInstruction(args: { + async setWormholeEndpointSibling(args: { + payer: Keypair + owner: Keypair + chain: ChainName + address: ArrayLike + config?: Config + }) { + await this.program.methods.setWormholeSibling({ + chainId: { id: toChainId(args.chain) }, + address: Array.from(args.address) + }) + .accounts({ + payer: args.payer.publicKey, + owner: args.owner.publicKey, + config: this.configAccountAddress(), + sibling: this.endpointSiblingAccountAddress(args.chain), + }) + .signers([args.payer, args.owner]) + .rpc() + } + + async registerEndpoint(args: { + payer: Keypair + owner: Keypair + endpoint: PublicKey + }): Promise { + await this.program.methods.registerEndpoint() + .accounts({ + payer: args.payer.publicKey, + owner: args.owner.publicKey, + config: this.configAccountAddress(), + endpoint: args.endpoint, + registeredEndpoint: this.registeredEndpointAddress(args.endpoint), + }) + .signers([args.payer, args.owner]) + .rpc() + } + + async createReceiveWormholeMessageInstruction(args: { payer: PublicKey vaa: SignedVaa config?: Config @@ -514,7 +571,43 @@ export class NTT { // TODO: explain why this is fine here const chainId = parsedVaa.emitterChain as ChainId - const sibling = this.siblingAccountAddress(chainId) + const endpointSibling = this.endpointSiblingAccountAddress(chainId) + + return await this.program.methods.receiveWormholeMessage().accounts({ + payer: args.payer, + config: this.configAccountAddress(), + sibling: endpointSibling, + vaa: derivePostedVaaKey(this.wormholeId, parseVaa(args.vaa).hash), + endpointMessage: this.endpointMessageAccountAddress( + chainId, + new BN(managerMessage.sequence.toString()) + ), + }).instruction(); + } + + + async createRedeemInstruction(args: { + payer: PublicKey + vaa: SignedVaa + config?: Config + }): Promise { + const config = await this.getConfig(args.config) + + if (await this.isPaused(config)) { + throw new Error('Contract is paused') + } + + const parsedVaa = parseVaa(args.vaa) + const endpointMessage = + WormholeEndpointMessage.deserialize( + parsedVaa.payload, a => ManagerMessage.deserialize(a, a => a) + ) + const managerMessage = endpointMessage.managerPayload + // NOTE: we do an 'as ChainId' cast here, which is generally unsafe. + // TODO: explain why this is fine here + const chainId = parsedVaa.emitterChain as ChainId + + const managerSibling = this.siblingAccountAddress(chainId) const inboxRateLimit = this.inboxRateLimitAccountAddress(chainId) return await this.program.methods @@ -522,8 +615,9 @@ export class NTT { .accounts({ payer: args.payer, config: this.configAccountAddress(), - sibling, - vaa: derivePostedVaaKey(this.wormholeId, parseVaa(args.vaa).hash), + sibling: managerSibling, + endpointMessage: this.endpointMessageAccountAddress(chainId, new BN(managerMessage.sequence.toString())), + endpoint: { endpoint: this.registeredEndpointAddress(this.program.programId) }, inboxItem: this.inboxItemAccountAddress(chainId, new BN(managerMessage.sequence.toString())), inboxRateLimit, outboxRateLimit: this.outboxRateLimitAccountAddress(), @@ -560,11 +654,13 @@ export class NTT { // TODO: explain why this is fine here const chainId = parsedVaa.emitterChain as ChainId - // Here we create a transaction with two instructions: + // Here we create a transaction with three instructions: + // 1. receive wormhole messsage (vaa) // 1. redeem // 2. releaseInboundMint or releaseInboundUnlock (depending on mode) // - // The first instruction places the transfer in the inbox, then the second instruction + // The first instruction verifies the VAA. + // The second instruction places the transfer in the inbox, then the third instruction // releases it. // // In case the redeemed amount exceeds the remaining inbound rate limit capacity, @@ -574,6 +670,7 @@ export class NTT { // just make the second instruction a no-op in case the transfer is delayed. const tx = new Transaction() + tx.add(await this.createReceiveWormholeMessageInstruction(redeemArgs)) tx.add(await this.createRedeemInstruction(redeemArgs)) const releaseArgs = { From 34cbb2641a744da96e1788d0c908c9c6c40faa03 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 16 Feb 2024 02:07:30 +0400 Subject: [PATCH 50/90] solana: threshold voting --- solana/Cargo.lock | 11 +++- .../example-native-token-transfers/Cargo.toml | 3 +- .../src/bitmap.rs | 56 +++++++++++++++++++ .../src/config.rs | 5 ++ .../src/error.rs | 6 +- .../src/instructions/admin.rs | 5 +- .../src/instructions/initialize.rs | 3 + .../src/instructions/redeem.rs | 38 +++++++++---- .../src/instructions/release_inbound.rs | 15 ++--- .../src/instructions/release_outbound.rs | 15 +++-- .../src/instructions/transfer.rs | 4 +- .../example-native-token-transfers/src/lib.rs | 1 + .../src/queue/inbox.rs | 38 ++++++++----- .../src/queue/outbox.rs | 14 ++--- .../src/registered_endpoint.rs | 1 + .../sdk/instructions/release_outbound.rs | 6 +- .../tests/transfer.rs | 12 ++-- solana/ts/sdk/index.ts | 3 +- 18 files changed, 175 insertions(+), 61 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/src/bitmap.rs diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 2fe115db1..35f5df376 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -623,6 +623,12 @@ dependencies = [ "typenum", ] +[[package]] +name = "bitmaps" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1d084b0137aaa901caf9f1e8b21daa6aa24d41cd806e111335541eff9683bd6" + [[package]] name = "blake3" version = "1.5.0" @@ -1466,6 +1472,7 @@ dependencies = [ "anchor-lang", "anchor-spl", "base64 0.21.7", + "bitmaps 3.2.1", "hex", "serde", "serde_json", @@ -1944,7 +1951,7 @@ version = "15.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ - "bitmaps", + "bitmaps 2.1.0", "rand_core 0.6.4", "rand_xoshiro", "rayon", @@ -3449,7 +3456,7 @@ version = "0.6.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e" dependencies = [ - "bitmaps", + "bitmaps 2.1.0", "typenum", ] diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index c21e09c5a..f0c6c21d5 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -22,8 +22,9 @@ idl-build = [ [dependencies] ahash = "=0.8.6" -anchor-lang = "0.29.0" +anchor-lang = { version = "0.29.0", features = ["init-if-needed"] } anchor-spl = "0.29.0" +bitmaps = "3.2.1" wormhole-anchor-sdk = "0.29.0-alpha.1" wormhole-io = "0.1.3" diff --git a/solana/programs/example-native-token-transfers/src/bitmap.rs b/solana/programs/example-native-token-transfers/src/bitmap.rs new file mode 100644 index 000000000..0e951941f --- /dev/null +++ b/solana/programs/example-native-token-transfers/src/bitmap.rs @@ -0,0 +1,56 @@ +use anchor_lang::prelude::*; +use bitmaps::Bitmap as BM; + +#[derive(PartialEq, Eq, Clone, Copy, Debug, AnchorDeserialize, AnchorSerialize, InitSpace)] +pub struct Bitmap { + map: u128, +} + +impl Bitmap { + pub fn new() -> Self { + Bitmap { map: 0 } + } + + pub fn from_value(value: u128) -> Self { + Bitmap { map: value } + } + + pub fn set(&mut self, index: u8, value: bool) { + let mut bm = BM::<128>::from_value(self.map); + bm.set(index as usize, value); + self.map = *bm.as_value(); + } + + pub fn get(&self, index: u8) -> bool { + BM::<128>::from_value(self.map).get(index as usize) + } + + pub fn count_ones(&self) -> u8 { + BM::<128>::from_value(self.map).len().try_into().unwrap() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bitmap() { + let mut bm = Bitmap::new(); + assert_eq!(bm.count_ones(), 0); + bm.set(0, true); + assert_eq!(bm.count_ones(), 1); + assert_eq!(bm.get(0), true); + assert_eq!(bm.get(1), false); + bm.set(1, true); + assert_eq!(bm.count_ones(), 2); + assert_eq!(bm.get(0), true); + assert_eq!(bm.get(1), true); + bm.set(0, false); + assert_eq!(bm.count_ones(), 1); + assert_eq!(bm.get(0), false); + assert_eq!(bm.get(1), true); + bm.set(18, true); + assert_eq!(bm.count_ones(), 2); + } +} diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index de95f7411..cd5eebbc6 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -25,6 +25,11 @@ pub struct Config { /// hardcode this so that the program is deployable on any potential SVM /// forks. pub chain_id: ChainId, + /// The next endpoint id to use when registering an endpoint. + pub next_endpoint_id: u8, + /// The number of endpoints that must attest to a transfer before it is + /// accepted. + pub threshold: u8, /// Pause the program. This is useful for upgrades and other maintenance. pub paused: bool, } diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index 37f6fcbf1..225bf14da 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -3,8 +3,8 @@ use anchor_lang::prelude::error_code; #[error_code] // TODO(csongor): rename pub enum NTTError { - #[msg("ReleaseTimestampNotReached")] - ReleaseTimestampNotReached, + #[msg("CantReleaseYet")] + CantReleaseYet, #[msg("InvalidChainId")] InvalidChainId, #[msg("InvalidRecipientAddress")] @@ -15,6 +15,8 @@ pub enum NTTError { InvalidManagerSibling, #[msg("TransferAlreadyRedeemed")] TransferAlreadyRedeemed, + #[msg("TransferNotApproved")] + TransferNotApproved, #[msg("MessageAlreadySent")] MessageAlreadySent, #[msg("InvalidMode")] diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 600347f71..e006f9762 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -130,6 +130,7 @@ pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> #[derive(Accounts)] pub struct RegisterEndpoint<'info> { #[account( + mut, has_one = owner, )] pub config: Account<'info, Config>, @@ -155,16 +156,18 @@ pub struct RegisterEndpoint<'info> { } pub fn register_endpoint(ctx: Context) -> Result<()> { + let id = ctx.accounts.config.next_endpoint_id; + ctx.accounts.config.next_endpoint_id += 1; ctx.accounts .registered_endpoint .set_inner(RegisteredEndpoint { bump: ctx.bumps.registered_endpoint, + id, endpoint_address: ctx.accounts.endpoint.key(), enabled: true, }); // TODO set in enabled bitmap - // TODO: set id Ok(()) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index ef8a4c6e2..62674f046 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -95,6 +95,9 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> owner: ctx.accounts.owner.key(), pending_owner: None, paused: false, + next_endpoint_id: 0, + // NOTE: can't be changed for now + threshold: 1, }); ctx.accounts.seq.set_inner(Sequence { diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index c654b648a..b088f8830 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -1,12 +1,13 @@ use anchor_lang::prelude::*; use crate::{ + bitmap::Bitmap, clock::current_timestamp, config::*, error::NTTError, messages::{ManagerMessage, NativeTokenTransfer, ValidatedEndpointMessage}, queue::{ - inbox::{InboxItem, InboxRateLimit}, + inbox::{InboxItem, InboxRateLimit, ReleaseStatus}, outbox::OutboxRateLimit, rate_limit::RateLimitResult, }, @@ -41,7 +42,7 @@ pub struct Redeem<'info> { pub endpoint: EnabledEndpoint<'info>, #[account( - init, + init_if_needed, payer = payer, space = 8 + InboxItem::INIT_SPACE, seeds = [ @@ -80,14 +81,35 @@ pub struct RedeemArgs {} pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let accs = ctx.accounts; + // TODO: seed PDA by content instead of sequence + let message: ManagerMessage = accs.endpoint_message.message.manager_payload.clone(); let amount = message.payload.amount; let amount = amount.change_decimals(accs.outbox_rate_limit.rate_limit.limit.decimals); - let recipient_address = - Pubkey::try_from(message.payload.to).map_err(|_| NTTError::InvalidRecipientAddress)?; + if !accs.inbox_item.init { + let recipient_address = + Pubkey::try_from(message.payload.to).map_err(|_| NTTError::InvalidRecipientAddress)?; + + accs.inbox_item.set_inner(InboxItem { + init: true, + bump: ctx.bumps.inbox_item, + amount, + recipient_address, + release_status: ReleaseStatus::NotApproved, + votes: Bitmap::new(), + }); + } + + // idempotent + accs.inbox_item.votes.set(accs.endpoint.id, true); + + // TODO: if endpoints can be disabled, this should only cound enabled endpoints + if accs.inbox_item.votes.count_ones() < accs.config.threshold { + return Ok(()); + } let release_timestamp = match accs.inbox_rate_limit.rate_limit.consume_or_delay(amount) { RateLimitResult::Consumed => { @@ -99,13 +121,7 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { RateLimitResult::Delayed(release_timestamp) => release_timestamp, }; - accs.inbox_item.set_inner(InboxItem { - bump: ctx.bumps.inbox_item, - amount, - recipient_address, - release_timestamp, - released: false, - }); + accs.inbox_item.release_status = ReleaseStatus::ReleaseAfter(release_timestamp); Ok(()) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index b6ea0679c..8d2fe9eff 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -1,7 +1,7 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; -use crate::{config::*, error::NTTError, queue::inbox::InboxItem}; +use crate::{config::*, error::NTTError, queue::inbox::{InboxItem, ReleaseStatus}}; #[derive(Accounts)] pub struct ReleaseInbound<'info> { @@ -10,10 +10,7 @@ pub struct ReleaseInbound<'info> { pub config: NotPausedConfig<'info>, - #[account( - mut, - constraint = !inbox_item.released @ NTTError::TransferAlreadyRedeemed, - )] + #[account(mut)] pub inbox_item: Account<'info, InboxItem>, #[account( @@ -68,13 +65,13 @@ pub fn release_inbound_mint( if !released { if args.revert_on_delay { - return Err(NTTError::ReleaseTimestampNotReached.into()); + return Err(NTTError::CantReleaseYet.into()); } else { return Ok(()); } } - assert!(inbox_item.released); + assert!(inbox_item.release_status == ReleaseStatus::Released); match ctx.accounts.common.config.mode { Mode::Burning => token_interface::mint_to( CpiContext::new_with_signer( @@ -122,13 +119,13 @@ pub fn release_inbound_unlock( if !released { if args.revert_on_delay { - return Err(NTTError::ReleaseTimestampNotReached.into()); + return Err(NTTError::CantReleaseYet.into()); } else { return Ok(()); } } - assert!(inbox_item.released); + assert!(inbox_item.release_status == ReleaseStatus::Released); match ctx.accounts.common.config.mode { Mode::Burning => Err(NTTError::InvalidMode.into()), Mode::Locking => token_interface::transfer_checked( diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 18b13dc21..1e54e21a9 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -9,6 +9,7 @@ use crate::{ error::NTTError, messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, queue::outbox::OutboxItem, + registered_endpoint::*, }; #[derive(Accounts)] @@ -20,10 +21,15 @@ pub struct ReleaseOutbound<'info> { #[account( mut, - constraint = !outbox_item.released @ NTTError::MessageAlreadySent, + constraint = !outbox_item.released.get(endpoint.id) @ NTTError::MessageAlreadySent, )] pub outbox_item: Account<'info, OutboxItem>, + #[account( + constraint = endpoint.endpoint_address == crate::ID, + )] + pub endpoint: EnabledEndpoint<'info>, + #[account( mut, seeds = [b"message", outbox_item.key().as_ref()], @@ -72,18 +78,17 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs let accs = ctx.accounts; let batch_id = 0; - // TODO: record endpoint position - let released = accs.outbox_item.try_release()?; + let released = accs.outbox_item.try_release(accs.endpoint.id)?; if !released { if args.revert_on_delay { - return Err(NTTError::ReleaseTimestampNotReached.into()); + return Err(NTTError::CantReleaseYet.into()); } else { return Ok(()); } } - assert!(accs.outbox_item.released); + assert!(accs.outbox_item.released.get(accs.endpoint.id)); let message: EndpointMessage = EndpointMessage::new( // TODO: should we just put the ntt id here statically? accs.outbox_item.to_account_info().owner.to_bytes(), diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 96f3da2c9..471d635b8 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -11,7 +11,7 @@ use crate::{ inbox::InboxRateLimit, outbox::{OutboxItem, OutboxRateLimit}, rate_limit::RateLimitResult, - }, + }, bitmap::Bitmap, }; // this will burn the funds and create an account that either allows sending the @@ -229,7 +229,7 @@ fn insert_into_outbox( recipient_chain, recipient_address, release_timestamp, - released: false, + released: Bitmap::new(), }); Ok(()) diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 5abd99da1..c3e4be2d9 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -12,6 +12,7 @@ pub mod queue; pub mod registered_endpoint; pub mod sequence; pub mod sibling; +pub mod bitmap; use endpoints::wormhole::instructions::*; diff --git a/solana/programs/example-native-token-transfers/src/queue/inbox.rs b/solana/programs/example-native-token-transfers/src/queue/inbox.rs index 91e735e53..6c7f3aad5 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbox.rs @@ -2,7 +2,9 @@ use std::ops::{Deref, DerefMut}; use anchor_lang::prelude::*; -use crate::{clock::current_timestamp, error::NTTError, normalized_amount::NormalizedAmount}; +use crate::{ + bitmap::Bitmap, clock::current_timestamp, error::NTTError, normalized_amount::NormalizedAmount, +}; use super::rate_limit::RateLimitState; @@ -10,11 +12,19 @@ use super::rate_limit::RateLimitState; #[derive(InitSpace)] // TODO: generalise this to arbitrary inbound messages (via a generic parameter in place of amount and recipient info) pub struct InboxItem { + pub init: bool, pub bump: u8, pub amount: NormalizedAmount, pub recipient_address: Pubkey, - pub release_timestamp: i64, - pub released: bool, + pub votes: Bitmap, + pub release_status: ReleaseStatus, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug, PartialEq, Eq, InitSpace)] +pub enum ReleaseStatus { + NotApproved, + ReleaseAfter(i64), + Released, } impl InboxItem { @@ -25,17 +35,19 @@ impl InboxItem { pub fn try_release(&mut self) -> Result { let now = current_timestamp(); - if self.release_timestamp > now { - return Ok(false) - } - - if self.released { - return Err(NTTError::TransferAlreadyRedeemed.into()); + match self.release_status { + ReleaseStatus::NotApproved => Ok(false), + ReleaseStatus::ReleaseAfter(release_timestamp) => { + if release_timestamp > now { + return Ok(false); + } + self.release_status = ReleaseStatus::Released; + Ok(true) + } + ReleaseStatus::Released => { + return Err(NTTError::TransferAlreadyRedeemed.into()); + } } - - self.released = true; - - Ok(true) } } diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 8a4c09cf5..43706b884 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -3,7 +3,7 @@ use std::ops::{Deref, DerefMut}; use anchor_lang::prelude::*; use crate::{ - chain_id::ChainId, clock::current_timestamp, error::NTTError, + bitmap::*, chain_id::ChainId, clock::current_timestamp, error::NTTError, normalized_amount::NormalizedAmount, }; @@ -19,27 +19,25 @@ pub struct OutboxItem { pub recipient_chain: ChainId, pub recipient_address: [u8; 32], pub release_timestamp: i64, - // TODO: change this to a bitmap to store which endpoints have released the - // transfer? (multi endpoint) - pub released: bool, + pub released: Bitmap, } impl OutboxItem { /// Attempt to release the transfer. /// Returns true if the transfer was released, false if it was not yet time to release it. /// TODO: this is duplicated in inbox.rs. factor out? - pub fn try_release(&mut self) -> Result { + pub fn try_release(&mut self, endpoint_index: u8) -> Result { let now = current_timestamp(); if self.release_timestamp > now { - return Ok(false) + return Ok(false); } - if self.released { + if self.released.get(endpoint_index) { return Err(NTTError::MessageAlreadySent.into()); } - self.released = true; + self.released.set(endpoint_index, true); Ok(true) } diff --git a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs index 709e0dd70..0b19fb192 100644 --- a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs +++ b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs @@ -6,6 +6,7 @@ use anchor_lang::prelude::*; #[derive(InitSpace)] pub struct RegisteredEndpoint { pub bump: u8, + pub id: u8, pub endpoint_address: Pubkey, pub enabled: bool, } diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs index a71a27b1a..f0718731c 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs @@ -1,6 +1,7 @@ use anchor_lang::{prelude::*, InstructionData}; use example_native_token_transfers::{ - accounts::NotPausedConfig, instructions::ReleaseOutboundArgs, + accounts::{EnabledEndpoint, NotPausedConfig}, + instructions::ReleaseOutboundArgs, }; use solana_sdk::{instruction::Instruction, sysvar::SysvarId}; @@ -25,6 +26,9 @@ pub fn release_outbound( outbox_item: release_outbound.outbox_item, wormhole_message: ntt.wormhole_message(&release_outbound.outbox_item), emitter: ntt.emitter(), + endpoint: EnabledEndpoint { + endpoint: ntt.registered_endpoint(&ntt.program), + }, wormhole_bridge: ntt.wormhole.bridge(), wormhole_fee_collector: ntt.wormhole.fee_collector(), wormhole_sequence: ntt.wormhole_sequence(), diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 5eeb2e5b5..772dfd9d3 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -5,14 +5,16 @@ use anchor_lang::prelude::{Clock, Pubkey}; use anchor_spl::token::{Mint, TokenAccount}; use common::setup::TestData; use example_native_token_transfers::{ + bitmap::Bitmap, chain_id::ChainId, config::Mode, + endpoints::wormhole::messages::WormholeEndpoint, error::NTTError, instructions::{ReleaseOutboundArgs, TransferArgs}, messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, normalized_amount::NormalizedAmount, queue::outbox::{OutboxItem, OutboxRateLimit}, - sequence::Sequence, endpoints::wormhole::messages::WormholeEndpoint, + sequence::Sequence, }; use solana_program_test::*; use solana_sdk::{ @@ -117,7 +119,7 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: recipient_chain: ChainId { id: 2 }, recipient_address: [1u8; 32], release_timestamp: clock.unix_timestamp, - released: false + released: Bitmap::new(), } ); @@ -141,7 +143,7 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: // make sure the outbox item is now released, but nothing else has changed assert_eq!( OutboxItem { - released: true, + released: Bitmap::from_value(1), ..outbox_item_account }, outbox_item_account_after, @@ -325,7 +327,7 @@ async fn assert_queued(ctx: &mut ProgramTestContext, outbox_item: Pubkey) { let clock: Clock = ctx.banks_client.get_sysvar().await.unwrap(); - assert!(!outbox_item_account.released); + assert!(!outbox_item_account.released.get(0)); assert!(outbox_item_account.release_timestamp > clock.unix_timestamp); } @@ -476,7 +478,7 @@ async fn test_cant_release_queued() { err.unwrap(), TransactionError::InstructionError( 0, - InstructionError::Custom(NTTError::ReleaseTimestampNotReached.into()) + InstructionError::Custom(NTTError::CantReleaseYet.into()) ) ); diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index cdc52b144..74602bb31 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -334,6 +334,7 @@ export class NTT { outboxItem: args.outboxItem, wormholeMessage: this.wormholeMessageAccountAddress(args.outboxItem), emitter: whAccs.wormholeEmitter, + endpoint: { endpoint: this.registeredEndpointAddress(this.program.programId) }, wormholeBridge: whAccs.wormholeBridge, wormholeFeeCollector: whAccs.wormholeFeeCollector, wormholeSequence: whAccs.wormholeSequence, @@ -693,7 +694,7 @@ export class NTT { // Let's check if the transfer was released const inboxItem = await this.getInboxItem(chainId, new BN(managerMessage.sequence.toString())) - return inboxItem.released + return inboxItem.releaseStatus.released !== null } // Account access From 3f7449c90d24e298f341ce6859416dd9ab8992ea Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 16 Feb 2024 03:24:36 +0400 Subject: [PATCH 51/90] solana: content-addressed inbox items --- solana/Cargo.lock | 2 + solana/package-lock.json | 3 +- solana/package.json | 3 +- .../example-native-token-transfers/Cargo.toml | 3 ++ .../wormhole/instructions/receive_message.rs | 1 - .../src/instructions/redeem.rs | 14 +++-- .../src/messages.rs | 8 +++ .../tests/cancel_flow.rs | 54 ++++++++++--------- .../tests/sdk/accounts.rs | 20 +++++-- solana/ts/sdk/index.ts | 39 ++++++++------ solana/yarn.lock | 2 +- 11 files changed, 93 insertions(+), 56 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 35f5df376..3ade7c39b 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -1476,6 +1476,8 @@ dependencies = [ "hex", "serde", "serde_json", + "sha3 0.10.8", + "solana-program", "solana-program-test", "solana-sdk", "spl-associated-token-account", diff --git a/solana/package-lock.json b/solana/package-lock.json index aac44c512..83078ccba 100644 --- a/solana/package-lock.json +++ b/solana/package-lock.json @@ -8,7 +8,8 @@ "dependencies": { "@certusone/wormhole-sdk": "^0.10.10", "@coral-xyz/anchor": "^0.29.0", - "@solana/spl-token": "^0.4.0" + "@solana/spl-token": "^0.4.0", + "sha3": "^2.1.4" }, "devDependencies": { "@stylistic/eslint-plugin": "^1.6.1", diff --git a/solana/package.json b/solana/package.json index 5ababb583..de9169d7c 100644 --- a/solana/package.json +++ b/solana/package.json @@ -7,7 +7,8 @@ "dependencies": { "@certusone/wormhole-sdk": "^0.10.10", "@coral-xyz/anchor": "^0.29.0", - "@solana/spl-token": "^0.4.0" + "@solana/spl-token": "^0.4.0", + "sha3": "^2.1.4" }, "devDependencies": { "@stylistic/eslint-plugin": "^1.6.1", diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index f0c6c21d5..2206769e2 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -25,6 +25,8 @@ ahash = "=0.8.6" anchor-lang = { version = "0.29.0", features = ["init-if-needed"] } anchor-spl = "0.29.0" bitmaps = "3.2.1" +hex = "0.4.3" +solana-program = "1.17.2" wormhole-anchor-sdk = "0.29.0-alpha.1" wormhole-io = "0.1.3" @@ -37,3 +39,4 @@ base64 = "0.21.7" solana-sdk = "1.17.2" spl-token = "4" spl-associated-token-account = "2.2.0" +sha3 = "0.10.4" diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs index 99844bcf1..2d3a876d8 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs @@ -42,7 +42,6 @@ pub struct ReceiveMessage<'info> { seeds = [ ValidatedEndpointMessage::>::SEED_PREFIX, vaa.emitter_chain().to_be_bytes().as_ref(), - // TODO: use hash instead of just sequence vaa.message().manager_payload.sequence.to_be_bytes().as_ref(), ], bump, diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index b088f8830..e836e5b29 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -48,15 +48,15 @@ pub struct Redeem<'info> { seeds = [ InboxItem::SEED_PREFIX, endpoint_message.from_chain.id.to_be_bytes().as_ref(), - // TODO: use hash instead of just sequence - endpoint_message.message.manager_payload.sequence.to_be_bytes().as_ref(), + endpoint_message.message.manager_payload.keccak256().as_ref(), ], bump, )] - // NOTE: in order to handle multiple endpoints, we can just augment the - // inbox item transfer struct with a bitmap storing which endpoints have - // attested to the transfer. Then we only release it if there's quorum. - // We would need to maybe_init this account in that case. + /// NOTE: This account is content-addressed (PDA seeded by the message hash). + /// This is because in a multi-endpoint configuration, the different + /// endpoints "vote" on messages (by delivering them). By making the inbox + /// items content-addressed, we can ensure that disagreeing votes don't + /// interfere with each other. pub inbox_item: Account<'info, InboxItem>, #[account( @@ -81,8 +81,6 @@ pub struct RedeemArgs {} pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let accs = ctx.accounts; - // TODO: seed PDA by content instead of sequence - let message: ManagerMessage = accs.endpoint_message.message.manager_payload.clone(); diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index ea6ef6b53..4df51200c 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -1,5 +1,6 @@ use anchor_lang::prelude::*; use core::fmt; +use solana_program::keccak::Hash; use std::{collections::HashMap, io, marker::PhantomData}; use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; @@ -15,6 +16,13 @@ pub struct ManagerMessage { pub payload: A, } +impl ManagerMessage { + pub fn keccak256(&self) -> Hash { + let payload = TypePrefixedPayload::to_vec_payload(self); + solana_program::keccak::hash(&payload) + } +} + impl TypePrefixedPayload for ManagerMessage { const TYPE: Option = None; } diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 7efa2c947..eb4bac0ab 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -67,14 +67,16 @@ fn init_redeem_accs( ctx: &mut ProgramTestContext, test_data: &TestData, chain_id: u16, - sequence: u64, + manager_message: ManagerMessage, ) -> Redeem { let accs = Redeem { payer: ctx.payer.pubkey(), sibling: test_data.ntt.sibling(chain_id), endpoint: test_data.ntt.program, - endpoint_message: test_data.ntt.endpoint_message(chain_id, sequence), - inbox_item: test_data.ntt.inbox_item(chain_id, sequence), + endpoint_message: test_data + .ntt + .endpoint_message(chain_id, manager_message.sequence), + inbox_item: test_data.ntt.inbox_item(chain_id, manager_message), inbox_rate_limit: test_data.ntt.inbox_rate_limit(chain_id), }; @@ -104,25 +106,27 @@ fn init_receive_message_accs( /// doesn't support posting vaas yet. /// TODO: in an ideal world, writing into these accounts should be even easier, but /// the sdk doesn't have a working serializer implementation for the vaa account either -fn make_vaa(sequence: u64, amount: u64, recipient: &Keypair) -> (Pubkey, Account) { +fn make_vaa( + sequence: u64, + amount: u64, + recipient: &Keypair, +) -> (Pubkey, Account, ManagerMessage) { let vaa = Keypair::new(); - let endpoint_message: EndpointMessage = - EndpointMessage::new( - OTHER_MANAGER, - ManagerMessage { - sequence, - sender: [4u8; 32], - payload: NativeTokenTransfer { - amount: NormalizedAmount { - amount, - decimals: 9, - }, - source_token: [3u8; 32], - to_chain: ChainId { id: THIS_CHAIN }, - to: recipient.pubkey().to_bytes(), - }, + let manager_message = ManagerMessage { + sequence, + sender: [4u8; 32], + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount, + decimals: 9, }, - ); + source_token: [3u8; 32], + to_chain: ChainId { id: THIS_CHAIN }, + to: recipient.pubkey().to_bytes(), + }, + }; + let endpoint_message: EndpointMessage = + EndpointMessage::new(OTHER_MANAGER, manager_message.clone()); let payload = endpoint_message.to_vec_payload(); @@ -150,7 +154,7 @@ fn make_vaa(sequence: u64, amount: u64, recipient: &Keypair) -> (Pubkey, Account rent_epoch: u64::MAX, }; - (vaa.pubkey(), vaa_account) + (vaa.pubkey(), vaa_account, manager_message) } async fn outbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> u64 { @@ -180,8 +184,8 @@ async fn inbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> #[tokio::test] async fn test_cancel() { let recipient = Keypair::new(); - let (vaa0, vaa_account0) = make_vaa(0, 1000, &recipient); - let (vaa1, vaa_account1) = make_vaa(1, 2000, &recipient); + let (vaa0, vaa_account0, msg0) = make_vaa(0, 1000, &recipient); + let (vaa1, vaa_account1, msg1) = make_vaa(1, 2000, &recipient); let (mut ctx, test_data) = setup_with_extra_accounts(Mode::Locking, &[(vaa0, vaa_account0), (vaa1, vaa_account1)]) .await; @@ -199,7 +203,7 @@ async fn test_cancel() { redeem( &test_data.ntt, - init_redeem_accs(&mut ctx, &test_data, OTHER_CHAIN, 0), + init_redeem_accs(&mut ctx, &test_data, OTHER_CHAIN, msg0), RedeemArgs {}, ) .submit(&mut ctx) @@ -247,7 +251,7 @@ async fn test_cancel() { redeem( &test_data.ntt, - init_redeem_accs(&mut ctx, &test_data, OTHER_CHAIN, 1), + init_redeem_accs(&mut ctx, &test_data, OTHER_CHAIN, msg1), RedeemArgs {}, ) .submit(&mut ctx) diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 50bec9c88..70e653698 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -1,6 +1,7 @@ use anchor_lang::prelude::Pubkey; use example_native_token_transfers::{ config::Config, + messages::{ManagerMessage, NativeTokenTransfer}, queue::{ inbox::{InboxItem, InboxRateLimit}, outbox::OutboxRateLimit, @@ -8,7 +9,9 @@ use example_native_token_transfers::{ registered_endpoint::RegisteredEndpoint, sequence::Sequence, }; +use sha3::{Digest, Keccak256}; use wormhole_anchor_sdk::wormhole; +use wormhole_io::TypePrefixedPayload; pub struct Wormhole { pub program: Pubkey, @@ -66,12 +69,19 @@ impl NTT { inbox_rate_limit } - pub fn inbox_item(&self, chain: u16, sequence: u64) -> Pubkey { + pub fn inbox_item( + &self, + chain: u16, + manager_message: ManagerMessage, + ) -> Pubkey { + let mut hasher = Keccak256::new(); + hasher.update(&TypePrefixedPayload::to_vec_payload(&manager_message)); + let (inbox_item, _) = Pubkey::find_program_address( &[ InboxItem::SEED_PREFIX, &chain.to_be_bytes(), - &sequence.to_be_bytes(), + &hasher.finalize(), ], &self.program, ); @@ -123,7 +133,11 @@ impl NTT { pub fn endpoint_message(&self, chain: u16, sequence: u64) -> Pubkey { let (endpoint_message, _) = Pubkey::find_program_address( - &[b"endpoint_message".as_ref(), &chain.to_be_bytes(), &sequence.to_be_bytes()], + &[ + b"endpoint_message".as_ref(), + &chain.to_be_bytes(), + &sequence.to_be_bytes(), + ], &self.program, ); endpoint_message diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 74602bb31..7c99ab2be 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -11,6 +11,7 @@ import { sendAndConfirmTransaction, type TransactionSignature } from '@solana/web3.js' +import { Keccak } from 'sha3' import { type ExampleNativeTokenTransfers } from '../../target/types/example_native_token_transfers' import { ManagerMessage } from './payloads/common' import { NativeTokenTransfer } from './payloads/transfers' @@ -75,13 +76,17 @@ export class NTT { return this.derive_pda([Buffer.from('inbox_rate_limit'), new BN(chainId).toBuffer('be', 2)]) } - inboxItemAccountAddress(chain: ChainName | ChainId, sequence: BN): PublicKey { + inboxItemAccountAddress(chain: ChainName | ChainId, managerMessage: ManagerMessage): PublicKey { const chainId = coalesceChainId(chain) + const serialized = ManagerMessage.serialize(managerMessage, NativeTokenTransfer.serialize) + const hasher = new Keccak(256) + hasher.update(serialized) + const hash = hasher.digest('hex') return this.derive_pda( [ Buffer.from('inbox_item'), new BN(chainId).toBuffer('be', 2), - sequence.toBuffer('be', 8) + Buffer.from(hash, 'hex') ]) } @@ -370,7 +375,7 @@ export class NTT { async createReleaseInboundMintInstruction(args: { payer: PublicKey chain: ChainName | ChainId - sequence: BN + managerMessage: ManagerMessage revertOnDelay: boolean recipient?: PublicKey config?: Config @@ -382,7 +387,7 @@ export class NTT { } const recipientAddress = - args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress + args.recipient ?? (await this.getInboxItem(args.chain, args.managerMessage)).recipientAddress const mint = await this.mintAccountAddress(config) @@ -394,7 +399,7 @@ export class NTT { common: { payer: args.payer, config: { config: this.configAccountAddress() }, - inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), + inboxItem: this.inboxItemAccountAddress(args.chain, args.managerMessage), recipient: getAssociatedTokenAddressSync(mint, recipientAddress), mint, tokenAuthority: this.tokenAuthorityAddress(), @@ -406,7 +411,7 @@ export class NTT { async releaseInboundMint(args: { payer: Keypair chain: ChainName | ChainId - sequence: BN + managerMessage: ManagerMessage revertOnDelay: boolean config?: Config }): Promise { @@ -429,7 +434,7 @@ export class NTT { async createReleaseInboundUnlockInstruction(args: { payer: PublicKey chain: ChainName | ChainId - sequence: BN + managerMessage: ManagerMessage revertOnDelay: boolean recipient?: PublicKey config?: Config @@ -441,7 +446,7 @@ export class NTT { } const recipientAddress = - args.recipient ?? (await this.getInboxItem(args.chain, args.sequence)).recipientAddress + args.recipient ?? (await this.getInboxItem(args.chain, args.managerMessage)).recipientAddress const mint = await this.mintAccountAddress(config) @@ -453,7 +458,7 @@ export class NTT { common: { payer: args.payer, config: { config: this.configAccountAddress() }, - inboxItem: this.inboxItemAccountAddress(args.chain, args.sequence), + inboxItem: this.inboxItemAccountAddress(args.chain, args.managerMessage), recipient: getAssociatedTokenAddressSync(mint, recipientAddress), mint, tokenAuthority: this.tokenAuthorityAddress(), @@ -466,7 +471,7 @@ export class NTT { async releaseInboundUnlock(args: { payer: Keypair chain: ChainName | ChainId - sequence: BN + managerMessage: ManagerMessage revertOnDelay: boolean config?: Config }): Promise { @@ -601,7 +606,9 @@ export class NTT { const parsedVaa = parseVaa(args.vaa) const endpointMessage = WormholeEndpointMessage.deserialize( - parsedVaa.payload, a => ManagerMessage.deserialize(a, a => a) + parsedVaa.payload, a => ManagerMessage.deserialize( + a, NativeTokenTransfer.deserialize + ) ) const managerMessage = endpointMessage.managerPayload // NOTE: we do an 'as ChainId' cast here, which is generally unsafe. @@ -619,7 +626,7 @@ export class NTT { sibling: managerSibling, endpointMessage: this.endpointMessageAccountAddress(chainId, new BN(managerMessage.sequence.toString())), endpoint: { endpoint: this.registeredEndpointAddress(this.program.programId) }, - inboxItem: this.inboxItemAccountAddress(chainId, new BN(managerMessage.sequence.toString())), + inboxItem: this.inboxItemAccountAddress(chainId, managerMessage), inboxRateLimit, outboxRateLimit: this.outboxRateLimitAccountAddress(), }) @@ -677,7 +684,7 @@ export class NTT { const releaseArgs = { ...args, payer: args.payer.publicKey, - sequence: new BN(managerMessage.sequence.toString()), + managerMessage, recipient: new PublicKey(managerMessage.payload.recipientAddress), chain: chainId, revertOnDelay: false @@ -693,7 +700,7 @@ export class NTT { await this.sendAndConfirmTransaction(tx, signers) // Let's check if the transfer was released - const inboxItem = await this.getInboxItem(chainId, new BN(managerMessage.sequence.toString())) + const inboxItem = await this.getInboxItem(chainId, managerMessage) return inboxItem.releaseStatus.released !== null } @@ -723,8 +730,8 @@ export class NTT { return (await this.getConfig(config)).tokenProgram } - async getInboxItem(chain: ChainName | ChainId, sequence: BN): Promise { - return await this.program.account.inboxItem.fetch(this.inboxItemAccountAddress(chain, sequence)) + async getInboxItem(chain: ChainName | ChainId, managerMessage: ManagerMessage): Promise { + return await this.program.account.inboxItem.fetch(this.inboxItemAccountAddress(chain, managerMessage)) } /** diff --git a/solana/yarn.lock b/solana/yarn.lock index 5b1b72d0d..a3c5451df 100644 --- a/solana/yarn.lock +++ b/solana/yarn.lock @@ -4486,7 +4486,7 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" -sha3@^2.1.1: +sha3@^2.1.1, sha3@^2.1.4: version "2.1.4" resolved "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz" integrity sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg== From b7d2377ffd54a39f010fa21f6b61e8855a97433c Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 16 Feb 2024 03:54:56 +0400 Subject: [PATCH 52/90] solana: enabled endpoints bitmap --- .../src/bitmap.rs | 19 ++++++++++++------- .../src/config.rs | 4 +++- .../src/instructions/admin.rs | 2 +- .../src/instructions/initialize.rs | 3 ++- .../src/instructions/redeem.rs | 7 ++++++- .../src/registered_endpoint.rs | 4 ++++ 6 files changed, 28 insertions(+), 11 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/bitmap.rs b/solana/programs/example-native-token-transfers/src/bitmap.rs index 0e951941f..9d9230bd7 100644 --- a/solana/programs/example-native-token-transfers/src/bitmap.rs +++ b/solana/programs/example-native-token-transfers/src/bitmap.rs @@ -25,8 +25,9 @@ impl Bitmap { BM::<128>::from_value(self.map).get(index as usize) } - pub fn count_ones(&self) -> u8 { - BM::<128>::from_value(self.map).len().try_into().unwrap() + pub fn count_enabled_votes(&self, enabled: Bitmap) -> u8 { + let bm = BM::<128>::from_value(self.map) & BM::<128>::from_value(enabled.map); + bm.len() as u8 } } @@ -36,21 +37,25 @@ mod tests { #[test] fn test_bitmap() { + let mut enabled = Bitmap::from_value(u128::MAX); let mut bm = Bitmap::new(); - assert_eq!(bm.count_ones(), 0); + assert_eq!(bm.count_enabled_votes(enabled), 0); bm.set(0, true); - assert_eq!(bm.count_ones(), 1); + assert_eq!(bm.count_enabled_votes(enabled), 1); assert_eq!(bm.get(0), true); assert_eq!(bm.get(1), false); bm.set(1, true); - assert_eq!(bm.count_ones(), 2); + assert_eq!(bm.count_enabled_votes(enabled), 2); assert_eq!(bm.get(0), true); assert_eq!(bm.get(1), true); bm.set(0, false); - assert_eq!(bm.count_ones(), 1); + assert_eq!(bm.count_enabled_votes(enabled), 1); assert_eq!(bm.get(0), false); assert_eq!(bm.get(1), true); bm.set(18, true); - assert_eq!(bm.count_ones(), 2); + assert_eq!(bm.count_enabled_votes(enabled), 2); + + enabled.set(18, false); + assert_eq!(bm.count_enabled_votes(enabled), 1); } } diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index cd5eebbc6..56bdfae8b 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -2,7 +2,7 @@ use std::ops::{Deref, DerefMut}; use anchor_lang::prelude::*; -use crate::chain_id::ChainId; +use crate::{chain_id::ChainId, bitmap::Bitmap}; #[account] #[derive(InitSpace)] @@ -30,6 +30,8 @@ pub struct Config { /// The number of endpoints that must attest to a transfer before it is /// accepted. pub threshold: u8, + /// Bitmap of enabled endpoints + pub enabled_endpoints: Bitmap, /// Pause the program. This is useful for upgrades and other maintenance. pub paused: bool, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index e006f9762..ac3fa29e0 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -167,7 +167,7 @@ pub fn register_endpoint(ctx: Context) -> Result<()> { enabled: true, }); - // TODO set in enabled bitmap + ctx.accounts.config.enabled_endpoints.set(id, true); Ok(()) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 62674f046..fdefe8bb0 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -6,7 +6,7 @@ use crate::{ error::NTTError, normalized_amount::NormalizedAmount, queue::{outbox::OutboxRateLimit, rate_limit::RateLimitState}, - sequence::Sequence, + sequence::Sequence, bitmap::Bitmap, }; // TODO: upgradeability @@ -98,6 +98,7 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> next_endpoint_id: 0, // NOTE: can't be changed for now threshold: 1, + enabled_endpoints: Bitmap::new(), }); ctx.accounts.seq.set_inner(Sequence { diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index e836e5b29..9835393f5 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -105,7 +105,12 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { accs.inbox_item.votes.set(accs.endpoint.id, true); // TODO: if endpoints can be disabled, this should only cound enabled endpoints - if accs.inbox_item.votes.count_ones() < accs.config.threshold { + if accs + .inbox_item + .votes + .count_enabled_votes(accs.config.enabled_endpoints) + < accs.config.threshold + { return Ok(()); } diff --git a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs index 0b19fb192..d8de88fb0 100644 --- a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs +++ b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs @@ -8,6 +8,10 @@ pub struct RegisteredEndpoint { pub bump: u8, pub id: u8, pub endpoint_address: Pubkey, + /// Whether the endpoint is enabled. + /// NOTE: there is a bitmap in the config account which must be kept in sync + /// with this. If endpoint disabling is implemented, the bitmap must be updated + /// in the same transaction as the endpoint account. pub enabled: bool, } From d5f0580860eda8e4cbeed936413b03184b388e2f Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 16 Feb 2024 04:06:56 +0400 Subject: [PATCH 53/90] solana: reorder Makefile targets --- solana/Makefile | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/solana/Makefile b/solana/Makefile index 7fc2d67fc..58d2ab3f7 100644 --- a/solana/Makefile +++ b/solana/Makefile @@ -1,4 +1,5 @@ -# in this Makefile, ensure jq binary is available +.PHONY: build +build: _anchor-build target/idl/example_native_token_transfers.json # remove the generics from the idl file. This is necessary as of anchor 0.29.0, because # the javascript library does not support generics yet, and just panics @@ -11,8 +12,5 @@ target/idl/example_native_token_transfers.json: _anchor-build: @anchor build -.PHONY: build -build: _anchor-build target/idl/example_native_token_transfers.json - anchor-test: build target/idl/example_native_token_transfers.json anchor test --skip-build From f7d5ae0cc41130c7512f78615bd5536067009bc3 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 16 Feb 2024 04:12:33 +0400 Subject: [PATCH 54/90] solana: cargo fmt --- .../example-native-token-transfers/src/config.rs | 2 +- .../example-native-token-transfers/src/endpoints/mod.rs | 2 +- .../src/endpoints/wormhole/messages.rs | 1 - .../src/instructions/initialize.rs | 3 ++- .../src/instructions/release_inbound.rs | 6 +++++- .../src/instructions/transfer.rs | 3 ++- .../programs/example-native-token-transfers/src/lib.rs | 2 +- .../src/normalized_amount.rs | 9 +-------- .../src/queue/rate_limit.rs | 5 +---- .../example-native-token-transfers/tests/common/mod.rs | 2 +- .../tests/sdk/endpoints/wormhole/instructions/mod.rs | 2 +- .../tests/sdk/instructions/redeem.rs | 2 +- .../example-native-token-transfers/tests/sdk/mod.rs | 2 +- 13 files changed, 18 insertions(+), 23 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 56bdfae8b..6e84d239d 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -2,7 +2,7 @@ use std::ops::{Deref, DerefMut}; use anchor_lang::prelude::*; -use crate::{chain_id::ChainId, bitmap::Bitmap}; +use crate::{bitmap::Bitmap, chain_id::ChainId}; #[account] #[derive(InitSpace)] diff --git a/solana/programs/example-native-token-transfers/src/endpoints/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/mod.rs index 7ab58a710..9dfec0804 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/mod.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/mod.rs @@ -1,2 +1,2 @@ -pub mod wormhole; pub mod accounts; +pub mod wormhole; diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs index 477668610..f06b45dfd 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs @@ -1,6 +1,5 @@ use crate::messages::Endpoint; - #[derive(PartialEq, Eq)] pub struct WormholeEndpoint {} diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index fdefe8bb0..fbc3071e0 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -2,11 +2,12 @@ use anchor_lang::prelude::*; use anchor_spl::{associated_token::AssociatedToken, token_interface}; use crate::{ + bitmap::Bitmap, chain_id::ChainId, error::NTTError, normalized_amount::NormalizedAmount, queue::{outbox::OutboxRateLimit, rate_limit::RateLimitState}, - sequence::Sequence, bitmap::Bitmap, + sequence::Sequence, }; // TODO: upgradeability diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 8d2fe9eff..7c865c2e0 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -1,7 +1,11 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; -use crate::{config::*, error::NTTError, queue::inbox::{InboxItem, ReleaseStatus}}; +use crate::{ + config::*, + error::NTTError, + queue::inbox::{InboxItem, ReleaseStatus}, +}; #[derive(Accounts)] pub struct ReleaseInbound<'info> { diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 471d635b8..a621504a2 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -2,6 +2,7 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; use crate::{ + bitmap::Bitmap, chain_id::ChainId, clock::current_timestamp, config::*, @@ -11,7 +12,7 @@ use crate::{ inbox::InboxRateLimit, outbox::{OutboxItem, OutboxRateLimit}, rate_limit::RateLimitResult, - }, bitmap::Bitmap, + }, }; // this will burn the funds and create an account that either allows sending the diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index c3e4be2d9..75952d754 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -1,5 +1,6 @@ use anchor_lang::prelude::*; +pub mod bitmap; pub mod chain_id; pub mod clock; pub mod config; @@ -12,7 +13,6 @@ pub mod queue; pub mod registered_endpoint; pub mod sequence; pub mod sibling; -pub mod bitmap; use endpoints::wormhole::instructions::*; diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index 87884a2fd..b8de4aa3c 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -14,14 +14,7 @@ use wormhole_io::{Readable, Writeable}; pub const NORMALIZED_DECIMALS: u8 = 8; -#[derive( - Debug, - Clone, - Copy, - AnchorSerialize, - AnchorDeserialize, - InitSpace, -)] +#[derive(Debug, Clone, Copy, AnchorSerialize, AnchorDeserialize, InitSpace)] pub struct NormalizedAmount { pub amount: u64, pub decimals: u8, diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index b13c12d3f..547b0cb2e 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -97,10 +97,7 @@ impl RateLimitState { /// Refills the capacity by the given amount. /// This is used to replenish the capacity via backflows. pub fn refill(&mut self, amount: NormalizedAmount) { - self.capacity_at_last_tx = self - .capacity() - .saturating_add(amount) - .min(self.limit); + self.capacity_at_last_tx = self.capacity().saturating_add(amount).min(self.limit); self.last_tx_timestamp = current_timestamp(); } diff --git a/solana/programs/example-native-token-transfers/tests/common/mod.rs b/solana/programs/example-native-token-transfers/tests/common/mod.rs index b430fd2c8..e5d25c752 100644 --- a/solana/programs/example-native-token-transfers/tests/common/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/common/mod.rs @@ -1,6 +1,6 @@ #![allow(async_fn_in_trait)] pub mod account_json_utils; +pub mod hack; pub mod query; pub mod setup; pub mod submit; -pub mod hack; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs index f6db77f05..571d4fd22 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs @@ -1,2 +1,2 @@ -pub mod receive_message; pub mod admin; +pub mod receive_message; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs index 6aa8cd695..c0014ed15 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs @@ -23,7 +23,7 @@ pub fn redeem(ntt: &NTT, accs: Redeem, args: RedeemArgs) -> Instruction { sibling: accs.sibling, endpoint_message: accs.endpoint_message, endpoint: EnabledEndpoint { - endpoint: ntt.registered_endpoint(&accs.endpoint) + endpoint: ntt.registered_endpoint(&accs.endpoint), }, inbox_item: accs.inbox_item, inbox_rate_limit: accs.inbox_rate_limit, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs index f3cd5e69b..5623dba3d 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/mod.rs @@ -1,3 +1,3 @@ -pub mod instructions; pub mod accounts; pub mod endpoints; +pub mod instructions; From 06e76e254ffebcefc7ac7cbe81744bda1bf48562 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 16 Feb 2024 04:14:38 +0400 Subject: [PATCH 55/90] solana: CI --- .github/workflows/build.yml | 108 +++++++++ solana/Anchor.toml | 2 +- solana/Cargo.lock | 205 +++++++++--------- .../example-native-token-transfers/Cargo.toml | 2 +- .../src/bitmap.rs | 18 +- .../src/instructions/release_outbound.rs | 2 +- .../src/instructions/transfer.rs | 2 +- .../example-native-token-transfers/src/lib.rs | 2 +- .../src/messages.rs | 2 +- .../src/normalized_amount.rs | 2 +- .../src/queue/inbox.rs | 4 +- .../src/queue/rate_limit.rs | 9 +- .../src/sequence.rs | 2 +- .../tests/cancel_flow.rs | 7 +- .../tests/common/hack.rs | 2 +- .../tests/common/setup.rs | 2 +- .../tests/sdk/accounts.rs | 2 +- .../tests/transfer.rs | 1 - solana/rust-toolchain | 3 + 19 files changed, 241 insertions(+), 136 deletions(-) create mode 100644 .github/workflows/build.yml create mode 100644 solana/rust-toolchain diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..5e53af405 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,108 @@ +name: Build +on: + workflow_dispatch: + pull_request: + push: + branches: + - main + - dev +jobs: + solana: + runs-on: ubuntu-20.04 + env: + RUSTFLAGS: -Dwarnings + + steps: + - uses: actions/checkout@v3 + - name: Get rust toolchain version + id: toolchain + run: | + RUST_VERSION="$(awk '/channel =/ { print substr($3, 2, length($3)-2) }' solana/rust-toolchain)" + echo "::set-output name=version::${RUST_VERSION}" + + - name: Get solana version + id: solana + run: | + SOLANA_VERSION="$(awk '/solana-program =/ { print substr($3, 3, length($3)-3) }' solana/programs/example-native-token-transfers/Cargo.toml)" + echo "::set-output name=version::${SOLANA_VERSION}" + + - name: Cache rust toolchain + uses: actions/cache@v3 + env: + cache-name: solana-toolchain + with: + path: | + ~/.cargo/bin + ~/.rustup + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ steps.toolchain.outputs.version }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Install rust toolchain + uses: dtolnay/rust-toolchain@55c7845fad90d0ae8b2e83715cb900e5e861e8cb + with: + toolchain: ${{ steps.toolchain.outputs.version }} + components: "clippy,rustfmt" + + - name: Cache rust packages / build cache + uses: actions/cache@v3 + env: + cache-name: solana-rust-packages + with: + path: | + ~/.cargo/bin + ~/.cargo/registry + ~/.cargo/git/db + solana/target + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ hashFiles('solana/Cargo.lock') }} + restore-keys: | + ${{ runner.os }}-build-${{ env.cache-name }}- + ${{ runner.os }}-build- + ${{ runner.os }}- + + - name: Run `cargo fmt` + run: cargo fmt --check --all --manifest-path solana/Cargo.toml + + - name: Run `cargo check` + run: cargo check --workspace --tests --manifest-path solana/Cargo.toml + + - name: Run `cargo clippy` + run: cargo clippy --workspace --tests --manifest-path solana/Cargo.toml + + - name: Cache solana tools + id: cache-solana + uses: actions/cache@v3 + env: + cache-name: solana-tools + with: + path: | + ~/.local/share/solana/install/ + ~/.cache/solana/ + key: ${{ runner.os }}-build-${{ env.cache-name }}-${{ steps.solana.outputs.version }} + + - if: ${{ steps.cache-solana.outputs.cache-hit != 'true' }} + name: Install solana tools + env: + SOLANA_VERSION: ${{ steps.solana.outputs.version }} + run: | + sh -c "$(curl -sSfL https://release.solana.com/v${SOLANA_VERSION}/install)" + ~/.local/share/solana/install/active_release/bin/sdk/sbf/scripts/install.sh + + - name: Run unit tests + env: + RUST_BACKTRACE: "1" + run: | + cd solana + export BPF_OUT_DIR="$(pwd)/target/deploy" + export PATH="${HOME}/.local/share/solana/install/active_release/bin:${PATH}" + + mkdir -p "${BPF_OUT_DIR}" + + BPF_PACKAGES=( + programs/example-native-token-transfers/Cargo.toml + ) + for p in "${BPF_PACKAGES[@]}"; do + cargo test-sbf --manifest-path "${p}" + done diff --git a/solana/Anchor.toml b/solana/Anchor.toml index ccc41f696..af735de58 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -2,7 +2,7 @@ seeds = false skip-lint = false [programs.localnet] -solana_multi_endpoint = "5cR7BT9Qjs9CMCekudXKsypXrJrttUzYwgXEf3Z9RgoQ" +solana_multi_endpoint = "F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV" [registry] url = "https://api.apr.dev" diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 3ade7c39b..f3273ff45 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -2136,13 +2136,12 @@ dependencies = [ [[package]] name = "light-poseidon" -version = "0.2.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +checksum = "a5b439809cdfc0d86ecc7317f1724df13dfa665df48991b79e90e689411451f7" dependencies = [ "ark-bn254", "ark-ff", - "num-bigint 0.4.4", "thiserror", ] @@ -3489,9 +3488,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c48541b782c0fbb15ac202f2487353c3649fbf868afacae6ca1c9fe0f7df0b4a" +checksum = "ea108fb41a4d6c3bafaf7d78fa94a6c2c6e863dc4e773c8e57dec22161be42b0" dependencies = [ "Inflector", "base64 0.21.7", @@ -3513,9 +3512,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a5a48e3dfffb0699a7b2c6a0714f4c6dd974a8fd744b4e4ac67238ed3fc3ba0" +checksum = "4f1667ba2a54bf033667d17eaf3b12a7aee362b7b55725a6b594b67cb8e8fc7f" dependencies = [ "arrayref", "bincode", @@ -3572,9 +3571,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "918eaf2c89e92960ab5fa7c21921fb3921ace134770c371b5d25b13569e2993f" +checksum = "d2ee56e31d9b1733f874bfe5b54abef43fb49810f7291deccbdf713527b44b6f" dependencies = [ "bincode", "bytemuck", @@ -3593,9 +3592,9 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c565499d7fdb92ac2dc6ad2de23c9b8e9cedd54630953e8fcdd98a03a898b8e6" +checksum = "4118d1d75cecd79defb0f8de61e428d186fb873d17641e817f80caed202a5647" dependencies = [ "borsh 0.10.3", "futures", @@ -3610,9 +3609,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b88919cc1dc06b78da78d2f82b0afd094926981d7538ed68fe204201c5f60d72" +checksum = "1fdea91839646ec597a1dd6f5e884cb5c30d574db21970fcc20b04deb4747d96" dependencies = [ "serde", "solana-sdk", @@ -3621,9 +3620,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fcf6f5a00e3e30b33a6f72c4e5b02a0933dfdf294efabf47dfed4d6a1640928" +checksum = "faa79d64545dcb21680e6939ed63bd9e88425f55a098492d96c9407c7a5b4990" dependencies = [ "bincode", "crossbeam-channel", @@ -3641,9 +3640,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1f0c6b35b805f7bf31d08b3c609fb37eb13031d675e2e4db227873e1050c27" +checksum = "91dc36edd5b4d37b852accbed3bf41dde302954d7716565700e0fd81e0f5dced" dependencies = [ "bincode", "byteorder", @@ -3660,9 +3659,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93f4038e5bf34bcca677fd749512fbca8db2db21ca629b6b1095e502d11e4265" +checksum = "36bf733cdfccac6bf2cb1e74f3bd247bd59c2024fc72760cf3ac4cb334e6b86d" dependencies = [ "bv", "bytemuck", @@ -3678,9 +3677,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a78952f057a7d4f87b3a6a5f4a8705cefbb67bbc00ecffc2c75b168a54c931" +checksum = "1114079301af35bed62dba298beaad478a3788cbc376def9a56b8e9d26fc1b8f" dependencies = [ "chrono", "clap 2.34.0", @@ -3695,9 +3694,9 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e85b1d68bce244750bd02c4d71ed0df415c9b8d91a4b0f1e7ce6b97748db46c" +checksum = "fcc2d00016dc7975d866dd9ef3ffdd7c6dffec972495645953c07e587330e135" dependencies = [ "async-trait", "bincode", @@ -3728,9 +3727,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cc2978cf6a5335576b2c12ce4bb3cf6c95178a9e2f1f110a39c17c7ca79ba94" +checksum = "33e650787669f715616444f32bafabf1fe17240d9154e182f83c3949bdd3d627" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -3738,9 +3737,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c66c9c5bbc148affd42127061af9c0e7e5901b5e5142e951912f165272203c1" +checksum = "96a1f220474e7b9ed04cf450b13fa5ff4d03e7b7acefd36edfbe3d4c8d3f4ebb" dependencies = [ "bincode", "chrono", @@ -3752,9 +3751,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4180686b6384013f062242ee9f18ea6ea68268e9b35fa9aa0206c2a622d1773f" +checksum = "9ac0b83f1486f474424f77d2af10608305cac2e1184fde39a13c2a4a8e4c7cc8" dependencies = [ "async-trait", "bincode", @@ -3774,9 +3773,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ad4fb3639f3d1751fad91bfbfc07d99427633705328d2e123fe578ca9dedf67" +checksum = "77597dfb4f40a753218811c06647d6bf63d31060f67336212acff6c1282efb8e" dependencies = [ "lazy_static", "log", @@ -3798,9 +3797,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "174a53486f9e0774680c2b6a53568a15c11ccc5cef1263a7e7d42958bfd61792" +checksum = "098378043a888c680de07eee987bf927e23e0720b472ba61c753d7b3757e6b3e" dependencies = [ "ahash 0.8.6", "blake3", @@ -3828,9 +3827,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e69b9bc56d9f92bd194569091d655be239a51a934df1db247e0c8bd2a9352909" +checksum = "c5f48c89a8a3a12f6a409a45fef50dae642211eae0207a91f01211aebb270026" dependencies = [ "proc-macro2", "quote", @@ -3840,9 +3839,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a62b38cd73c136635f9e8e56185b56d006a508bab67d4a06764efd1f3b0ef7" +checksum = "a86dfb559013436f20bbf6ae56323630319d853c82836e1a9a3dcae1180b9497" dependencies = [ "log", "solana-measure", @@ -3853,9 +3852,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccb457626944fd2f192285c8281e887081dc346920c181aaf165426dbf081859" +checksum = "d7fa5daba09e7c2bc579b0d3151f649496f148a0ac2054bb042915fbfe9c1678" dependencies = [ "env_logger", "lazy_static", @@ -3864,9 +3863,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2a8bb3ec59a415b1c30827001c38af358a0c244e00a3d5280ca0b0ed264036" +checksum = "e87403b9fb2abd9f2f2b2879ca9e56e14b5ae58f145466e3e893a7810bcbceff" dependencies = [ "log", "solana-sdk", @@ -3874,9 +3873,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c89e3237a73f781e0156fe419831c554f6807eb4f4bffea42535be9627d6fc1" +checksum = "e4b504a682911c4bf85b21278720870555f5996e2991daf54ea4ce300012e93e" dependencies = [ "crossbeam-channel", "gethostname", @@ -3889,9 +3888,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ec445e2d9dbfab7360bc0d846a676e318c13eb4d1e0359ef199187d07795d02" +checksum = "a573d966fd61609501401dc1350b6ba1d0dee91c166453ec77b2fb312e8072b1" dependencies = [ "bincode", "clap 3.2.25", @@ -3911,9 +3910,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7b58cc4a2f4f450361bc8c1a24a94383c659e6212a74e6080a410f7d87e05a6" +checksum = "fcffede3b37ccdddbd57f93e4228b268f05c0a5cb44cb6e382ed8a31a15f5573" dependencies = [ "ahash 0.8.6", "bincode", @@ -3928,10 +3927,7 @@ dependencies = [ "nix", "rand 0.8.5", "rayon", - "rustc_version", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", "solana-metrics", "solana-rayon-threadlimit", "solana-sdk", @@ -3940,9 +3936,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c183d16916dd70ce2b59a4b39088f5094649a592e475fb9ebfc3cfe78b3a192c" +checksum = "6e8834ffcd3773375e7fce4b261efefebbb64409da78e1627cbc4c2632139921" dependencies = [ "ark-bn254", "ark-ec", @@ -3994,9 +3990,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fca7d79b03e54e108069f32cf553c863838b647be7f7135644f8a1d2bdcd3a1" +checksum = "99127d74ad7a383b7f3dae2ecaebfc7926250fb7cef19b67fb344811d020dc14" dependencies = [ "base64 0.21.7", "bincode", @@ -4022,9 +4018,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5c27258c216a68f7fe927da2392d23cf1d1a329fccd888f3287cbf922614772" +checksum = "444889fcaf4588b2aa7733aa2f726b80c126026d60d79f882064b06f70fea05b" dependencies = [ "assert_matches", "async-trait", @@ -4044,7 +4040,6 @@ dependencies = [ "solana-runtime", "solana-sdk", "solana-vote-program", - "solana_rbpf", "test-case", "thiserror", "tokio", @@ -4052,9 +4047,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d90c6e27f0d1e627728f137db688c45accb1b7ae839021b978d1dcceff40d7a3" +checksum = "f271c0f60d010af98f03a595552891ca3f497e7074e2225131c5bb24fadca9b8" dependencies = [ "crossbeam-channel", "futures-util", @@ -4077,9 +4072,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f340646d1bdd7b7c8e0c71f1f817a4eaeba35c06f025944c52df8f82bb565c79" +checksum = "09e9e5f5bea29716b4c14d319058b4e01c5837d68bd29acbdfaccbeebddac68d" dependencies = [ "async-mutex", "async-trait", @@ -4104,9 +4099,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7effa9e68a7ab9883f7fb4a91c083970223e8e8e355979eb605279608fafa6b7" +checksum = "e864b2647831d5cad75bafa9234590821a97eba780c131fc12dc3bc45c1d9916" dependencies = [ "lazy_static", "num_cpus", @@ -4114,9 +4109,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e59fee3edad929473b7178f84ae58dbb3feb004a26873c8ab557b3aecfaa6d87" +checksum = "8d2ac9610026a977828af8b73984fdb2bac21f48bcf6b1f37767df31ca1cb0db" dependencies = [ "console", "dialoguer", @@ -4133,9 +4128,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94ae66b579851b5142ace6133b95192b38f9a72fb4a81ce936f0af92977c062f" +checksum = "54b9bdf8cf0b55be95bd4198d2706a6536ff30957b8c939a2fdee0627343793b" dependencies = [ "async-trait", "base64 0.21.7", @@ -4159,9 +4154,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0a62a61c8c5989f2b5e4b75bda30b4647ad4affbcfe4a2890b1adb05e2b54c8" +checksum = "d219157e9a0cf86a96b1d5601751df75340e2add88eca5ab1b0941a42307f2f1" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -4181,9 +4176,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9db51df524aceb35e305b735086191db052dc163d09b6d5d9be65e216ab7413b" +checksum = "01995b2fea7b6d2623fd3ad00a4af6426f7eb225f8d529acf2397ea8cb6d3f10" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4194,9 +4189,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba17961673c7ca5ac090d4e413d6d8b59956f03c36e1a20597b1d13ea4513077" +checksum = "ebf7b2d9c9ae6301651ad601219e9c9ca879d9f11f86673c2eea6197aca4aafa" dependencies = [ "arrayref", "base64 0.21.7", @@ -4271,9 +4266,9 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "284587e20a7256621b6061589a6d7f9fc1c1bcb9f25d183555034f7817ec49a6" +checksum = "dd1d4bf7b8f6a0350b8a1a81346a5819d9bd5c93096c2bf079f01b905dfe0443" dependencies = [ "assert_matches", "base64 0.21.7", @@ -4325,9 +4320,9 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fee7090babd8fe6cedd2e377366979464d29fa958bf5fc6554f6c7577b73fd4" +checksum = "170f3c87d862ba5c74c03fa37a2867c10aa68e7b210bdf004c7a8b330284c789" dependencies = [ "bs58 0.4.0", "proc-macro2", @@ -4338,9 +4333,9 @@ dependencies = [ [[package]] name = "solana-send-transaction-service" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d9d89f6816738de42436b6cb08798b8023a5106effc4f0c37ddca9ee8b10fe32" +checksum = "4d4d5c756cd87641dd720dc7874182149d106f6753b0ba758023f1f1523fb8d9" dependencies = [ "crossbeam-channel", "log", @@ -4354,9 +4349,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e46cec174bb995bb71ea3c875d17662d4c34f6e6ab853a08e9c3ddc06f0927c" +checksum = "8ea1b3f9e4a288970a308f47f25308ebba071100eae72f374fdcd777647315c9" dependencies = [ "bincode", "log", @@ -4369,9 +4364,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4219f40db983a290ea75212b9e47013a47715eb224ca18e05bd094d86baefc37" +checksum = "ca08a69ae2ac103925bf367020e646dcdbb778ead2ce8685d962ca15616f0fc5" dependencies = [ "async-channel", "bytes", @@ -4401,9 +4396,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9d710ecc45f8bb0219e46237df572efdf63fa2a1016d0a62e3b4a74f471863" +checksum = "dcda9bf5b7e7b8726c6ddc7f06fc9110875e688e197e0602721b1b425cfc5cc2" dependencies = [ "bincode", "log", @@ -4415,9 +4410,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f8d9eb19550425cbb6a96fdea18171a2e44529414fe09f8cf7a238a78fd9a37" +checksum = "1d2c780ce4d234abbde57ed94342e882c0170c6ebe7d8f1f02763f6cb88a925d" dependencies = [ "bincode", "log", @@ -4430,9 +4425,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "795d4d7e76f87640d7a3d1ab6ebc2376d9b9d76a7c2664653628dc6f4bc64ecc" +checksum = "e00eb9926169f8d4f9f6af95410decc01545a9ce991e12781cb8ae1515ab833f" dependencies = [ "async-trait", "bincode", @@ -4454,9 +4449,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176b554ca42e29abd21d56f31c01599f9b334e65b22911bcdb691b9b02706636" +checksum = "0f8af464b440c000a3e5306509f02240150b5311fffc4534738e1bdfdb604604" dependencies = [ "Inflector", "base64 0.21.7", @@ -4479,9 +4474,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a60895d452a9e2de1115d4ebaef537fb608b9a6e206cb7b24c82881a35348e3" +checksum = "f2763ee4af6d7a92cd5b70679a8b46ea13f167e59a8f5f294041905b5258d9ae" dependencies = [ "async-trait", "solana-connection-cache", @@ -4494,9 +4489,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "572a7a0f49ee43473c2f235432f98b2594c3a4e8cc9a1befd7a085be8192f5bd" +checksum = "9d133bdd437accc92171e40d76cd5cd76cba59d58f6a2f89b02c8621ffab3b5d" dependencies = [ "log", "rustc_version", @@ -4510,9 +4505,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d11054cc7d40221e3b80aded18b4436c57d0ae8a586aff88e32e22099e99298" +checksum = "840a57075b446db53d5591e107b32b46afeff7c5e1172c2ff90ed30067b8650a" dependencies = [ "crossbeam-channel", "itertools", @@ -4529,9 +4524,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89cffa52ab296ccc95ced7ae7875534cb4fd1cbb0bd9b8ad20e7ec55f15bcd5d" +checksum = "733573c6e800f04d8721bd4b861165c17db94026e2c9da28d6a3553e095efacb" dependencies = [ "bincode", "log", @@ -4551,9 +4546,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "83089a1e9b5ceef00ac0d399922604b12e925667fc6c3f0024398bb805a4ae27" +checksum = "4d2aa189efb2af7b1cf2339808b9bc236addeb776e62e5b5527947d2a68c699d" dependencies = [ "bytemuck", "num-derive 0.3.3", @@ -4565,9 +4560,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.13" +version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e8e2f6c0d78bc9eb07efc1fcd034dd0fcc508af8809343ac861096aab84876" +checksum = "34f2a9ce880cac8d1f7f0cbfaaac07fb84e163e7f616125f4980c13a21b17727" dependencies = [ "aes-gcm-siv", "base64 0.21.7", @@ -4594,9 +4589,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.8.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" +checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196" dependencies = [ "byteorder", "combine", diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index 2206769e2..dee1a7fbf 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -26,7 +26,7 @@ anchor-lang = { version = "0.29.0", features = ["init-if-needed"] } anchor-spl = "0.29.0" bitmaps = "3.2.1" hex = "0.4.3" -solana-program = "1.17.2" +solana-program = "=1.17.2" wormhole-anchor-sdk = "0.29.0-alpha.1" wormhole-io = "0.1.3" diff --git a/solana/programs/example-native-token-transfers/src/bitmap.rs b/solana/programs/example-native-token-transfers/src/bitmap.rs index 9d9230bd7..2408eef44 100644 --- a/solana/programs/example-native-token-transfers/src/bitmap.rs +++ b/solana/programs/example-native-token-transfers/src/bitmap.rs @@ -6,6 +6,12 @@ pub struct Bitmap { map: u128, } +impl Default for Bitmap { + fn default() -> Self { + Self::new() + } +} + impl Bitmap { pub fn new() -> Self { Bitmap { map: 0 } @@ -42,16 +48,16 @@ mod tests { assert_eq!(bm.count_enabled_votes(enabled), 0); bm.set(0, true); assert_eq!(bm.count_enabled_votes(enabled), 1); - assert_eq!(bm.get(0), true); - assert_eq!(bm.get(1), false); + assert!(bm.get(0)); + assert!(!bm.get(1)); bm.set(1, true); assert_eq!(bm.count_enabled_votes(enabled), 2); - assert_eq!(bm.get(0), true); - assert_eq!(bm.get(1), true); + assert!(bm.get(0)); + assert!(bm.get(1)); bm.set(0, false); assert_eq!(bm.count_enabled_votes(enabled), 1); - assert_eq!(bm.get(0), false); - assert_eq!(bm.get(1), true); + assert!(!bm.get(0)); + assert!(bm.get(1)); bm.set(18, true); assert_eq!(bm.count_enabled_votes(enabled), 2); diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index 1e54e21a9..d3b1ff269 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -98,7 +98,7 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs payload: NativeTokenTransfer { amount: accs.outbox_item.amount, source_token: accs.config.mint.to_bytes(), - to: accs.outbox_item.recipient_address.clone(), + to: accs.outbox_item.recipient_address, to_chain: accs.outbox_item.recipient_chain, }, }, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index a621504a2..95b9c24c3 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -221,7 +221,7 @@ fn insert_into_outbox( } }; - let sequence = common.seq.next(); + let sequence = common.seq.next_sequence(); common.outbox_item.set_inner(OutboxItem { sequence, diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 75952d754..3ab36f34c 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -18,7 +18,7 @@ use endpoints::wormhole::instructions::*; use instructions::*; -declare_id!("5cR7BT9Qjs9CMCekudXKsypXrJrttUzYwgXEf3Z9RgoQ"); +declare_id!("F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV"); #[program] pub mod example_native_token_transfers { diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 4df51200c..4cb357795 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -239,7 +239,7 @@ where Self { _phantom: PhantomData, message_data: EndpointMessageData { - source_manager: self.source_manager.clone(), + source_manager: self.source_manager, manager_payload: self.manager_payload.clone(), }, } diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index b8de4aa3c..d61f12924 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -152,7 +152,7 @@ mod test { fn test_normalize() { assert_eq!( NormalizedAmount::normalize(100_000_000_000_000_000, 18).amount(), - 100_000_00 + 10_000_000 ); assert_eq!( diff --git a/solana/programs/example-native-token-transfers/src/queue/inbox.rs b/solana/programs/example-native-token-transfers/src/queue/inbox.rs index 6c7f3aad5..bdd41a275 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbox.rs @@ -44,9 +44,7 @@ impl InboxItem { self.release_status = ReleaseStatus::Released; Ok(true) } - ReleaseStatus::Released => { - return Err(NTTError::TransferAlreadyRedeemed.into()); - } + ReleaseStatus::Released => Err(NTTError::TransferAlreadyRedeemed.into()), } } } diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index 547b0cb2e..ef15001fc 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -107,16 +107,15 @@ impl RateLimitState { self.limit = limit; - let new_capacity: NormalizedAmount; - if old_limit > limit { + let new_capacity: NormalizedAmount = if old_limit > limit { // decrease in limit, let diff = old_limit - limit; - new_capacity = current_capacity.saturating_sub(diff); + current_capacity.saturating_sub(diff) } else { // increase in limit let diff = limit - old_limit; - new_capacity = current_capacity.saturating_add(diff); - } + current_capacity.saturating_add(diff) + }; self.capacity_at_last_tx = new_capacity.min(limit); self.last_tx_timestamp = current_timestamp(); diff --git a/solana/programs/example-native-token-transfers/src/sequence.rs b/solana/programs/example-native-token-transfers/src/sequence.rs index 5cf20d484..728bf4e90 100644 --- a/solana/programs/example-native-token-transfers/src/sequence.rs +++ b/solana/programs/example-native-token-transfers/src/sequence.rs @@ -10,7 +10,7 @@ pub struct Sequence { impl Sequence { pub const SEED_PREFIX: &'static [u8] = b"sequence"; - pub fn next(&mut self) -> u64 { + pub fn next_sequence(&mut self) -> u64 { let next = self.sequence; self.sequence += 1; next diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index eb4bac0ab..24bb664fa 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -1,5 +1,4 @@ #![feature(type_changing_struct_update)] -#![feature(async_fn_in_trait)] use anchor_lang::{ prelude::{Clock, Pubkey}, @@ -69,7 +68,7 @@ fn init_redeem_accs( chain_id: u16, manager_message: ManagerMessage, ) -> Redeem { - let accs = Redeem { + Redeem { payer: ctx.payer.pubkey(), sibling: test_data.ntt.sibling(chain_id), endpoint: test_data.ntt.program, @@ -78,9 +77,7 @@ fn init_redeem_accs( .endpoint_message(chain_id, manager_message.sequence), inbox_item: test_data.ntt.inbox_item(chain_id, manager_message), inbox_rate_limit: test_data.ntt.inbox_rate_limit(chain_id), - }; - - accs + } } fn init_receive_message_accs( diff --git a/solana/programs/example-native-token-transfers/tests/common/hack.rs b/solana/programs/example-native-token-transfers/tests/common/hack.rs index 52dfdb192..3a88065ef 100644 --- a/solana/programs/example-native-token-transfers/tests/common/hack.rs +++ b/solana/programs/example-native-token-transfers/tests/common/hack.rs @@ -37,7 +37,7 @@ pub struct PostedVaaHack { impl AccountSerialize for PostedVaaHack { fn try_serialize(&self, writer: &mut W) -> Result<()> { - writer.write(b"vaa")?; + writer.write_all(b"vaa")?; Self::serialize(self, writer)?; Ok(()) } diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index 020f6f573..c058e89a9 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -65,7 +65,7 @@ pub async fn setup_with_extra_accounts( let test_data = setup_accounts(&mut ctx).await; setup_ntt(&mut ctx, &test_data, mode).await; - return (ctx, test_data); + (ctx, test_data) } pub async fn setup(mode: Mode) -> (ProgramTestContext, TestData) { diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 70e653698..b30439fe6 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -146,7 +146,7 @@ impl NTT { pub fn custody(&self, mint: &Pubkey) -> Pubkey { anchor_spl::associated_token::get_associated_token_address_with_program_id( &self.token_authority(), - &mint, + mint, &spl_token::ID, ) } diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 772dfd9d3..60a6a5526 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -1,5 +1,4 @@ #![feature(type_changing_struct_update)] -#![feature(async_fn_in_trait)] use anchor_lang::prelude::{Clock, Pubkey}; use anchor_spl::token::{Mint, TokenAccount}; diff --git a/solana/rust-toolchain b/solana/rust-toolchain new file mode 100644 index 000000000..4c2ee1c3a --- /dev/null +++ b/solana/rust-toolchain @@ -0,0 +1,3 @@ +[toolchain] +channel = "nightly-2023-10-29" +profile = "minimal" From eff2608cf39f72e0c314281a358b78f43c266ed4 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Fri, 16 Feb 2024 19:04:54 +0400 Subject: [PATCH 56/90] solana: test: submit VAAs via core bridge instead of hardcoding them into the ledger at startup. this will allow easier governance testing this should have been a *lot* easier --- solana/Cargo.lock | 99 +++++++++++++ .../example-native-token-transfers/Cargo.toml | 6 + .../tests/cancel_flow.rs | 75 ++++------ .../tests/common/hack.rs | 44 ------ .../tests/common/mod.rs | 1 - .../tests/sdk/accounts.rs | 14 ++ .../tests/sdk/instructions/mod.rs | 1 + .../tests/sdk/instructions/post_vaa.rs | 136 ++++++++++++++++++ 8 files changed, 282 insertions(+), 94 deletions(-) delete mode 100644 solana/programs/example-native-token-transfers/tests/common/hack.rs create mode 100644 solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs diff --git a/solana/Cargo.lock b/solana/Cargo.lock index f3273ff45..e2ef6d79d 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -794,6 +794,17 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "bstr" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c48f0051a4b4c5e0b6d365cd04af53aeaa209e3cc15ec2cdb69e73cc87fbd0dc" +dependencies = [ + "memchr", + "regex-automata", + "serde", +] + [[package]] name = "bumpalo" version = "3.14.0" @@ -1322,6 +1333,12 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "dyn-clone" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "545b22097d44f8a9581187cdf93de7a71e4722bf51200cfaba810865b49a495d" + [[package]] name = "eager" version = "0.1.0" @@ -1474,8 +1491,10 @@ dependencies = [ "base64 0.21.7", "bitmaps 3.2.1", "hex", + "libsecp256k1", "serde", "serde_json", + "serde_wormhole", "sha3 0.10.8", "solana-program", "solana-program-test", @@ -1483,7 +1502,10 @@ dependencies = [ "spl-associated-token-account", "spl-token", "wormhole-anchor-sdk", + "wormhole-governance", "wormhole-io", + "wormhole-raw-vaas", + "wormhole-sdk", ] [[package]] @@ -3219,6 +3241,30 @@ 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" @@ -3313,6 +3359,17 @@ dependencies = [ "syn 2.0.48", ] +[[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.113" @@ -3358,6 +3415,18 @@ dependencies = [ "syn 2.0.48", ] +[[package]] +name = "serde_wormhole" +version = "0.1.0" +source = "git+https://github.com/wormhole-foundation/wormhole?rev=eee4641#eee4641f55954d2d0db47831688a2e97eb20f7ee" +dependencies = [ + "base64 0.13.1", + "itoa", + "serde", + "serde_bytes", + "thiserror", +] + [[package]] name = "sha1" version = "0.10.6" @@ -5821,12 +5890,42 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "wormhole-governance" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "solana-program", + "wormhole-anchor-sdk", + "wormhole-io", +] + [[package]] name = "wormhole-io" version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b021a14ea7bcef9517ed9f81d4466c4a663dd90e726c5724707a976fa83ad8f3" +[[package]] +name = "wormhole-raw-vaas" +version = "0.2.0-alpha.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4b8fed51f54543a57b009ce057df3380269c70971d4d096cc9f5dcc2cb1fdb7" + +[[package]] +name = "wormhole-sdk" +version = "0.1.0" +source = "git+https://github.com/wormhole-foundation/wormhole?rev=eee4641#eee4641f55954d2d0db47831688a2e97eb20f7ee" +dependencies = [ + "anyhow", + "bstr", + "schemars", + "serde", + "serde_wormhole", + "sha3 0.10.8", + "thiserror", +] + [[package]] name = "x509-parser" version = "0.14.0" diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index dee1a7fbf..570deaf62 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -32,6 +32,7 @@ wormhole-io = "0.1.3" [dev-dependencies] hex = "0.4.3" + solana-program-test = "1.17.2" serde_json = "1.0.113" serde = "1.0.196" @@ -40,3 +41,8 @@ solana-sdk = "1.17.2" spl-token = "4" spl-associated-token-account = "2.2.0" sha3 = "0.10.4" +wormhole-governance = { path = "../wormhole-governance" } +wormhole-raw-vaas = "0.2.0-alpha.2" +libsecp256k1 = "=0.6.0" +wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } +serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 24bb664fa..6cba7b3a4 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -1,9 +1,6 @@ #![feature(type_changing_struct_update)] -use anchor_lang::{ - prelude::{Clock, Pubkey}, - AccountSerialize, -}; +use anchor_lang::prelude::*; use common::setup::{TestData, OTHER_CHAIN, OTHER_ENDPOINT, OTHER_MANAGER, THIS_CHAIN}; use example_native_token_transfers::{ chain_id::ChainId, @@ -16,23 +13,21 @@ use example_native_token_transfers::{ }; use sdk::endpoints::wormhole::instructions::receive_message::ReceiveMessage; use solana_program_test::*; -use solana_sdk::{account::Account, signature::Keypair, signer::Signer}; -use wormhole_io::TypePrefixedPayload; +use solana_sdk::{signature::Keypair, signer::Signer}; +use wormhole_sdk::{Address, Vaa}; +use crate::{common::submit::Submittable, sdk::instructions::transfer::transfer}; use crate::{ - common::{hack::PostedVaaHack, query::GetAccountDataAnchor}, + common::{query::GetAccountDataAnchor, setup::setup}, sdk::{ endpoints::wormhole::instructions::receive_message::receive_message, instructions::{ + post_vaa::post_vaa, redeem::{redeem, Redeem}, transfer::Transfer, }, }, }; -use crate::{ - common::{setup::setup_with_extra_accounts, submit::Submittable}, - sdk::instructions::transfer::transfer, -}; pub mod common; pub mod sdk; @@ -96,19 +91,13 @@ fn init_receive_message_accs( } } -/// helper function to write into vaa accounts. -/// this is mostly to avoid having to go through the process of posting the vaa -/// via the wormhole program -/// TODO: in an ideal world it should be very easy to do that, but the sdk -/// doesn't support posting vaas yet. -/// TODO: in an ideal world, writing into these accounts should be even easier, but -/// the sdk doesn't have a working serializer implementation for the vaa account either -fn make_vaa( +async fn post_transfer_vaa( + ctx: &mut ProgramTestContext, + test_data: &TestData, sequence: u64, amount: u64, recipient: &Keypair, -) -> (Pubkey, Account, ManagerMessage) { - let vaa = Keypair::new(); +) -> (Pubkey, ManagerMessage) { let manager_message = ManagerMessage { sequence, sender: [4u8; 32], @@ -125,33 +114,22 @@ fn make_vaa( let endpoint_message: EndpointMessage = EndpointMessage::new(OTHER_MANAGER, manager_message.clone()); - let payload = endpoint_message.to_vec_payload(); - - let vaa_data = PostedVaaHack { - vaa_version: 1, - consistency_level: 32, - vaa_time: 0, - vaa_signature_account: Keypair::new().pubkey(), - submission_time: 0, + let vaa = Vaa { + version: 1, + guardian_set_index: 0, + signatures: vec![], + timestamp: 123232, nonce: 0, - sequence, - emitter_chain: OTHER_CHAIN, - emitter_address: OTHER_ENDPOINT, - payload, + emitter_chain: OTHER_CHAIN.into(), + emitter_address: Address(OTHER_ENDPOINT), + sequence: 0, + consistency_level: 0, + payload: endpoint_message, }; - let mut serialized = vec![]; - vaa_data.try_serialize(&mut serialized).unwrap(); + let posted_vaa = post_vaa(&test_data.ntt.wormhole, ctx, vaa).await; - let vaa_account: Account = Account { - lamports: 1000000, - data: serialized, - owner: wormhole_anchor_sdk::wormhole::program::id(), - executable: false, - rent_epoch: u64::MAX, - }; - - (vaa.pubkey(), vaa_account, manager_message) + (posted_vaa, manager_message) } async fn outbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> u64 { @@ -181,11 +159,10 @@ async fn inbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> #[tokio::test] async fn test_cancel() { let recipient = Keypair::new(); - let (vaa0, vaa_account0, msg0) = make_vaa(0, 1000, &recipient); - let (vaa1, vaa_account1, msg1) = make_vaa(1, 2000, &recipient); - let (mut ctx, test_data) = - setup_with_extra_accounts(Mode::Locking, &[(vaa0, vaa_account0), (vaa1, vaa_account1)]) - .await; + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let (vaa0, msg0) = post_transfer_vaa(&mut ctx, &test_data, 0, 1000, &recipient).await; + let (vaa1, msg1) = post_transfer_vaa(&mut ctx, &test_data, 1, 2000, &recipient).await; let inbound_limit_before = inbound_capacity(&mut ctx, &test_data).await; let outbound_limit_before = outbound_capacity(&mut ctx, &test_data).await; diff --git a/solana/programs/example-native-token-transfers/tests/common/hack.rs b/solana/programs/example-native-token-transfers/tests/common/hack.rs deleted file mode 100644 index 3a88065ef..000000000 --- a/solana/programs/example-native-token-transfers/tests/common/hack.rs +++ /dev/null @@ -1,44 +0,0 @@ -use anchor_lang::prelude::*; - -#[derive(Debug, Default, AnchorSerialize, AnchorDeserialize, Clone)] -// TODO: copy pasted this struct as the sdk version doesn't have a working -// serializer implementation -pub struct PostedVaaHack { - /// Header of the posted VAA - pub vaa_version: u8, - - /// Level of consistency requested by the emitter - pub consistency_level: u8, - - /// Time the vaa was submitted - pub vaa_time: u32, - - /// Account where signatures are stored - pub vaa_signature_account: Pubkey, - - /// Time the posted message was created - pub submission_time: u32, - - /// Unique nonce for this message - pub nonce: u32, - - /// Sequence number of this message - pub sequence: u64, - - /// Emitter of the message - pub emitter_chain: u16, - - /// Emitter of the message - pub emitter_address: [u8; 32], - - /// Message payload - pub payload: A, -} - -impl AccountSerialize for PostedVaaHack { - fn try_serialize(&self, writer: &mut W) -> Result<()> { - writer.write_all(b"vaa")?; - Self::serialize(self, writer)?; - Ok(()) - } -} diff --git a/solana/programs/example-native-token-transfers/tests/common/mod.rs b/solana/programs/example-native-token-transfers/tests/common/mod.rs index e5d25c752..5c1f8f0ca 100644 --- a/solana/programs/example-native-token-transfers/tests/common/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/common/mod.rs @@ -1,6 +1,5 @@ #![allow(async_fn_in_trait)] pub mod account_json_utils; -pub mod hack; pub mod query; pub mod setup; pub mod submit; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index b30439fe6..813cf672a 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -37,6 +37,20 @@ impl Wormhole { ); sequence } + + pub fn guardian_set(&self, guardian_set_index: u32) -> Pubkey { + let (guardian_set, _) = Pubkey::find_program_address( + &[b"GuardianSet", &guardian_set_index.to_be_bytes()], + &self.program, + ); + guardian_set + } + + pub fn posted_vaa(&self, vaa_hash: &[u8]) -> Pubkey { + let (posted_vaa, _) = + Pubkey::find_program_address(&[b"PostedVAA", vaa_hash], &self.program); + posted_vaa + } } pub struct NTT { diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs index 559c09d4e..457b78d8b 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs @@ -3,3 +3,4 @@ pub mod initialize; pub mod redeem; pub mod release_outbound; pub mod transfer; +pub mod post_vaa; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs new file mode 100644 index 000000000..349de2909 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs @@ -0,0 +1,136 @@ +//! NOTE: currently the wormhole sdk does not expose instruction builders for +//! posting vaas, so we go through the CPI route for testing +//! TODO: remove this once the sdk supports posting vaas +//! +//! also, this whole module is a mess. this is way harder than it needs to be + +use anchor_lang::prelude::*; +use serde_wormhole::RawMessage; +use solana_program::{instruction::AccountMeta, sysvar}; +use solana_program_test::ProgramTestContext; +use solana_sdk::{ + instruction::Instruction, secp256k1_instruction::new_secp256k1_instruction, signature::Keypair, + signer::Signer, transaction::Transaction, +}; + +use crate::{common::submit::Submittable, sdk::accounts::Wormhole}; + +use wormhole_sdk::vaa::*; + +// NOTE: assuming guardian set index 0 which has a single guardian (who is always the signer) + +pub const MAX_LEN_GUARDIAN_KEYS: usize = 19; + +pub const GUARDIAN_SECRET_KEY: &'static str = + "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"; + +pub struct VerifySignatures { + pub payer: Pubkey, + pub signature_set: Pubkey, +} + +pub async fn post_vaa( + wh: &Wormhole, + ctx: &mut ProgramTestContext, + vaa: Vaa, +) -> Pubkey { + let signature_set = Keypair::new(); + + let (verify_tx, post_ix, posted_vaa) = verify_signatures( + wh, + VerifySignatures { + payer: ctx.payer.pubkey(), + signature_set: signature_set.pubkey(), + }, + vaa.clone(), + ); + + verify_tx + .submit_with_signers(&[&signature_set], ctx) + .await + .unwrap(); + + post_ix.submit(ctx).await.unwrap(); + + posted_vaa +} + +pub fn verify_signatures( + wh: &Wormhole, + accounts: VerifySignatures, + vaa: Vaa, +) -> (Transaction, Instruction, Pubkey) { + let mut signers: [i8; MAX_LEN_GUARDIAN_KEYS] = [-1; 19]; + signers[0] = 0; + + let priv_key: libsecp256k1::SecretKey = libsecp256k1::SecretKey::parse( + &hex::decode(GUARDIAN_SECRET_KEY) + .unwrap() + .try_into() + .unwrap(), + ) + .unwrap(); + + let (header, body): (Header, Body) = vaa.into(); + + let serialized_body: Body> = Body { + payload: Box::::from(body.payload.try_to_vec().unwrap()), + ..body + }; + + let digest = serialized_body.digest().unwrap().hash; + + let secp_ix = new_secp256k1_instruction(&priv_key, &digest); + + let verify_sigs_ix = Instruction { + program_id: wh.program, + accounts: vec![ + AccountMeta::new(accounts.payer, true), + AccountMeta::new_readonly(wh.guardian_set(0), false), + AccountMeta::new(accounts.signature_set, true), + AccountMeta::new_readonly(sysvar::instructions::id(), false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + AccountMeta::new_readonly(solana_program::system_program::id(), false), + ], + data: wormhole_anchor_sdk::wormhole::Instruction::VerifySignatures { signers } + .try_to_vec() + .unwrap(), + }; + + let posted_vaa = wh.posted_vaa(&digest); + + let post_vaa_ix = Instruction { + program_id: wh.program, + accounts: vec![ + AccountMeta::new_readonly(wh.guardian_set(0), false), + AccountMeta::new_readonly(wh.bridge(), false), + AccountMeta::new_readonly(accounts.signature_set, false), + AccountMeta::new(posted_vaa, false), + AccountMeta::new(accounts.payer, true), + AccountMeta::new_readonly(sysvar::clock::id(), false), + AccountMeta::new_readonly(sysvar::rent::id(), false), + AccountMeta::new_readonly(solana_program::system_program::id(), false), + ], + data: wormhole_anchor_sdk::wormhole::Instruction::PostVAA { + version: header.version, + guardian_set_index: header.guardian_set_index, + timestamp: body.timestamp, + nonce: body.nonce, + emitter_chain: body.emitter_chain.into(), + emitter_address: body.emitter_address.0, + sequence: body.sequence, + consistency_level: body.consistency_level, + payload: body.payload.try_to_vec().unwrap(), + } + .try_to_vec() + .unwrap(), + }; + + // TODO: for some reason submitting the verification in the same ix as the + // post vaa does not seem to work. why? + ( + Transaction::new_with_payer(&[secp_ix, verify_sigs_ix], Some(&accounts.payer)), + post_vaa_ix, + posted_vaa, + ) +} From 8e261db1b57f0a07246d1d6da8edc85f4b40ea5a Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sat, 17 Feb 2024 03:26:27 +0400 Subject: [PATCH 57/90] solana: general purpose governance program --- solana/Anchor.toml | 25 ++- solana/Cargo.lock | 1 + .../example-native-token-transfers/Cargo.toml | 2 +- .../src/error.rs | 2 + .../src/instructions/admin.rs | 18 +- .../tests/common/setup.rs | 8 +- .../tests/governance.rs | 184 +++++++++++++++++ .../tests/sdk/accounts.rs | 11 ++ .../tests/sdk/instructions/admin.rs | 4 +- .../programs/wormhole-governance/Cargo.toml | 26 +++ .../programs/wormhole-governance/Xargo.toml | 2 + .../programs/wormhole-governance/src/error.rs | 9 + .../src/instructions/governance.rs | 186 ++++++++++++++++++ .../src/instructions/mod.rs | 3 + .../programs/wormhole-governance/src/lib.rs | 19 ++ 15 files changed, 478 insertions(+), 22 deletions(-) create mode 100644 solana/programs/example-native-token-transfers/tests/governance.rs create mode 100644 solana/programs/wormhole-governance/Cargo.toml create mode 100644 solana/programs/wormhole-governance/Xargo.toml create mode 100644 solana/programs/wormhole-governance/src/error.rs create mode 100644 solana/programs/wormhole-governance/src/instructions/governance.rs create mode 100644 solana/programs/wormhole-governance/src/instructions/mod.rs create mode 100644 solana/programs/wormhole-governance/src/lib.rs diff --git a/solana/Anchor.toml b/solana/Anchor.toml index af735de58..2115314be 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -1,8 +1,12 @@ +[toolchain] + [features] seeds = false skip-lint = false + [programs.localnet] solana_multi_endpoint = "F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV" +wormhole_governance = "7kK9JyavhgE5G8oErMziHeBzZiAu3J64oLMbNf8FpG4S" [registry] url = "https://api.apr.dev" @@ -14,29 +18,30 @@ wallet = "keys/test.json" [scripts] test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" +[test] +startup_wait = 5000 +shutdown_wait = 2000 +upgradeable = false -[test.validator] -url = "https://api.mainnet-beta.solana.com" -### At 160 ticks/s, 64 ticks per slot implies that leader rotation and voting will happen -### every 400 ms. A fast voting cadence ensures faster finality and convergence -ticks_per_slot = 16 - -### Wormhole Core Bridge (Mainnet) -- Program [[test.genesis]] address = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth" program = "programs/example-native-token-transfers/tests/fixtures/mainnet_core_bridge.so" -### Wormhole Core Bridge (Mainnet) -- Config +[test.validator] +bind_address = "0.0.0.0" +url = "https://api.mainnet-beta.solana.com" +ledger = ".anchor/test-ledger" +rpc_port = 8899 +ticks_per_slot = 16 + [[test.validator.account]] address = "2yVjuQwpsvdsrywzsJJVs9Ueh4zayyo5DYJbBNc3DDpn" filename = "tests/accounts/mainnet/core_bridge_config.json" -### Wormhole Core Bridge (Mainnet) -- Fee Collector [[test.validator.account]] address = "9bFNrXNb2WTx8fMHXCheaZqkLZ3YCCaiqTftHxeintHy" filename = "tests/accounts/mainnet/core_bridge_fee_collector.json" -### Wormhole Core Bridge (Mainnet) -- Guardian set 0 (overridden with devnet private key) [[test.validator.account]] address = "DS7qfSAgYsonPpKoAjcGhX9VFjXdGkiHjEDkTidf8H2P" filename = "tests/accounts/mainnet/guardian_set_0.json" diff --git a/solana/Cargo.lock b/solana/Cargo.lock index e2ef6d79d..d660206cb 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -5898,6 +5898,7 @@ dependencies = [ "solana-program", "wormhole-anchor-sdk", "wormhole-io", + "wormhole-sdk", ] [[package]] diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index 570deaf62..2b5bd7314 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -29,6 +29,7 @@ hex = "0.4.3" solana-program = "=1.17.2" wormhole-anchor-sdk = "0.29.0-alpha.1" wormhole-io = "0.1.3" +wormhole-governance = { path = "../wormhole-governance" } [dev-dependencies] hex = "0.4.3" @@ -41,7 +42,6 @@ solana-sdk = "1.17.2" spl-token = "4" spl-associated-token-account = "2.2.0" sha3 = "0.10.4" -wormhole-governance = { path = "../wormhole-governance" } wormhole-raw-vaas = "0.2.0-alpha.2" libsecp256k1 = "=0.6.0" wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index 225bf14da..2c5c790f6 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -5,6 +5,8 @@ use anchor_lang::prelude::error_code; pub enum NTTError { #[msg("CantReleaseYet")] CantReleaseYet, + #[msg("InvalidPendingOwner")] + InvalidPendingOwner, #[msg("InvalidChainId")] InvalidChainId, #[msg("InvalidRecipientAddress")] diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index ac3fa29e0..ef2672290 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -4,6 +4,7 @@ use anchor_spl::token_interface; use crate::{ chain_id::ChainId, config::Config, + error::NTTError, normalized_amount::NormalizedAmount, queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, registered_endpoint::RegisteredEndpoint, @@ -15,6 +16,7 @@ use crate::{ #[derive(Accounts)] pub struct TransferOwnership<'info> { #[account( + mut, has_one = owner, )] pub config: Account<'info, Config>, @@ -41,7 +43,7 @@ pub fn transfer_ownership( pub struct ClaimOwnership<'info> { #[account( mut, - constraint = config.pending_owner == Some(new_owner.key()) + constraint = config.pending_owner == Some(new_owner.key()) @ NTTError::InvalidPendingOwner )] pub config: Account<'info, Config>, @@ -61,16 +63,16 @@ pub fn claim_ownership(ctx: Context) -> Result<()> { #[derive(Accounts)] #[instruction(args: SetSiblingArgs)] pub struct SetSibling<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + pub owner: Signer<'info>, + #[account( has_one = owner, )] pub config: Account<'info, Config>, - pub owner: Signer<'info>, - - #[account(mut)] - pub payer: Signer<'info>, - #[account( init, space = 8 + ManagerSibling::INIT_SPACE, @@ -245,13 +247,13 @@ pub fn set_inbound_limit(ctx: Context, args: SetInboundLimitArg // * Pausing #[derive(Accounts)] pub struct SetPaused<'info> { + pub owner: Signer<'info>, + #[account( mut, has_one = owner, )] pub config: Account<'info, Config>, - - pub owner: Signer<'info>, } pub fn set_paused(ctx: Context, paused: bool) -> Result<()> { diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index c058e89a9..343affbc9 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -16,7 +16,7 @@ use spl_token::instruction::AuthorityType; use wormhole_anchor_sdk::wormhole::{BridgeData, FeeCollector}; use crate::sdk::{ - accounts::{Wormhole, NTT}, + accounts::{Governance, Wormhole, NTT}, endpoints::wormhole::instructions::admin::{set_endpoint_sibling, SetEndpointSibling}, instructions::{ admin::{register_endpoint, set_sibling, RegisterEndpoint, SetSibling}, @@ -43,6 +43,7 @@ pub const OTHER_CHAIN: u16 = 2; pub struct TestData { pub ntt: NTT, + pub governance: Governance, pub program_owner: Keypair, pub mint_authority: Keypair, pub mint: Pubkey, @@ -80,6 +81,8 @@ pub async fn setup_programs() -> Result { None, ); + program_test.add_program("wormhole_governance", wormhole_governance::ID, None); + program_test.add_program( "mainnet_core_bridge", wormhole_anchor_sdk::wormhole::program::ID, @@ -237,6 +240,9 @@ pub async fn setup_accounts(ctx: &mut ProgramTestContext) -> TestData { program: wormhole_anchor_sdk::wormhole::program::ID, }, }, + governance: Governance { + program: wormhole_governance::ID, + }, program_owner, mint_authority, mint: mint.pubkey(), diff --git a/solana/programs/example-native-token-transfers/tests/governance.rs b/solana/programs/example-native-token-transfers/tests/governance.rs new file mode 100644 index 000000000..3284094e1 --- /dev/null +++ b/solana/programs/example-native-token-transfers/tests/governance.rs @@ -0,0 +1,184 @@ +#![feature(type_changing_struct_update)] + +use anchor_lang::{prelude::*, InstructionData}; +use example_native_token_transfers::{ + config::{Config, Mode}, + instructions::TransferOwnershipArgs, +}; +use sdk::accounts::{Governance, Wormhole}; +use solana_program::instruction::{Instruction, InstructionError}; +use solana_program_test::*; +use solana_sdk::{signer::Signer, transaction::TransactionError}; +use wormhole_governance::{ + error::GovernanceError, + instructions::{GovernanceMessage, OWNER, PAYER}, +}; +use wormhole_sdk::{Address, Vaa, GOVERNANCE_EMITTER}; + +use crate::{ + common::{query::GetAccountDataAnchor, setup::setup, submit::Submittable}, + sdk::instructions::{ + admin::{set_paused, SetPaused}, + post_vaa::post_vaa, + }, +}; + +pub mod common; +pub mod sdk; + +async fn post_governance_vaa( + ctx: &mut ProgramTestContext, + wormhole: &Wormhole, + gov_message: A, + emitter_override: Option
, +) -> Pubkey { + let vaa = Vaa { + version: 1, + guardian_set_index: 0, + signatures: vec![], + timestamp: 123232, + nonce: 0, + emitter_chain: wormhole_sdk::Chain::Solana, + emitter_address: emitter_override.unwrap_or(GOVERNANCE_EMITTER), + sequence: 0, + consistency_level: 0, + payload: gov_message, + }; + + let posted_vaa = post_vaa(&wormhole, ctx, vaa).await; + + posted_vaa +} + +#[tokio::test] +async fn test_governance() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let governance_pda = test_data.governance.governance(); + + // step 1. transfer ownership to governance + let ix = example_native_token_transfers::instruction::TransferOwnership { + args: TransferOwnershipArgs { + new_owner: governance_pda, + }, + }; + + let accs = example_native_token_transfers::accounts::TransferOwnership { + config: test_data.ntt.config(), + owner: test_data.program_owner.pubkey(), + }; + + Instruction { + program_id: test_data.ntt.program, + accounts: accs.to_account_metas(None), + data: ix.data(), + } + .submit_with_signers(&[&test_data.program_owner], &mut ctx) + .await + .unwrap(); + + // step 2. claim ownership + let inner_ix_data = example_native_token_transfers::instruction::ClaimOwnership {}; + let inner_ix_accs = example_native_token_transfers::accounts::ClaimOwnership { + new_owner: OWNER, + config: test_data.ntt.config(), + }; + + let inner_ix: Instruction = Instruction { + program_id: test_data.ntt.program, + accounts: inner_ix_accs.to_account_metas(None), + data: inner_ix_data.data(), + }; + + wrap_governance( + &mut ctx, + &test_data.governance, + &test_data.ntt.wormhole, + inner_ix, + None, + ) + .await + .unwrap(); + + // step 3. set paused + wrap_governance( + &mut ctx, + &test_data.governance, + &test_data.ntt.wormhole, + set_paused(&test_data.ntt, SetPaused { owner: OWNER }, true), + None, + ) + .await + .unwrap(); + + let config_account: Config = ctx.get_account_data_anchor(test_data.ntt.config()).await; + assert!(config_account.paused); +} + +#[tokio::test] +async fn test_governance_bad_emitter() { + let (mut ctx, test_data) = setup(Mode::Locking).await; + + let err = wrap_governance( + &mut ctx, + &test_data.governance, + &test_data.ntt.wormhole, + set_paused(&test_data.ntt, SetPaused { owner: OWNER }, true), + Some(Address::default()), + ) + .await + .unwrap_err(); + + assert_eq!( + err.unwrap(), + TransactionError::InstructionError( + 0, + InstructionError::Custom(GovernanceError::InvalidGovernanceEmitter.into()) + ) + ); +} + +// TODO: move (some of) this into the governance library +async fn wrap_governance( + ctx: &mut ProgramTestContext, + gov_program: &Governance, + wormhole: &Wormhole, + mut ix: Instruction, + emitter_override: Option
, +) -> core::result::Result<(), BanksClientError> { + let program = ix.program_id; + // TODO: LUTs? + + // map over ix.accounts and make "owner" and "payer" not signers + ix.accounts.iter_mut().for_each(|acc| { + if acc.pubkey == OWNER || acc.pubkey == PAYER { + acc.is_signer = false; + } + }); + + let other_accounts = ix.accounts.to_vec(); + + let gov_message: GovernanceMessage = ix.into(); + + let data = wormhole_governance::instruction::Governance {}; + + let vaa = post_governance_vaa(ctx, &wormhole, gov_message, emitter_override).await; + + let gov_accounts = wormhole_governance::accounts::Governance { + payer: ctx.payer.pubkey(), + governance: gov_program.governance(), + vaa, + program, + }; + + let mut accounts = gov_accounts.to_account_metas(None); + accounts.extend(other_accounts); + + let gov_ix = Instruction { + program_id: gov_program.program, + accounts, + data: data.data(), + }; + + gov_ix.submit(ctx).await +} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 813cf672a..f540f4a68 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -53,6 +53,17 @@ impl Wormhole { } } +pub struct Governance { + pub program: Pubkey, +} + +impl Governance { + pub fn governance(&self) -> Pubkey { + let (gov, _) = Pubkey::find_program_address(&[b"governance"], &self.program); + gov + } +} + pub struct NTT { pub program: Pubkey, pub wormhole: Wormhole, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs index ef586cb16..61985c705 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs @@ -39,8 +39,8 @@ pub fn set_paused(ntt: &NTT, accounts: SetPaused, pause: bool) -> Instruction { let data = example_native_token_transfers::instruction::SetPaused { pause }; let accounts = example_native_token_transfers::accounts::SetPaused { - config: ntt.config(), owner: accounts.owner, + config: ntt.config(), }; Instruction { @@ -69,7 +69,7 @@ pub fn register_endpoint(ntt: &NTT, accounts: RegisterEndpoint) -> Instruction { }; Instruction { - program_id: example_native_token_transfers::ID, + program_id: ntt.program, accounts: accounts.to_account_metas(None), data: data.data(), } diff --git a/solana/programs/wormhole-governance/Cargo.toml b/solana/programs/wormhole-governance/Cargo.toml new file mode 100644 index 000000000..c879d9ce8 --- /dev/null +++ b/solana/programs/wormhole-governance/Cargo.toml @@ -0,0 +1,26 @@ +[package] +name = "wormhole-governance" +version = "0.1.0" +description = "Governance for programs controlled by Wormhole Guardians" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "wormhole_governance" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +idl-build = [ + "anchor-lang/idl-build", +] + +[dependencies] +anchor-lang = "0.29.0" + +solana-program = "=1.17.2" +wormhole-anchor-sdk = "0.29.0-alpha.1" +wormhole-io = "0.1.3" +wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } diff --git a/solana/programs/wormhole-governance/Xargo.toml b/solana/programs/wormhole-governance/Xargo.toml new file mode 100644 index 000000000..475fb71ed --- /dev/null +++ b/solana/programs/wormhole-governance/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/solana/programs/wormhole-governance/src/error.rs b/solana/programs/wormhole-governance/src/error.rs new file mode 100644 index 000000000..b7b5d7f91 --- /dev/null +++ b/solana/programs/wormhole-governance/src/error.rs @@ -0,0 +1,9 @@ +use anchor_lang::prelude::error_code; + +#[error_code] +pub enum GovernanceError { + #[msg("InvalidGovernanceChain")] + InvalidGovernanceChain, + #[msg("InvalidGovernanceEmitter")] + InvalidGovernanceEmitter, +} diff --git a/solana/programs/wormhole-governance/src/instructions/governance.rs b/solana/programs/wormhole-governance/src/instructions/governance.rs new file mode 100644 index 000000000..227184535 --- /dev/null +++ b/solana/programs/wormhole-governance/src/instructions/governance.rs @@ -0,0 +1,186 @@ +//! General purpose governance program. +//! +//! This program is designed to be a generic governance program that can be used to +//! execute arbitrary instructions on behalf of a guardian set. +//! The program being governed simply needs to expose admin instructions that can be +//! invoked by a signer account (that's checked by the program's access control logic). +//! +//! If the signer is set to be the "governance" PDA of this program, then the governance +//! instruction is able to invoke the program's admin instructions. +//! +//! The instruction needs to be encoded in the VAA payload, with all the +//! accounts. These accounts may be in any order, with two placeholder accounts: +//! - [`OWNER`]: the program will replace this account with the governance PDA +//! - [`PAYER`]: the program will replace this account with the payer account +use anchor_lang::prelude::*; +use solana_program::instruction::Instruction; +use wormhole_anchor_sdk::wormhole::PostedVaa; +use wormhole_sdk::{Chain, GOVERNANCE_EMITTER}; + +use crate::error::GovernanceError; + +pub const OWNER: Pubkey = sentinel_pubkey(b"owner"); +pub const PAYER: Pubkey = sentinel_pubkey(b"payer"); + +#[derive(Accounts)] +pub struct Governance<'info> { + #[account(mut)] + pub payer: Signer<'info>, + + #[account( + mut, + seeds = [b"governance"], + bump, + )] + /// CHECK: TODO + pub governance: AccountInfo<'info>, + + #[account( + constraint = vaa.emitter_chain() == Into::::into(Chain::Solana) @ GovernanceError::InvalidGovernanceChain, + constraint = *vaa.emitter_address() == GOVERNANCE_EMITTER.0 @ GovernanceError::InvalidGovernanceEmitter, + )] + pub vaa: Account<'info, PostedVaa>, + + #[account(executable)] + pub program: AccountInfo<'info>, +} + +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +// TODO: adjust wire format to match the wh governance spec +pub struct GovernanceMessage { + pub program_id: Pubkey, + pub accounts: Vec, + pub data: Vec, +} + +impl Into for GovernanceMessage { + fn into(self) -> Instruction { + let GovernanceMessage { + program_id, + accounts, + data, + } = self; + let accounts: Vec = accounts.into_iter().map(|a| a.into()).collect(); + Instruction { + program_id, + accounts, + data, + } + } +} + +impl From for GovernanceMessage { + fn from(instruction: Instruction) -> GovernanceMessage { + let Instruction { + program_id, + accounts, + data, + } = instruction; + let accounts: Vec = accounts.into_iter().map(|a| a.into()).collect(); + GovernanceMessage { + program_id, + accounts, + data, + } + } +} + +/// A copy of [`solana_program::instruction::AccountMeta`] with +/// `AccountSerialize`/`AccountDeserialize` impl. +/// Would be nice to just use the original, but it lacks these traits. +#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)] +pub struct Acc { + pub pubkey: Pubkey, + pub is_signer: bool, + pub is_writable: bool, +} + +impl Into for Acc { + fn into(self) -> AccountMeta { + let Acc { + pubkey, + is_signer, + is_writable, + } = self; + AccountMeta { + pubkey, + is_signer, + is_writable, + } + } +} + +impl From for Acc { + fn from(account_meta: AccountMeta) -> Acc { + let AccountMeta { + pubkey, + is_signer, + is_writable, + } = account_meta; + Acc { + pubkey, + is_signer, + is_writable, + } + } +} + +pub fn governance<'a, 'b, 'c, 'info>( + ctx: Context<'a, 'b, 'c, 'info, Governance<'info>>, +) -> Result<()> { + let vaa_data = ctx.accounts.vaa.data(); + + let mut instruction: Instruction = vaa_data.clone().into(); + + instruction.accounts.iter_mut().for_each(|acc| { + if acc.pubkey == OWNER { + acc.pubkey = ctx.accounts.governance.key(); + acc.is_writable = ctx.accounts.governance.is_writable; + acc.is_signer = true; + } else if acc.pubkey == PAYER { + acc.pubkey = ctx.accounts.payer.key(); + acc.is_writable = ctx.accounts.payer.is_writable; + acc.is_signer = true; + } + }); + + // TODO(SECURITY): what does the runtime verify about these accounts? + // should we match them against the accounts in the instruction? the runtime + // *should* do that but I'll add tests + let account_infos: Vec> = ctx + .remaining_accounts + .iter() + .map(|acc| { + if acc.key() == OWNER { + AccountInfo { + is_signer: true, + ..ctx.accounts.governance.to_account_info() + } + } else if acc.key() == PAYER { + ctx.accounts.payer.to_account_info() + } else { + acc.clone() + } + }) + .collect(); + + solana_program::program::invoke_signed( + &instruction, + &account_infos, + &[&[b"governance", &[ctx.bumps.governance]]], + )?; + + Ok(()) +} + +const fn sentinel_pubkey(input: &[u8]) -> Pubkey { + let mut output: [u8; 32] = [0; 32]; + + let mut i = 0; + while i < input.len() { + output[i] = input[i]; + i += 1; + } + + Pubkey::new_from_array(output) +} diff --git a/solana/programs/wormhole-governance/src/instructions/mod.rs b/solana/programs/wormhole-governance/src/instructions/mod.rs new file mode 100644 index 000000000..5d4eb88e3 --- /dev/null +++ b/solana/programs/wormhole-governance/src/instructions/mod.rs @@ -0,0 +1,3 @@ +pub mod governance; + +pub use governance::*; diff --git a/solana/programs/wormhole-governance/src/lib.rs b/solana/programs/wormhole-governance/src/lib.rs new file mode 100644 index 000000000..27388d7d2 --- /dev/null +++ b/solana/programs/wormhole-governance/src/lib.rs @@ -0,0 +1,19 @@ +use anchor_lang::prelude::*; + +declare_id!("7kK9JyavhgE5G8oErMziHeBzZiAu3J64oLMbNf8FpG4S"); + +pub mod instructions; +pub mod error; + +use instructions::*; + +#[program] +pub mod wormhole_governance { + use super::*; + + pub fn governance<'a, 'b, 'c, 'info>( + ctx: Context<'a, 'b, 'c, 'info, Governance<'info>>, + ) -> Result<()> { + instructions::governance(ctx) + } +} From 0c420e3cfaea1a8a384f211e688a47fdec07e008 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sun, 18 Feb 2024 17:15:11 +0400 Subject: [PATCH 58/90] solana: assert decimals are equal instead of shifting if these are not equal, that's an implementation bug, so let's not handle it gracefully --- .../src/normalized_amount.rs | 25 +++++-------------- 1 file changed, 6 insertions(+), 19 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index d61f12924..aa5253569 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -22,7 +22,8 @@ pub struct NormalizedAmount { impl PartialEq for NormalizedAmount { fn eq(&self, other: &Self) -> bool { - self.amount == other.change_decimals(self.decimals).amount + assert_eq!(self.decimals, other.decimals); + self.amount == other.amount } } @@ -36,7 +37,7 @@ impl PartialOrd for NormalizedAmount { impl Ord for NormalizedAmount { fn cmp(&self, other: &Self) -> std::cmp::Ordering { - let other = other.change_decimals(self.decimals); + assert_eq!(self.decimals, other.decimals); self.amount.cmp(&other.amount) } } @@ -45,7 +46,7 @@ impl Sub for NormalizedAmount { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { - let rhs = rhs.change_decimals(self.decimals); + assert_eq!(self.decimals, rhs.decimals); Self { amount: self.amount - rhs.amount, decimals: self.decimals, @@ -59,7 +60,7 @@ impl NormalizedAmount { } pub fn saturating_sub(self, rhs: Self) -> Self { - let rhs = rhs.change_decimals(self.decimals); + assert_eq!(self.decimals, rhs.decimals); Self { amount: self.amount.saturating_sub(rhs.amount), decimals: self.decimals, @@ -67,7 +68,7 @@ impl NormalizedAmount { } pub fn saturating_add(self, rhs: Self) -> Self { - let rhs = rhs.change_decimals(self.decimals); + assert_eq!(self.decimals, rhs.decimals); Self { amount: self.amount.saturating_add(rhs.amount), decimals: self.decimals, @@ -173,19 +174,5 @@ mod test { .denormalize(13), 10000000 ); - - assert_eq!( - NormalizedAmount { - amount: 2, - decimals: 5, - } - NormalizedAmount { - amount: 10, - decimals: 6, - }, - NormalizedAmount { - amount: 1, - decimals: 5, - } - ); } } From 80dc2474b320a3f5a708f3d4706cb74d88fc5d6f Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Sun, 18 Feb 2024 17:47:10 +0400 Subject: [PATCH 59/90] solana: use unnormalised values internally all arithmetic is done on the native token amount decimals. this way, NormalizedAmount is strictly used at the API boundaries, and no arithmetic is performed on those values. This ensures every operation is internally consistent --- .../src/instructions/admin.rs | 30 +------ .../src/instructions/initialize.rs | 5 +- .../src/instructions/redeem.rs | 9 +- .../src/instructions/release_inbound.rs | 8 +- .../src/instructions/transfer.rs | 16 ++-- .../src/normalized_amount.rs | 51 ++---------- .../src/queue/inbox.rs | 6 +- .../src/queue/rate_limit.rs | 82 +++++++------------ .../tests/cancel_flow.rs | 11 +-- .../tests/sdk/instructions/admin.rs | 1 - .../tests/sdk/instructions/redeem.rs | 2 + .../tests/transfer.rs | 5 +- solana/ts/sdk/index.ts | 2 +- 13 files changed, 66 insertions(+), 162 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index ef2672290..fc95d5541 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -1,11 +1,9 @@ use anchor_lang::prelude::*; -use anchor_spl::token_interface; use crate::{ chain_id::ChainId, config::Config, error::NTTError, - normalized_amount::NormalizedAmount, queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, registered_endpoint::RegisteredEndpoint, sibling::ManagerSibling, @@ -94,13 +92,6 @@ pub struct SetSibling<'info> { )] pub inbox_rate_limit: Account<'info, InboxRateLimit>, - #[account( - constraint = mint.key() == config.mint - )] - // TODO: should we just store the decimals in the config? a lot of - // instructions just take mint for the decimals - pub mint: InterfaceAccount<'info, token_interface::Mint>, - pub system_program: Program<'info, System>, } @@ -119,10 +110,7 @@ pub fn set_sibling(ctx: Context, args: SetSiblingArgs) -> Result<()> ctx.accounts.inbox_rate_limit.set_inner(InboxRateLimit { bump: ctx.bumps.inbox_rate_limit, - rate_limit: RateLimitState::new(NormalizedAmount::normalize( - args.limit, - ctx.accounts.mint.decimals, - )), + rate_limit: RateLimitState::new(args.limit), }); Ok(()) } @@ -185,11 +173,6 @@ pub struct SetOutboundLimit<'info> { #[account(mut)] pub rate_limit: Account<'info, OutboxRateLimit>, - - #[account( - constraint = mint.key() == config.mint - )] - pub mint: InterfaceAccount<'info, token_interface::Mint>, } #[derive(AnchorDeserialize, AnchorSerialize)] @@ -201,8 +184,7 @@ pub fn set_outbound_limit( ctx: Context, args: SetOutboundLimitArgs, ) -> Result<()> { - let limit = NormalizedAmount::normalize(args.limit, ctx.accounts.mint.decimals); - ctx.accounts.rate_limit.set_limit(limit); + ctx.accounts.rate_limit.set_limit(args.limit); Ok(()) } @@ -225,11 +207,6 @@ pub struct SetInboundLimit<'info> { bump = rate_limit.bump )] pub rate_limit: Account<'info, InboxRateLimit>, - - #[account( - constraint = mint.key() == config.mint - )] - pub mint: InterfaceAccount<'info, token_interface::Mint>, } #[derive(AnchorDeserialize, AnchorSerialize)] @@ -239,8 +216,7 @@ pub struct SetInboundLimitArgs { } pub fn set_inbound_limit(ctx: Context, args: SetInboundLimitArgs) -> Result<()> { - let limit = NormalizedAmount::normalize(args.limit, ctx.accounts.mint.decimals); - ctx.accounts.rate_limit.set_limit(limit); + ctx.accounts.rate_limit.set_limit(args.limit); Ok(()) } diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index fbc3071e0..3fa6139c5 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -5,7 +5,6 @@ use crate::{ bitmap::Bitmap, chain_id::ChainId, error::NTTError, - normalized_amount::NormalizedAmount, queue::{outbox::OutboxRateLimit, rate_limit::RateLimitState}, sequence::Sequence, }; @@ -107,10 +106,8 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> sequence: 0, }); - let decimals: u8 = ctx.accounts.mint.decimals; - ctx.accounts.rate_limit.set_inner(OutboxRateLimit { - rate_limit: RateLimitState::new(NormalizedAmount::normalize(args.limit, decimals)), + rate_limit: RateLimitState::new(args.limit), }); Ok(()) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 9835393f5..088552dcd 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -1,4 +1,5 @@ use anchor_lang::prelude::*; +use anchor_spl::token_interface; use crate::{ bitmap::Bitmap, @@ -41,6 +42,11 @@ pub struct Redeem<'info> { pub endpoint: EnabledEndpoint<'info>, + #[account( + constraint = mint.key() == config.mint + )] + pub mint: InterfaceAccount<'info, token_interface::Mint>, + #[account( init_if_needed, payer = payer, @@ -84,8 +90,7 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { let message: ManagerMessage = accs.endpoint_message.message.manager_payload.clone(); - let amount = message.payload.amount; - let amount = amount.change_decimals(accs.outbox_rate_limit.rate_limit.limit.decimals); + let amount = message.payload.amount.denormalize(accs.mint.decimals); if !accs.inbox_item.init { let recipient_address = diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 7c865c2e0..508db7cfb 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -87,9 +87,7 @@ pub fn release_inbound_mint( }, &[&[b"token_authority", &[ctx.bumps.common.token_authority]]], ), - inbox_item - .amount - .denormalize(ctx.accounts.common.mint.decimals), + inbox_item.amount, ), Mode::Locking => Err(NTTError::InvalidMode.into()), } @@ -143,9 +141,7 @@ pub fn release_inbound_unlock( }, &[&[b"token_authority", &[ctx.bumps.common.token_authority]]], ), - inbox_item - .amount - .denormalize(ctx.accounts.common.mint.decimals), + inbox_item.amount, ctx.accounts.common.mint.decimals, ), } diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 95b9c24c3..f22bbad0c 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -98,7 +98,8 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( should_queue, } = args; - let amount = NormalizedAmount::normalize(amount, accs.common.mint.decimals); + // TODO: should we revert if we have dust? + let amount = NormalizedAmount::remove_dust(amount, accs.common.mint.decimals); match accs.common.config.mode { Mode::Burning => token_interface::burn( @@ -110,8 +111,7 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( authority: accs.common.from_authority.to_account_info(), }, ), - // TODO: should we revert if we have dust? - amount.denormalize(accs.common.mint.decimals), + amount, )?, Mode::Locking => return Err(NTTError::InvalidMode.into()), } @@ -167,7 +167,8 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( should_queue, } = args; - let amount = NormalizedAmount::normalize(amount, accs.common.mint.decimals); + // TODO: should we revert if we have dust? + let amount = NormalizedAmount::remove_dust(amount, accs.common.mint.decimals); match accs.common.config.mode { Mode::Burning => return Err(NTTError::InvalidMode.into()), @@ -181,8 +182,7 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( mint: accs.common.mint.to_account_info(), }, ), - // TODO: should we revert if we have dust? - amount.denormalize(accs.common.mint.decimals), + amount, accs.common.mint.decimals, )?, } @@ -200,7 +200,7 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( fn insert_into_outbox( common: &mut Transfer<'_>, inbox_rate_limit: &mut InboxRateLimit, - amount: NormalizedAmount, + amount: u64, recipient_chain: ChainId, recipient_address: [u8; 32], should_queue: bool, @@ -225,7 +225,7 @@ fn insert_into_outbox( common.outbox_item.set_inner(OutboxItem { sequence, - amount, + amount: NormalizedAmount::normalize(amount, common.mint.decimals), sender: common.from_authority.key(), recipient_chain, recipient_address, diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index aa5253569..bdaf197bf 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -7,7 +7,7 @@ //! The functions [`normalize`] and [`denormalize`] take care of convertion to/from //! this type given the original amount's decimals. -use std::{io, ops::Sub}; +use std::io; use anchor_lang::prelude::*; use wormhole_io::{Readable, Writeable}; @@ -16,8 +16,8 @@ pub const NORMALIZED_DECIMALS: u8 = 8; #[derive(Debug, Clone, Copy, AnchorSerialize, AnchorDeserialize, InitSpace)] pub struct NormalizedAmount { - pub amount: u64, - pub decimals: u8, + amount: u64, + decimals: u8, } impl PartialEq for NormalizedAmount { @@ -29,52 +29,11 @@ impl PartialEq for NormalizedAmount { impl Eq for NormalizedAmount {} -impl PartialOrd for NormalizedAmount { - fn partial_cmp(&self, other: &Self) -> Option { - Some(self.cmp(other)) - } -} - -impl Ord for NormalizedAmount { - fn cmp(&self, other: &Self) -> std::cmp::Ordering { - assert_eq!(self.decimals, other.decimals); - self.amount.cmp(&other.amount) - } -} - -impl Sub for NormalizedAmount { - type Output = Self; - - fn sub(self, rhs: Self) -> Self::Output { - assert_eq!(self.decimals, rhs.decimals); - Self { - amount: self.amount - rhs.amount, - decimals: self.decimals, - } - } -} - impl NormalizedAmount { pub fn new(amount: u64, decimals: u8) -> Self { Self { amount, decimals } } - pub fn saturating_sub(self, rhs: Self) -> Self { - assert_eq!(self.decimals, rhs.decimals); - Self { - amount: self.amount.saturating_sub(rhs.amount), - decimals: self.decimals, - } - } - - pub fn saturating_add(self, rhs: Self) -> Self { - assert_eq!(self.decimals, rhs.decimals); - Self { - amount: self.amount.saturating_add(rhs.amount), - decimals: self.decimals, - } - } - pub fn change_decimals(&self, new_decimals: u8) -> Self { if new_decimals == self.decimals { return *self; @@ -108,6 +67,10 @@ impl NormalizedAmount { Self::scale(self.amount, self.decimals, to_decimals) } + pub fn remove_dust(amount: u64, from_decimals: u8) -> u64 { + Self::normalize(amount, from_decimals).denormalize(from_decimals) + } + pub fn amount(&self) -> u64 { self.amount } diff --git a/solana/programs/example-native-token-transfers/src/queue/inbox.rs b/solana/programs/example-native-token-transfers/src/queue/inbox.rs index bdd41a275..947058e8d 100644 --- a/solana/programs/example-native-token-transfers/src/queue/inbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/inbox.rs @@ -2,9 +2,7 @@ use std::ops::{Deref, DerefMut}; use anchor_lang::prelude::*; -use crate::{ - bitmap::Bitmap, clock::current_timestamp, error::NTTError, normalized_amount::NormalizedAmount, -}; +use crate::{bitmap::Bitmap, clock::current_timestamp, error::NTTError}; use super::rate_limit::RateLimitState; @@ -14,7 +12,7 @@ use super::rate_limit::RateLimitState; pub struct InboxItem { pub init: bool, pub bump: u8, - pub amount: NormalizedAmount, + pub amount: u64, pub recipient_address: Pubkey, pub votes: Bitmap, pub release_status: ReleaseStatus, diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index ef15001fc..a7493f382 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -1,16 +1,16 @@ use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp}; -use crate::{clock::current_timestamp, normalized_amount::NormalizedAmount}; +use crate::clock::current_timestamp; #[derive(AnchorSerialize, AnchorDeserialize, Clone, InitSpace, PartialEq, Eq, Debug)] pub struct RateLimitState { /// The maximum capacity of the rate limiter. - pub limit: NormalizedAmount, + pub limit: u64, /// The capacity of the rate limiter at `last_tx_timestamp`. /// The actual current capacity is calculated in `capacity_at`, by /// accounting for the time that has passed since `last_tx_timestamp` and /// the refill rate. - pub capacity_at_last_tx: NormalizedAmount, + pub capacity_at_last_tx: u64, /// The timestamp of the last transaction that counted towards the current /// capacity. Transactions that exceeded the capacity do not count, they are /// just delayed. @@ -29,7 +29,7 @@ pub enum RateLimitResult { } impl RateLimitState { - pub fn new(limit: NormalizedAmount) -> Self { + pub fn new(limit: u64) -> Self { Self { limit, capacity_at_last_tx: limit, @@ -39,7 +39,7 @@ impl RateLimitState { pub const RATE_LIMIT_DURATION: i64 = 60 * 60 * 24; // 24 hours - pub fn capacity(&self) -> NormalizedAmount { + pub fn capacity(&self) -> u64 { self.capacity_at(current_timestamp()) } @@ -47,10 +47,10 @@ impl RateLimitState { /// On-chain programs and unit tests should always use [`capacity`]. /// This function is useful in solana-program-test, where the clock sysvar /// - pub fn capacity_at(&self, now: UnixTimestamp) -> NormalizedAmount { + pub fn capacity_at(&self, now: UnixTimestamp) -> u64 { assert!(self.last_tx_timestamp <= now); - let limit = self.limit.amount() as u128; + let limit = self.limit as u128; // morally this is // capacity = old_capacity + (limit / rate_limit_duration) * time_passed @@ -63,10 +63,7 @@ impl RateLimitState { // for the intermediate calculations. Theoretically it could also overflow u128 // if limit == time_passed == u64 max, but that will take a very long time. - let NormalizedAmount { - amount: capacity_at_last_tx, - decimals, - } = self.capacity_at_last_tx; + let capacity_at_last_tx = self.capacity_at_last_tx; let calculated_capacity = { let time_passed = now - self.last_tx_timestamp; @@ -74,7 +71,7 @@ impl RateLimitState { + time_passed as u128 * limit / (Self::RATE_LIMIT_DURATION as u128) }; - NormalizedAmount::new(calculated_capacity.min(limit) as u64, decimals) + calculated_capacity.min(limit) as u64 } /// Computes the timestamp at which the given amount can be consumed. @@ -82,7 +79,7 @@ impl RateLimitState { /// returned, and the remaining capacity is reduced. /// Otherwise, the timestamp at which the capacity will be available is /// returned. - pub fn consume_or_delay(&mut self, amount: NormalizedAmount) -> RateLimitResult { + pub fn consume_or_delay(&mut self, amount: u64) -> RateLimitResult { let now = current_timestamp(); let capacity = self.capacity(); if capacity >= amount { @@ -96,18 +93,18 @@ impl RateLimitState { /// Refills the capacity by the given amount. /// This is used to replenish the capacity via backflows. - pub fn refill(&mut self, amount: NormalizedAmount) { + pub fn refill(&mut self, amount: u64) { self.capacity_at_last_tx = self.capacity().saturating_add(amount).min(self.limit); self.last_tx_timestamp = current_timestamp(); } - pub fn set_limit(&mut self, limit: NormalizedAmount) { + pub fn set_limit(&mut self, limit: u64) { let old_limit = self.limit; let current_capacity = self.capacity(); self.limit = limit; - let new_capacity: NormalizedAmount = if old_limit > limit { + let new_capacity: u64 = if old_limit > limit { // decrease in limit, let diff = old_limit - limit; current_capacity.saturating_sub(diff) @@ -131,72 +128,51 @@ mod tests { #[test] fn test_rate_limit() { let mut rate_limit_state = RateLimitState { - limit: NormalizedAmount::new(100_000, 8), - capacity_at_last_tx: NormalizedAmount::new(100_000, 8), + limit: 100_000, + capacity_at_last_tx: 100_000, last_tx_timestamp: current_timestamp(), }; // consume 30k. should be immediate - let immediately = rate_limit_state.consume_or_delay(NormalizedAmount::new(30_000, 8)); + let immediately = rate_limit_state.consume_or_delay(30_000); assert_eq!(immediately, RateLimitResult::Consumed); - assert_eq!( - rate_limit_state.capacity(), - NormalizedAmount::new(70_000, 8) - ); - assert_eq!(rate_limit_state.limit, NormalizedAmount::new(100_000, 8)); // unchanged + assert_eq!(rate_limit_state.capacity(), 70_000); + assert_eq!(rate_limit_state.limit, 100_000); // unchanged assert_eq!(rate_limit_state.last_tx_timestamp, current_timestamp()); // replenish 1/4 of the limit, i.e. 25k set_test_timestamp(current_timestamp() + RateLimitState::RATE_LIMIT_DURATION / 4); - assert_eq!( - rate_limit_state.capacity(), - NormalizedAmount::new(70_000 + 25_000, 8) - ); + assert_eq!(rate_limit_state.capacity(), 70_000 + 25_000); // now consume 150k. should be delayed - let tomorrow = rate_limit_state.consume_or_delay(NormalizedAmount::new(150_000, 8)); + let tomorrow = rate_limit_state.consume_or_delay(150_000); assert_eq!( tomorrow, RateLimitResult::Delayed(current_timestamp() + RateLimitState::RATE_LIMIT_DURATION) ); // the limit is not changed, since the tx was delayed - assert_eq!( - rate_limit_state.capacity(), - NormalizedAmount::new(70_000 + 25_000, 8) - ); + assert_eq!(rate_limit_state.capacity(), 70_000 + 25_000); // now set the limit to 50k - rate_limit_state.set_limit(NormalizedAmount::new(50_000, 8)); + rate_limit_state.set_limit(50_000); // this decreases the capacity by 50k, to 45k - assert_eq!( - rate_limit_state.capacity(), - NormalizedAmount::new(45_000, 8) - ); + assert_eq!(rate_limit_state.capacity(), 45_000); // now set the limit to 100k - rate_limit_state.set_limit(NormalizedAmount::new(100_000, 8)); + rate_limit_state.set_limit(100_000); - assert_eq!( - rate_limit_state.capacity(), - NormalizedAmount::new(95_000, 8) - ); + assert_eq!(rate_limit_state.capacity(), 95_000); // now refill 2k - rate_limit_state.refill(NormalizedAmount::new(2_000, 8)); - assert_eq!( - rate_limit_state.capacity(), - NormalizedAmount::new(97_000, 8) - ); + rate_limit_state.refill(2_000); + assert_eq!(rate_limit_state.capacity(), 97_000); // now refill 50k - rate_limit_state.refill(NormalizedAmount::new(50_000, 8)); - assert_eq!( - rate_limit_state.capacity(), - NormalizedAmount::new(100_000, 8) - ); + rate_limit_state.refill(50_000); + assert_eq!(rate_limit_state.capacity(), 100_000); } } diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 6cba7b3a4..09c6e6ec8 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -72,6 +72,7 @@ fn init_redeem_accs( .endpoint_message(chain_id, manager_message.sequence), inbox_item: test_data.ntt.inbox_item(chain_id, manager_message), inbox_rate_limit: test_data.ntt.inbox_rate_limit(chain_id), + mint: test_data.mint, } } @@ -138,10 +139,7 @@ async fn outbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) - .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) .await; - rate_limit - .rate_limit - .capacity_at(clock.unix_timestamp) - .denormalize(9) + rate_limit.rate_limit.capacity_at(clock.unix_timestamp) } async fn inbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> u64 { @@ -150,10 +148,7 @@ async fn inbound_capacity(ctx: &mut ProgramTestContext, test_data: &TestData) -> .get_account_data_anchor(test_data.ntt.inbox_rate_limit(OTHER_CHAIN)) .await; - rate_limit - .rate_limit - .capacity_at(clock.unix_timestamp) - .denormalize(9) + rate_limit.rate_limit.capacity_at(clock.unix_timestamp) } #[tokio::test] diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs index 61985c705..ea9c3b141 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/admin.rs @@ -20,7 +20,6 @@ pub fn set_sibling(ntt: &NTT, accounts: SetSibling, args: SetSiblingArgs) -> Ins payer: accounts.payer, sibling: ntt.sibling(chain_id), inbox_rate_limit: ntt.inbox_rate_limit(chain_id), - mint: accounts.mint, system_program: System::id(), }; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs index c0014ed15..64d3bf53b 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs @@ -10,6 +10,7 @@ pub struct Redeem { pub sibling: Pubkey, pub endpoint_message: Pubkey, pub endpoint: Pubkey, + pub mint: Pubkey, pub inbox_item: Pubkey, pub inbox_rate_limit: Pubkey, } @@ -25,6 +26,7 @@ pub fn redeem(ntt: &NTT, accs: Redeem, args: RedeemArgs) -> Instruction { endpoint: EnabledEndpoint { endpoint: ntt.registered_endpoint(&accs.endpoint), }, + mint: accs.mint, inbox_item: accs.inbox_item, inbox_rate_limit: accs.inbox_rate_limit, outbox_rate_limit: ntt.outbox_rate_limit(), diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 60a6a5526..dd5a1d7cb 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -290,11 +290,8 @@ async fn test_rate_limit() { .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) .await; - assert_eq!(NormalizedAmount::normalize(100, 9).amount, 10); - assert_eq!( - outbound_limit_before.capacity_at(clock.unix_timestamp) - - NormalizedAmount::normalize(100, 9), + outbound_limit_before.capacity_at(clock.unix_timestamp) - 100, outbound_limit_after.capacity_at(clock.unix_timestamp) ); } diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 7c99ab2be..24640abae 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -512,7 +512,6 @@ export class NTT { config: this.configAccountAddress(), sibling: this.siblingAccountAddress(args.chain), inboxRateLimit: this.inboxRateLimitAccountAddress(args.chain), - mint: config.mint, }) .signers([args.payer, args.owner]) .rpc() @@ -626,6 +625,7 @@ export class NTT { sibling: managerSibling, endpointMessage: this.endpointMessageAccountAddress(chainId, new BN(managerMessage.sequence.toString())), endpoint: { endpoint: this.registeredEndpointAddress(this.program.programId) }, + mint: await this.mintAccountAddress(config), inboxItem: this.inboxItemAccountAddress(chainId, managerMessage), inboxRateLimit, outboxRateLimit: this.outboxRateLimitAccountAddress(), From 16e8147c207693a0968f3d1ca2847739def0837e Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 20 Feb 2024 11:29:35 -0500 Subject: [PATCH 60/90] solana: simplify governance CPI --- .../tests/governance.rs | 23 ++++++-------- .../src/instructions/governance.rs | 31 +++---------------- 2 files changed, 14 insertions(+), 40 deletions(-) diff --git a/solana/programs/example-native-token-transfers/tests/governance.rs b/solana/programs/example-native-token-transfers/tests/governance.rs index 3284094e1..30863fbec 100644 --- a/solana/programs/example-native-token-transfers/tests/governance.rs +++ b/solana/programs/example-native-token-transfers/tests/governance.rs @@ -143,25 +143,16 @@ async fn wrap_governance( ctx: &mut ProgramTestContext, gov_program: &Governance, wormhole: &Wormhole, - mut ix: Instruction, + ix: Instruction, emitter_override: Option
, ) -> core::result::Result<(), BanksClientError> { let program = ix.program_id; // TODO: LUTs? - // map over ix.accounts and make "owner" and "payer" not signers - ix.accounts.iter_mut().for_each(|acc| { - if acc.pubkey == OWNER || acc.pubkey == PAYER { - acc.is_signer = false; - } - }); - - let other_accounts = ix.accounts.to_vec(); - - let gov_message: GovernanceMessage = ix.into(); - let data = wormhole_governance::instruction::Governance {}; + let gov_message: GovernanceMessage = ix.clone().into(); + let vaa = post_governance_vaa(ctx, &wormhole, gov_message, emitter_override).await; let gov_accounts = wormhole_governance::accounts::Governance { @@ -172,7 +163,13 @@ async fn wrap_governance( }; let mut accounts = gov_accounts.to_account_metas(None); - accounts.extend(other_accounts); + + let remaining_accounts = ix.accounts.iter().map(|acc| AccountMeta { + is_signer: false, + ..acc.clone() + }); + + accounts.extend(remaining_accounts); let gov_ix = Instruction { program_id: gov_program.program, diff --git a/solana/programs/wormhole-governance/src/instructions/governance.rs b/solana/programs/wormhole-governance/src/instructions/governance.rs index 227184535..d902bc132 100644 --- a/solana/programs/wormhole-governance/src/instructions/governance.rs +++ b/solana/programs/wormhole-governance/src/instructions/governance.rs @@ -125,9 +125,7 @@ impl From for Acc { } } -pub fn governance<'a, 'b, 'c, 'info>( - ctx: Context<'a, 'b, 'c, 'info, Governance<'info>>, -) -> Result<()> { +pub fn governance<'info>(ctx: Context<'_, '_, '_, 'info, Governance<'info>>) -> Result<()> { let vaa_data = ctx.accounts.vaa.data(); let mut instruction: Instruction = vaa_data.clone().into(); @@ -135,38 +133,17 @@ pub fn governance<'a, 'b, 'c, 'info>( instruction.accounts.iter_mut().for_each(|acc| { if acc.pubkey == OWNER { acc.pubkey = ctx.accounts.governance.key(); - acc.is_writable = ctx.accounts.governance.is_writable; - acc.is_signer = true; } else if acc.pubkey == PAYER { acc.pubkey = ctx.accounts.payer.key(); - acc.is_writable = ctx.accounts.payer.is_writable; - acc.is_signer = true; } }); - // TODO(SECURITY): what does the runtime verify about these accounts? - // should we match them against the accounts in the instruction? the runtime - // *should* do that but I'll add tests - let account_infos: Vec> = ctx - .remaining_accounts - .iter() - .map(|acc| { - if acc.key() == OWNER { - AccountInfo { - is_signer: true, - ..ctx.accounts.governance.to_account_info() - } - } else if acc.key() == PAYER { - ctx.accounts.payer.to_account_info() - } else { - acc.clone() - } - }) - .collect(); + let mut all_account_infos = ctx.accounts.to_account_infos(); + all_account_infos.extend_from_slice(ctx.remaining_accounts); solana_program::program::invoke_signed( &instruction, - &account_infos, + &all_account_infos, &[&[b"governance", &[ctx.bumps.governance]]], )?; From fa830f9e940caae33155445738d49535db7aed14 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 20 Feb 2024 11:41:11 -0500 Subject: [PATCH 61/90] solana: fix CI --- .github/workflows/build.yml | 4 ++++ .../example-native-token-transfers/Cargo.toml | 2 +- .../src/normalized_amount.rs | 4 ++-- .../tests/governance.rs | 8 +++----- .../tests/sdk/instructions/mod.rs | 2 +- .../tests/sdk/instructions/post_vaa.rs | 2 +- .../src/instructions/governance.rs | 12 ++++++------ solana/programs/wormhole-governance/src/lib.rs | 6 ++---- 8 files changed, 20 insertions(+), 20 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5e53af405..f225ebf25 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -102,7 +102,11 @@ jobs: BPF_PACKAGES=( programs/example-native-token-transfers/Cargo.toml + programs/wormhole-governance/Cargo.toml ) + for p in "${BPF_PACKAGES[@]}"; do + cargo build-sbf --manifest-path "${p}" + done for p in "${BPF_PACKAGES[@]}"; do cargo test-sbf --manifest-path "${p}" done diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index 2b5bd7314..b7138b6d2 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -29,11 +29,11 @@ hex = "0.4.3" solana-program = "=1.17.2" wormhole-anchor-sdk = "0.29.0-alpha.1" wormhole-io = "0.1.3" -wormhole-governance = { path = "../wormhole-governance" } [dev-dependencies] hex = "0.4.3" +wormhole-governance = { path = "../wormhole-governance", features = ["no-entrypoint"] } solana-program-test = "1.17.2" serde_json = "1.0.113" serde = "1.0.196" diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/programs/example-native-token-transfers/src/normalized_amount.rs index bdaf197bf..5f46069ba 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/programs/example-native-token-transfers/src/normalized_amount.rs @@ -16,8 +16,8 @@ pub const NORMALIZED_DECIMALS: u8 = 8; #[derive(Debug, Clone, Copy, AnchorSerialize, AnchorDeserialize, InitSpace)] pub struct NormalizedAmount { - amount: u64, - decimals: u8, + pub amount: u64, + pub decimals: u8, } impl PartialEq for NormalizedAmount { diff --git a/solana/programs/example-native-token-transfers/tests/governance.rs b/solana/programs/example-native-token-transfers/tests/governance.rs index 30863fbec..67baf074e 100644 --- a/solana/programs/example-native-token-transfers/tests/governance.rs +++ b/solana/programs/example-native-token-transfers/tests/governance.rs @@ -11,7 +11,7 @@ use solana_program_test::*; use solana_sdk::{signer::Signer, transaction::TransactionError}; use wormhole_governance::{ error::GovernanceError, - instructions::{GovernanceMessage, OWNER, PAYER}, + instructions::{GovernanceMessage, OWNER}, }; use wormhole_sdk::{Address, Vaa, GOVERNANCE_EMITTER}; @@ -45,9 +45,7 @@ async fn post_governance_vaa( payload: gov_message, }; - let posted_vaa = post_vaa(&wormhole, ctx, vaa).await; - - posted_vaa + post_vaa(wormhole, ctx, vaa).await } #[tokio::test] @@ -153,7 +151,7 @@ async fn wrap_governance( let gov_message: GovernanceMessage = ix.clone().into(); - let vaa = post_governance_vaa(ctx, &wormhole, gov_message, emitter_override).await; + let vaa = post_governance_vaa(ctx, wormhole, gov_message, emitter_override).await; let gov_accounts = wormhole_governance::accounts::Governance { payer: ctx.payer.pubkey(), diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs index 457b78d8b..732856782 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs @@ -1,6 +1,6 @@ pub mod admin; pub mod initialize; +pub mod post_vaa; pub mod redeem; pub mod release_outbound; pub mod transfer; -pub mod post_vaa; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs index 349de2909..fb807834e 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/post_vaa.rs @@ -21,7 +21,7 @@ use wormhole_sdk::vaa::*; pub const MAX_LEN_GUARDIAN_KEYS: usize = 19; -pub const GUARDIAN_SECRET_KEY: &'static str = +pub const GUARDIAN_SECRET_KEY: &str = "cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff516ab2ee113a0"; pub struct VerifySignatures { diff --git a/solana/programs/wormhole-governance/src/instructions/governance.rs b/solana/programs/wormhole-governance/src/instructions/governance.rs index d902bc132..232f109a3 100644 --- a/solana/programs/wormhole-governance/src/instructions/governance.rs +++ b/solana/programs/wormhole-governance/src/instructions/governance.rs @@ -53,13 +53,13 @@ pub struct GovernanceMessage { pub data: Vec, } -impl Into for GovernanceMessage { - fn into(self) -> Instruction { +impl From for Instruction { + fn from(val: GovernanceMessage) -> Self { let GovernanceMessage { program_id, accounts, data, - } = self; + } = val; let accounts: Vec = accounts.into_iter().map(|a| a.into()).collect(); Instruction { program_id, @@ -95,13 +95,13 @@ pub struct Acc { pub is_writable: bool, } -impl Into for Acc { - fn into(self) -> AccountMeta { +impl From for AccountMeta { + fn from(val: Acc) -> Self { let Acc { pubkey, is_signer, is_writable, - } = self; + } = val; AccountMeta { pubkey, is_signer, diff --git a/solana/programs/wormhole-governance/src/lib.rs b/solana/programs/wormhole-governance/src/lib.rs index 27388d7d2..c470a0bf7 100644 --- a/solana/programs/wormhole-governance/src/lib.rs +++ b/solana/programs/wormhole-governance/src/lib.rs @@ -2,8 +2,8 @@ use anchor_lang::prelude::*; declare_id!("7kK9JyavhgE5G8oErMziHeBzZiAu3J64oLMbNf8FpG4S"); -pub mod instructions; pub mod error; +pub mod instructions; use instructions::*; @@ -11,9 +11,7 @@ use instructions::*; pub mod wormhole_governance { use super::*; - pub fn governance<'a, 'b, 'c, 'info>( - ctx: Context<'a, 'b, 'c, 'info, Governance<'info>>, - ) -> Result<()> { + pub fn governance<'info>(ctx: Context<'_, '_, '_, 'info, Governance<'info>>) -> Result<()> { instructions::governance(ctx) } } From 2b09fe2a684dec25e6f6d1b8d026b18839e9bb56 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 20 Feb 2024 14:09:28 -0500 Subject: [PATCH 62/90] solana: remove EnabledEndpoint not enabled endpoints have a single source of truth (the config bitmap) --- .../src/instructions/admin.rs | 1 - .../src/instructions/redeem.rs | 5 ++- .../src/instructions/release_outbound.rs | 3 +- .../src/registered_endpoint.rs | 31 ------------------- .../tests/sdk/instructions/redeem.rs | 6 ++-- .../sdk/instructions/release_outbound.rs | 7 ++--- solana/ts/sdk/index.ts | 6 ++-- 7 files changed, 12 insertions(+), 47 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index fc95d5541..aa305ae3a 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -154,7 +154,6 @@ pub fn register_endpoint(ctx: Context) -> Result<()> { bump: ctx.bumps.registered_endpoint, id, endpoint_address: ctx.accounts.endpoint.key(), - enabled: true, }); ctx.accounts.config.enabled_endpoints.set(id, true); diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 088552dcd..beee6d537 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -40,7 +40,10 @@ pub struct Redeem<'info> { )] pub endpoint_message: Account<'info, ValidatedEndpointMessage>, - pub endpoint: EnabledEndpoint<'info>, + #[account( + constraint = config.enabled_endpoints.get(endpoint.id) @ NTTError::DisabledEndpoint + )] + pub endpoint: Account<'info, RegisteredEndpoint>, #[account( constraint = mint.key() == config.mint diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index d3b1ff269..b32ec8830 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -27,8 +27,9 @@ pub struct ReleaseOutbound<'info> { #[account( constraint = endpoint.endpoint_address == crate::ID, + constraint = config.enabled_endpoints.get(endpoint.id) @ NTTError::DisabledEndpoint )] - pub endpoint: EnabledEndpoint<'info>, + pub endpoint: Account<'info, RegisteredEndpoint>, #[account( mut, diff --git a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs index d8de88fb0..935c895dc 100644 --- a/solana/programs/example-native-token-transfers/src/registered_endpoint.rs +++ b/solana/programs/example-native-token-transfers/src/registered_endpoint.rs @@ -1,5 +1,3 @@ -use std::ops::{Deref, DerefMut}; - use anchor_lang::prelude::*; #[account] @@ -8,37 +6,8 @@ pub struct RegisteredEndpoint { pub bump: u8, pub id: u8, pub endpoint_address: Pubkey, - /// Whether the endpoint is enabled. - /// NOTE: there is a bitmap in the config account which must be kept in sync - /// with this. If endpoint disabling is implemented, the bitmap must be updated - /// in the same transaction as the endpoint account. - pub enabled: bool, } impl RegisteredEndpoint { pub const SEED_PREFIX: &'static [u8] = b"registered_endpoint"; } - -#[derive(Accounts)] -pub struct EnabledEndpoint<'info> { - #[account( - constraint = endpoint.enabled @ crate::error::NTTError::DisabledEndpoint, - seeds = [RegisteredEndpoint::SEED_PREFIX, endpoint.endpoint_address.as_ref()], - bump = endpoint.bump, - )] - pub endpoint: Account<'info, RegisteredEndpoint>, -} - -impl<'info> Deref for EnabledEndpoint<'info> { - type Target = Account<'info, RegisteredEndpoint>; - - fn deref(&self) -> &Self::Target { - &self.endpoint - } -} - -impl<'info> DerefMut for EnabledEndpoint<'info> { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.endpoint - } -} diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs index 64d3bf53b..7d7448ec3 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/redeem.rs @@ -1,5 +1,5 @@ use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; -use example_native_token_transfers::{accounts::EnabledEndpoint, instructions::RedeemArgs}; +use example_native_token_transfers::instructions::RedeemArgs; use solana_sdk::instruction::Instruction; use crate::sdk::accounts::NTT; @@ -23,9 +23,7 @@ pub fn redeem(ntt: &NTT, accs: Redeem, args: RedeemArgs) -> Instruction { config: ntt.config(), sibling: accs.sibling, endpoint_message: accs.endpoint_message, - endpoint: EnabledEndpoint { - endpoint: ntt.registered_endpoint(&accs.endpoint), - }, + endpoint: ntt.registered_endpoint(&accs.endpoint), mint: accs.mint, inbox_item: accs.inbox_item, inbox_rate_limit: accs.inbox_rate_limit, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs index f0718731c..964bc90b6 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs @@ -1,7 +1,6 @@ use anchor_lang::{prelude::*, InstructionData}; use example_native_token_transfers::{ - accounts::{EnabledEndpoint, NotPausedConfig}, - instructions::ReleaseOutboundArgs, + accounts::NotPausedConfig, instructions::ReleaseOutboundArgs, }; use solana_sdk::{instruction::Instruction, sysvar::SysvarId}; @@ -26,9 +25,7 @@ pub fn release_outbound( outbox_item: release_outbound.outbox_item, wormhole_message: ntt.wormhole_message(&release_outbound.outbox_item), emitter: ntt.emitter(), - endpoint: EnabledEndpoint { - endpoint: ntt.registered_endpoint(&ntt.program), - }, + endpoint: ntt.registered_endpoint(&ntt.program), wormhole_bridge: ntt.wormhole.bridge(), wormhole_fee_collector: ntt.wormhole.fee_collector(), wormhole_sequence: ntt.wormhole_sequence(), diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 24640abae..e7debfbf9 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -339,7 +339,7 @@ export class NTT { outboxItem: args.outboxItem, wormholeMessage: this.wormholeMessageAccountAddress(args.outboxItem), emitter: whAccs.wormholeEmitter, - endpoint: { endpoint: this.registeredEndpointAddress(this.program.programId) }, + endpoint: this.registeredEndpointAddress(this.program.programId), wormholeBridge: whAccs.wormholeBridge, wormholeFeeCollector: whAccs.wormholeFeeCollector, wormholeSequence: whAccs.wormholeSequence, @@ -499,8 +499,6 @@ export class NTT { limit: BN config?: Config }): Promise { - const config = await this.getConfig(args.config) - await this.program.methods.setSibling({ chainId: { id: toChainId(args.chain) }, address: Array.from(args.address), @@ -624,7 +622,7 @@ export class NTT { config: this.configAccountAddress(), sibling: managerSibling, endpointMessage: this.endpointMessageAccountAddress(chainId, new BN(managerMessage.sequence.toString())), - endpoint: { endpoint: this.registeredEndpointAddress(this.program.programId) }, + endpoint: this.registeredEndpointAddress(this.program.programId), mint: await this.mintAccountAddress(config), inboxItem: this.inboxItemAccountAddress(chainId, managerMessage), inboxRateLimit, From 43537bd7e43b295946279391ea960244679c6668 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Tue, 20 Feb 2024 16:46:32 -0500 Subject: [PATCH 63/90] solana: deploy programs as upgradeable in solana-program-test --- solana/Cargo.lock | 2 + .../example-native-token-transfers/Cargo.toml | 2 + .../tests/common/setup.rs | 161 +++++++++++++++++- 3 files changed, 161 insertions(+), 4 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index d660206cb..2bc4ab7cf 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -1489,6 +1489,7 @@ dependencies = [ "anchor-lang", "anchor-spl", "base64 0.21.7", + "bincode", "bitmaps 3.2.1", "hex", "libsecp256k1", @@ -1497,6 +1498,7 @@ dependencies = [ "serde_wormhole", "sha3 0.10.8", "solana-program", + "solana-program-runtime", "solana-program-test", "solana-sdk", "spl-associated-token-account", diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index b7138b6d2..a5b4de097 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -46,3 +46,5 @@ wormhole-raw-vaas = "0.2.0-alpha.2" libsecp256k1 = "=0.6.0" wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } +solana-program-runtime = "1.17.2" +bincode = "1.3.3" diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index 343affbc9..d64281797 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -1,3 +1,5 @@ +use std::path::PathBuf; + use anchor_lang::prelude::{Error, Id, Pubkey}; use anchor_spl::token::{Mint, Token}; use example_native_token_transfers::{ @@ -6,7 +8,12 @@ use example_native_token_transfers::{ endpoints::wormhole::SetEndpointSiblingArgs, instructions::{InitializeArgs, SetSiblingArgs}, }; -use solana_program_test::{ProgramTest, ProgramTestContext}; +use solana_program::{bpf_loader_upgradeable::UpgradeableLoaderState, rent::Rent}; +use solana_program_runtime::{ + invoke_context::ProcessInstructionWithContext, + log_collector::log::{trace, warn}, +}; +use solana_program_test::{find_file, read_file, ProgramTest, ProgramTestContext}; use solana_sdk::{ account::Account, signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, @@ -73,17 +80,28 @@ pub async fn setup(mode: Mode) -> (ProgramTestContext, TestData) { setup_with_extra_accounts(mode, &[]).await } +fn prefer_bpf() -> bool { + std::env::var("BPF_OUT_DIR").is_ok() || std::env::var("SBF_OUT_DIR").is_ok() +} + pub async fn setup_programs() -> Result { let mut program_test = ProgramTest::default(); - program_test.add_program( + add_program_upgradeable( + &mut program_test, "example_native_token_transfers", example_native_token_transfers::ID, None, ); - program_test.add_program("wormhole_governance", wormhole_governance::ID, None); + add_program_upgradeable( + &mut program_test, + "wormhole_governance", + wormhole_governance::ID, + None, + ); - program_test.add_program( + add_program_upgradeable( + &mut program_test, "mainnet_core_bridge", wormhole_anchor_sdk::wormhole::program::ID, None, @@ -285,3 +303,138 @@ pub async fn create_mint( blockhash, ) } + +// TODO: upstream this to solana-program-test + +/// Add a SBF program to the test environment. (copied from solana_program_test +/// `add_program`, but the owner is bpf_loader_upgradeable) +/// +/// `program_name` will also be used to locate the SBF shared object in the current or fixtures +/// directory. +/// +/// If `process_instruction` is provided, the natively built-program may be used instead of the +/// SBF shared object depending on the `BPF_OUT_DIR` environment variable. +pub fn add_program_upgradeable( + program_test: &mut ProgramTest, + program_name: &str, + program_id: Pubkey, + process_instruction: Option, +) { + let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| { + let elf = read_file(program_file); + + let (programdata_address, _) = Pubkey::find_program_address( + &[program_id.as_ref()], + &solana_sdk::bpf_loader_upgradeable::id(), + ); + let mut program_data = bincode::serialize(&UpgradeableLoaderState::ProgramData { + slot: 0, + upgrade_authority_address: Some(Pubkey::default()), + }) + .unwrap(); + program_data.extend_from_slice(&elf); + + this.add_account( + programdata_address, + Account { + lamports: Rent::default().minimum_balance(program_data.len()).max(1), + data: program_data, + owner: solana_sdk::bpf_loader_upgradeable::id(), + executable: false, + rent_epoch: 0, + }, + ); + + let data = bincode::serialize(&UpgradeableLoaderState::Program { + programdata_address, + }) + .unwrap(); + + this.add_account( + program_id, + Account { + lamports: Rent::default().minimum_balance(data.len()).max(1), + data, + owner: solana_sdk::bpf_loader_upgradeable::id(), + executable: true, + rent_epoch: 0, + }, + ); + }; + + let warn_invalid_program_name = || { + let valid_program_names = default_shared_object_dirs() + .iter() + .filter_map(|dir| dir.read_dir().ok()) + .flat_map(|read_dir| { + read_dir.filter_map(|entry| { + let path = entry.ok()?.path(); + if !path.is_file() { + return None; + } + match path.extension()?.to_str()? { + "so" => Some(path.file_stem()?.to_os_string()), + _ => None, + } + }) + }) + .collect::>(); + + if valid_program_names.is_empty() { + // This should be unreachable as `test-bpf` should guarantee at least one shared + // object exists somewhere. + warn!("No SBF shared objects found."); + return; + } + + warn!( + "Possible bogus program name. Ensure the program name ({}) \ + matches one of the following recognizable program names:", + program_name, + ); + for name in valid_program_names { + warn!(" - {}", name.to_str().unwrap()); + } + }; + + let program_file = find_file(&format!("{program_name}.so")); + match (prefer_bpf(), program_file, process_instruction) { + // If SBF is preferred (i.e., `test-sbf` is invoked) and a BPF shared object exists, + // use that as the program data. + (true, Some(file), _) => add_bpf(program_test, file), + + // If SBF is not required (i.e., we were invoked with `test`), use the provided + // processor function as is. + // + // TODO: figure out why tests hang if a processor panics when running native code. + (false, _, Some(process)) => { + program_test.add_builtin_program(program_name, program_id, process) + } + + // Invalid: `test-sbf` invocation with no matching SBF shared object. + (true, None, _) => { + warn_invalid_program_name(); + panic!("Program file data not available for {program_name} ({program_id})"); + } + + // Invalid: regular `test` invocation without a processor. + (false, _, None) => { + panic!("Program processor not available for {program_name} ({program_id})"); + } + } +} + +fn default_shared_object_dirs() -> Vec { + let mut search_path = vec![]; + if let Ok(bpf_out_dir) = std::env::var("BPF_OUT_DIR") { + search_path.push(PathBuf::from(bpf_out_dir)); + } else if let Ok(bpf_out_dir) = std::env::var("SBF_OUT_DIR") { + search_path.push(PathBuf::from(bpf_out_dir)); + } + search_path.push(PathBuf::from("tests/fixtures")); + if let Ok(dir) = std::env::current_dir() { + search_path.push(dir); + } + trace!("SBF .so search path: {:?}", search_path); + search_path +} From 833918615fd420a3a9eb74cfe3b77bc785701004 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Tue, 20 Feb 2024 18:22:37 -0500 Subject: [PATCH 64/90] solana: solana: set upgrade authority; rm transfer authority args --- solana/Cargo.lock | 23 ++++-- solana/Cargo.toml | 14 ++++ .../example-native-token-transfers/Cargo.toml | 25 +++--- .../src/error.rs | 2 + .../src/instructions/admin.rs | 80 ++++++++++++++++--- .../src/instructions/initialize.rs | 14 +++- .../example-native-token-transfers/src/lib.rs | 7 +- .../tests/common/setup.rs | 19 +++-- .../tests/governance.rs | 19 ++--- .../tests/sdk/accounts.rs | 12 +++ .../tests/sdk/instructions/initialize.rs | 8 +- .../programs/wormhole-governance/Cargo.toml | 10 +-- 12 files changed, 172 insertions(+), 61 deletions(-) diff --git a/solana/Cargo.lock b/solana/Cargo.lock index 2bc4ab7cf..fcd066406 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "cd7d5a2cecb58716e47d67d5703a249964b14c7be1ec3cad3affc295b2d1c35d" dependencies = [ "cfg-if", "getrandom 0.2.12", @@ -1485,7 +1485,7 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" name = "example-native-token-transfers" version = "0.1.0" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.5", "anchor-lang", "anchor-spl", "base64 0.21.7", @@ -1508,6 +1508,7 @@ dependencies = [ "wormhole-io", "wormhole-raw-vaas", "wormhole-sdk", + "wormhole-solana-utils", ] [[package]] @@ -1773,7 +1774,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.5", ] [[package]] @@ -3872,7 +3873,7 @@ version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "098378043a888c680de07eee987bf927e23e0720b472ba61c753d7b3757e6b3e" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.5", "blake3", "block-buffer 0.10.4", "bs58 0.4.0", @@ -3985,7 +3986,7 @@ version = "1.17.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fcffede3b37ccdddbd57f93e4228b268f05c0a5cb44cb6e382ed8a31a15f5573" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.5", "bincode", "bv", "caps", @@ -5929,6 +5930,16 @@ dependencies = [ "thiserror", ] +[[package]] +name = "wormhole-solana-utils" +version = "0.2.0-alpha.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae4412bb88773852fe58215601cda7d8f7f0204a700526f25a9ece951715774" +dependencies = [ + "anchor-lang", + "solana-program", +] + [[package]] name = "x509-parser" version = "0.14.0" diff --git a/solana/Cargo.toml b/solana/Cargo.toml index f39770481..fbf1730be 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -4,6 +4,20 @@ members = [ ] resolver = "2" +[workspace.dependencies] +wormhole-io = "0.1.3" +wormhole-solana-utils = "0.2.0-alpha.15" + +anchor-lang = "0.29.0" +anchor-spl = "0.29.0" +solana-program = "=1.17.2" + +wormhole-anchor-sdk = "0.29.0-alpha.1" +wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } +serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } + +hex = "0.4.3" + [profile.release] overflow-checks = true lto = "fat" diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index a5b4de097..1ea7d58b9 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -20,31 +20,30 @@ idl-build = [ ] [dependencies] -ahash = "=0.8.6" +ahash = "=0.8.5" -anchor-lang = { version = "0.29.0", features = ["init-if-needed"] } -anchor-spl = "0.29.0" +anchor-lang = { workspace = true, features = ["init-if-needed"] } +anchor-spl.workspace = true bitmaps = "3.2.1" -hex = "0.4.3" -solana-program = "=1.17.2" -wormhole-anchor-sdk = "0.29.0-alpha.1" -wormhole-io = "0.1.3" +hex.workspace = true +solana-program.workspace = true +wormhole-anchor-sdk.workspace = true +wormhole-io.workspace = true +wormhole-solana-utils.workspace = true [dev-dependencies] -hex = "0.4.3" - wormhole-governance = { path = "../wormhole-governance", features = ["no-entrypoint"] } -solana-program-test = "1.17.2" +solana-program-test = "*" serde_json = "1.0.113" serde = "1.0.196" base64 = "0.21.7" -solana-sdk = "1.17.2" +solana-sdk = "*" spl-token = "4" spl-associated-token-account = "2.2.0" sha3 = "0.10.4" wormhole-raw-vaas = "0.2.0-alpha.2" libsecp256k1 = "=0.6.0" -wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } -serde_wormhole = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } +wormhole-sdk.workspace = true +serde_wormhole.workspace = true solana-program-runtime = "1.17.2" bincode = "1.3.3" diff --git a/solana/programs/example-native-token-transfers/src/error.rs b/solana/programs/example-native-token-transfers/src/error.rs index 2c5c790f6..5a6ca9fba 100644 --- a/solana/programs/example-native-token-transfers/src/error.rs +++ b/solana/programs/example-native-token-transfers/src/error.rs @@ -31,4 +31,6 @@ pub enum NTTError { Paused, #[msg("DisabledEndpoint")] DisabledEndpoint, + #[msg("InvalidDeployer")] + InvalidDeployer, } diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index aa305ae3a..500f1c523 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -1,4 +1,5 @@ use anchor_lang::prelude::*; +use wormhole_solana_utils::cpi::bpf_loader_upgradeable::{self, BpfLoaderUpgradeable}; use crate::{ chain_id::ChainId, @@ -20,19 +21,45 @@ pub struct TransferOwnership<'info> { pub config: Account<'info, Config>, pub owner: Signer<'info>, -} -#[derive(AnchorDeserialize, AnchorSerialize)] -pub struct TransferOwnershipArgs { - pub new_owner: Pubkey, + /// CHECK: This account will be the signer in the [claim_ownership] instruction. + new_owner: AccountInfo<'info>, + + /// CHECK: Seeds must be \["upgrade-lock"\]. + #[account( + seeds = [b"upgrade-lock"], + bump, + )] + upgrade_lock: AccountInfo<'info>, + + #[account( + mut, + seeds = [crate::ID.as_ref()], + bump, + seeds::program = bpf_loader_upgradeable_program, + )] + program_data: Account<'info, ProgramData>, + + bpf_loader_upgradeable_program: Program<'info, BpfLoaderUpgradeable>, } -pub fn transfer_ownership( - ctx: Context, - args: TransferOwnershipArgs, -) -> Result<()> { - ctx.accounts.config.pending_owner = Some(args.new_owner); - Ok(()) +pub fn transfer_ownership(ctx: Context) -> Result<()> { + ctx.accounts.config.pending_owner = Some(ctx.accounts.new_owner.key()); + + bpf_loader_upgradeable::set_upgrade_authority_checked( + CpiContext::new_with_signer( + ctx.accounts + .bpf_loader_upgradeable_program + .to_account_info(), + bpf_loader_upgradeable::SetUpgradeAuthorityChecked { + program_data: ctx.accounts.program_data.to_account_info(), + current_authority: ctx.accounts.owner.to_account_info(), + new_authority: ctx.accounts.upgrade_lock.to_account_info(), + }, + &[&[b"upgrade-lock", &[ctx.bumps.upgrade_lock]]], + ), + &crate::ID, + ) } // * Claim ownership @@ -45,13 +72,44 @@ pub struct ClaimOwnership<'info> { )] pub config: Account<'info, Config>, + /// CHECK: Seeds must be \["upgrade-lock"\]. + #[account( + seeds = [b"upgrade-lock"], + bump, + )] + upgrade_lock: AccountInfo<'info>, + pub new_owner: Signer<'info>, + + #[account( + mut, + seeds = [crate::ID.as_ref()], + bump, + seeds::program = bpf_loader_upgradeable_program, + )] + program_data: Account<'info, ProgramData>, + + bpf_loader_upgradeable_program: Program<'info, BpfLoaderUpgradeable>, } pub fn claim_ownership(ctx: Context) -> Result<()> { ctx.accounts.config.pending_owner = None; ctx.accounts.config.owner = ctx.accounts.new_owner.key(); - Ok(()) + + bpf_loader_upgradeable::set_upgrade_authority_checked( + CpiContext::new_with_signer( + ctx.accounts + .bpf_loader_upgradeable_program + .to_account_info(), + bpf_loader_upgradeable::SetUpgradeAuthorityChecked { + program_data: ctx.accounts.program_data.to_account_info(), + current_authority: ctx.accounts.upgrade_lock.to_account_info(), + new_authority: ctx.accounts.new_owner.to_account_info(), + }, + &[&[b"upgrade-lock", &[ctx.bumps.upgrade_lock]]], + ), + &crate::ID, + ) } // * Set siblings diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 3fa6139c5..680ba576d 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -1,5 +1,6 @@ use anchor_lang::prelude::*; use anchor_spl::{associated_token::AssociatedToken, token_interface}; +use wormhole_solana_utils::cpi::bpf_loader_upgradeable::BpfLoaderUpgradeable; use crate::{ bitmap::Bitmap, @@ -16,7 +17,15 @@ pub struct Initialize<'info> { #[account(mut)] pub payer: Signer<'info>, - pub owner: Signer<'info>, + #[account(address = program_data.upgrade_authority_address.unwrap_or_default())] + pub deployer: Signer<'info>, + + #[account( + seeds = [crate::ID.as_ref()], + bump, + seeds::program = bpf_loader_upgradeable_program, + )] + program_data: Account<'info, ProgramData>, #[account( init, @@ -74,6 +83,7 @@ pub struct Initialize<'info> { /// associated token account for the given mint. pub token_program: Interface<'info, token_interface::TokenInterface>, pub associated_token_program: Program<'info, AssociatedToken>, + bpf_loader_upgradeable_program: Program<'info, BpfLoaderUpgradeable>, system_program: Program<'info, System>, } @@ -92,7 +102,7 @@ pub fn initialize(ctx: Context, args: InitializeArgs) -> Result<()> token_program: ctx.accounts.token_program.key(), mode: args.mode, chain_id: ChainId { id: args.chain_id }, - owner: ctx.accounts.owner.key(), + owner: ctx.accounts.deployer.key(), pending_owner: None, paused: false, next_endpoint_id: 0, diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 3ab36f34c..bef34da79 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -62,11 +62,8 @@ pub mod example_native_token_transfers { instructions::release_inbound_unlock(ctx, args) } - pub fn transfer_ownership( - ctx: Context, - args: TransferOwnershipArgs, - ) -> Result<()> { - instructions::transfer_ownership(ctx, args) + pub fn transfer_ownership(ctx: Context) -> Result<()> { + instructions::transfer_ownership(ctx) } pub fn claim_ownership(ctx: Context) -> Result<()> { diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index d64281797..57e969b5c 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -62,7 +62,8 @@ pub async fn setup_with_extra_accounts( mode: Mode, accounts: &[(Pubkey, Account)], ) -> (ProgramTestContext, TestData) { - let mut program_test = setup_programs().await.unwrap(); + let program_owner = Keypair::new(); + let mut program_test = setup_programs(program_owner.pubkey()).await.unwrap(); for (pubkey, account) in accounts { program_test.add_account(*pubkey, account.clone()); @@ -70,7 +71,7 @@ pub async fn setup_with_extra_accounts( let mut ctx = program_test.start_with_context().await; - let test_data = setup_accounts(&mut ctx).await; + let test_data = setup_accounts(&mut ctx, program_owner).await; setup_ntt(&mut ctx, &test_data, mode).await; (ctx, test_data) @@ -84,13 +85,14 @@ fn prefer_bpf() -> bool { std::env::var("BPF_OUT_DIR").is_ok() || std::env::var("SBF_OUT_DIR").is_ok() } -pub async fn setup_programs() -> Result { +pub async fn setup_programs(program_owner: Pubkey) -> Result { let mut program_test = ProgramTest::default(); add_program_upgradeable( &mut program_test, "example_native_token_transfers", example_native_token_transfers::ID, None, + Some(program_owner), ); add_program_upgradeable( @@ -98,6 +100,7 @@ pub async fn setup_programs() -> Result { "wormhole_governance", wormhole_governance::ID, None, + None, ); add_program_upgradeable( @@ -105,6 +108,7 @@ pub async fn setup_programs() -> Result { "mainnet_core_bridge", wormhole_anchor_sdk::wormhole::program::ID, None, + None, ); BridgeData::add_account( @@ -149,7 +153,7 @@ pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: &test_data.ntt, Initialize { payer: ctx.payer.pubkey(), - owner: test_data.program_owner.pubkey(), + deployer: test_data.program_owner.pubkey(), mint: test_data.mint, }, InitializeArgs { @@ -208,10 +212,8 @@ pub async fn setup_ntt(ctx: &mut ProgramTestContext, test_data: &TestData, mode: .unwrap(); } -pub async fn setup_accounts(ctx: &mut ProgramTestContext) -> TestData { +pub async fn setup_accounts(ctx: &mut ProgramTestContext, program_owner: Keypair) -> TestData { // create mint - let program_owner = Keypair::new(); - let mint = Keypair::new(); let mint_authority = Keypair::new(); @@ -319,6 +321,7 @@ pub fn add_program_upgradeable( program_name: &str, program_id: Pubkey, process_instruction: Option, + upgrade_authority_address: Option, ) { let add_bpf = |this: &mut ProgramTest, program_file: PathBuf| { let elf = read_file(program_file); @@ -329,7 +332,7 @@ pub fn add_program_upgradeable( ); let mut program_data = bincode::serialize(&UpgradeableLoaderState::ProgramData { slot: 0, - upgrade_authority_address: Some(Pubkey::default()), + upgrade_authority_address: upgrade_authority_address.or(Some(Pubkey::default())), }) .unwrap(); program_data.extend_from_slice(&elf); diff --git a/solana/programs/example-native-token-transfers/tests/governance.rs b/solana/programs/example-native-token-transfers/tests/governance.rs index 67baf074e..eefbc4d62 100644 --- a/solana/programs/example-native-token-transfers/tests/governance.rs +++ b/solana/programs/example-native-token-transfers/tests/governance.rs @@ -1,10 +1,7 @@ #![feature(type_changing_struct_update)] use anchor_lang::{prelude::*, InstructionData}; -use example_native_token_transfers::{ - config::{Config, Mode}, - instructions::TransferOwnershipArgs, -}; +use example_native_token_transfers::config::{Config, Mode}; use sdk::accounts::{Governance, Wormhole}; use solana_program::instruction::{Instruction, InstructionError}; use solana_program_test::*; @@ -14,6 +11,7 @@ use wormhole_governance::{ instructions::{GovernanceMessage, OWNER}, }; use wormhole_sdk::{Address, Vaa, GOVERNANCE_EMITTER}; +use wormhole_solana_utils::cpi::bpf_loader_upgradeable; use crate::{ common::{query::GetAccountDataAnchor, setup::setup, submit::Submittable}, @@ -55,15 +53,15 @@ async fn test_governance() { let governance_pda = test_data.governance.governance(); // step 1. transfer ownership to governance - let ix = example_native_token_transfers::instruction::TransferOwnership { - args: TransferOwnershipArgs { - new_owner: governance_pda, - }, - }; + let ix = example_native_token_transfers::instruction::TransferOwnership; let accs = example_native_token_transfers::accounts::TransferOwnership { config: test_data.ntt.config(), owner: test_data.program_owner.pubkey(), + new_owner: governance_pda, + upgrade_lock: test_data.ntt.upgrade_lock(), + program_data: test_data.ntt.program_data(), + bpf_loader_upgradeable_program: bpf_loader_upgradeable::id(), }; Instruction { @@ -80,6 +78,9 @@ async fn test_governance() { let inner_ix_accs = example_native_token_transfers::accounts::ClaimOwnership { new_owner: OWNER, config: test_data.ntt.config(), + upgrade_lock: test_data.ntt.upgrade_lock(), + program_data: test_data.ntt.program_data(), + bpf_loader_upgradeable_program: bpf_loader_upgradeable::id(), }; let inner_ix: Instruction = Instruction { diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index f540f4a68..70133913e 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -12,6 +12,7 @@ use example_native_token_transfers::{ use sha3::{Digest, Keccak256}; use wormhole_anchor_sdk::wormhole; use wormhole_io::TypePrefixedPayload; +use wormhole_solana_utils::cpi::bpf_loader_upgradeable; pub struct Wormhole { pub program: Pubkey, @@ -179,4 +180,15 @@ impl NTT { pub fn wormhole_sequence(&self) -> Pubkey { self.wormhole.sequence(&self.emitter()) } + + pub fn program_data(&self) -> Pubkey { + let (addr, _) = + Pubkey::find_program_address(&[self.program.as_ref()], &bpf_loader_upgradeable::id()); + addr + } + + pub fn upgrade_lock(&self) -> Pubkey { + let (addr, _) = Pubkey::find_program_address(&[b"upgrade-lock"], &self.program); + addr + } } diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs index 651a2e8cc..afa7fe528 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/initialize.rs @@ -2,21 +2,24 @@ use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, use anchor_spl::{associated_token::AssociatedToken, token::Token}; use example_native_token_transfers::instructions::InitializeArgs; use solana_sdk::instruction::Instruction; +use wormhole_solana_utils::cpi::bpf_loader_upgradeable::BpfLoaderUpgradeable; use crate::sdk::accounts::NTT; pub struct Initialize { pub payer: Pubkey, - pub owner: Pubkey, + pub deployer: Pubkey, pub mint: Pubkey, } pub fn initialize(ntt: &NTT, accounts: Initialize, args: InitializeArgs) -> Instruction { let data = example_native_token_transfers::instruction::Initialize { args }; + let bpf_loader_upgradeable_program = BpfLoaderUpgradeable::id(); let accounts = example_native_token_transfers::accounts::Initialize { payer: accounts.payer, - owner: accounts.owner, + deployer: accounts.deployer, + program_data: ntt.program_data(), config: ntt.config(), mint: accounts.mint, seq: ntt.sequence(), @@ -25,6 +28,7 @@ pub fn initialize(ntt: &NTT, accounts: Initialize, args: InitializeArgs) -> Inst custody: ntt.custody(&accounts.mint), token_program: Token::id(), associated_token_program: AssociatedToken::id(), + bpf_loader_upgradeable_program, system_program: System::id(), }; diff --git a/solana/programs/wormhole-governance/Cargo.toml b/solana/programs/wormhole-governance/Cargo.toml index c879d9ce8..fa65cc833 100644 --- a/solana/programs/wormhole-governance/Cargo.toml +++ b/solana/programs/wormhole-governance/Cargo.toml @@ -18,9 +18,9 @@ idl-build = [ ] [dependencies] -anchor-lang = "0.29.0" +anchor-lang.workspace = true +solana-program.workspace = true -solana-program = "=1.17.2" -wormhole-anchor-sdk = "0.29.0-alpha.1" -wormhole-io = "0.1.3" -wormhole-sdk = { git = "https://github.com/wormhole-foundation/wormhole", rev = "eee4641" } +wormhole-anchor-sdk.workspace = true +wormhole-io.workspace = true +wormhole-sdk.workspace = true From c0bd3a94958867d592fde35b686224215453fc13 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Wed, 21 Feb 2024 10:25:55 -0500 Subject: [PATCH 65/90] solana: solana: couple things... * add token authority const * transfer using token authority --- .../src/instructions/initialize.rs | 2 +- .../src/instructions/release_inbound.rs | 12 ++- .../src/instructions/transfer.rs | 41 ++++--- .../example-native-token-transfers/src/lib.rs | 2 + .../tests/cancel_flow.rs | 14 ++- .../tests/sdk/instructions/transfer.rs | 23 +++- .../tests/transfer.rs | 101 +++++++++++++++++- 7 files changed, 170 insertions(+), 25 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 680ba576d..2aa836b24 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -63,7 +63,7 @@ pub struct Initialize<'info> { pub rate_limit: Account<'info, OutboxRateLimit>, #[account( - seeds = [b"token_authority"], + seeds = [crate::TOKEN_AUTHORITY_SEED], bump, )] pub token_authority: AccountInfo<'info>, diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs index 508db7cfb..72cdd0eb9 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_inbound.rs @@ -25,7 +25,7 @@ pub struct ReleaseInbound<'info> { pub recipient: InterfaceAccount<'info, token_interface::TokenAccount>, #[account( - seeds = [b"token_authority"], + seeds = [crate::TOKEN_AUTHORITY_SEED], bump, )] pub token_authority: AccountInfo<'info>, @@ -85,7 +85,10 @@ pub fn release_inbound_mint( to: ctx.accounts.common.recipient.to_account_info(), authority: ctx.accounts.common.token_authority.clone(), }, - &[&[b"token_authority", &[ctx.bumps.common.token_authority]]], + &[&[ + crate::TOKEN_AUTHORITY_SEED, + &[ctx.bumps.common.token_authority], + ]], ), inbox_item.amount, ), @@ -139,7 +142,10 @@ pub fn release_inbound_unlock( authority: ctx.accounts.common.token_authority.clone(), mint: ctx.accounts.common.mint.to_account_info(), }, - &[&[b"token_authority", &[ctx.bumps.common.token_authority]]], + &[&[ + crate::TOKEN_AUTHORITY_SEED, + &[ctx.bumps.common.token_authority], + ]], ), inbox_item.amount, ctx.accounts.common.mint.decimals, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index f22bbad0c..8482cdf47 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -24,6 +24,9 @@ pub struct Transfer<'info> { pub config: NotPausedConfig<'info>, + /// This signer will be encoded in the outbox. + sender: Signer<'info>, + #[account( mut, address = config.mint, @@ -37,10 +40,6 @@ pub struct Transfer<'info> { )] pub from: InterfaceAccount<'info, token_interface::TokenAccount>, - /// authority to burn the tokens (owner) - /// CHECK: this is checked by the token program - pub from_authority: Signer<'info>, - pub token_program: Interface<'info, token_interface::TokenInterface>, #[account( @@ -60,6 +59,14 @@ pub struct Transfer<'info> { #[account(mut)] pub outbox_rate_limit: Account<'info, OutboxRateLimit>, + /// CHECK: This authority will need to have been delegated authority to + /// transfer or burn tokens in the [from](Self::from) account. + #[account( + seeds = [crate::TOKEN_AUTHORITY_SEED], + bump, + )] + token_authority: AccountInfo<'info>, + pub system_program: Program<'info, System>, } @@ -103,13 +110,17 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( match accs.common.config.mode { Mode::Burning => token_interface::burn( - CpiContext::new( + CpiContext::new_with_signer( accs.common.token_program.to_account_info(), token_interface::Burn { mint: accs.common.mint.to_account_info(), from: accs.common.from.to_account_info(), - authority: accs.common.from_authority.to_account_info(), + authority: accs.common.token_authority.to_account_info(), }, + &[&[ + crate::TOKEN_AUTHORITY_SEED, + &[ctx.bumps.common.token_authority], + ]], ), amount, )?, @@ -142,16 +153,10 @@ pub struct TransferLock<'info> { // have access to the instruction args pub inbox_rate_limit: Account<'info, InboxRateLimit>, - #[account( - seeds = [b"token_authority"], - bump, - )] - pub token_authority: AccountInfo<'info>, - #[account( mut, token::mint = common.mint, - token::authority = token_authority, + token::authority = common.token_authority, )] pub custody: InterfaceAccount<'info, token_interface::TokenAccount>, } @@ -173,14 +178,18 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( match accs.common.config.mode { Mode::Burning => return Err(NTTError::InvalidMode.into()), Mode::Locking => token_interface::transfer_checked( - CpiContext::new( + CpiContext::new_with_signer( accs.common.token_program.to_account_info(), token_interface::TransferChecked { from: accs.common.from.to_account_info(), to: accs.custody.to_account_info(), - authority: accs.common.from_authority.to_account_info(), + authority: accs.common.token_authority.to_account_info(), mint: accs.common.mint.to_account_info(), }, + &[&[ + crate::TOKEN_AUTHORITY_SEED, + &[ctx.bumps.common.token_authority], + ]], ), amount, accs.common.mint.decimals, @@ -226,7 +235,7 @@ fn insert_into_outbox( common.outbox_item.set_inner(OutboxItem { sequence, amount: NormalizedAmount::normalize(amount, common.mint.decimals), - sender: common.from_authority.key(), + sender: common.sender.key(), recipient_chain, recipient_address, release_timestamp, diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index bef34da79..d34d8dbeb 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -20,6 +20,8 @@ use instructions::*; declare_id!("F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV"); +const TOKEN_AUTHORITY_SEED: &[u8] = b"token_authority"; + #[program] pub mod example_native_token_transfers { diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 09c6e6ec8..32080c29b 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -16,7 +16,10 @@ use solana_program_test::*; use solana_sdk::{signature::Keypair, signer::Signer}; use wormhole_sdk::{Address, Vaa}; -use crate::{common::submit::Submittable, sdk::instructions::transfer::transfer}; +use crate::{ + common::submit::Submittable, + sdk::instructions::transfer::{approve_token_authority, transfer}, +}; use crate::{ common::{query::GetAccountDataAnchor, setup::setup}, sdk::{ @@ -194,6 +197,15 @@ async fn test_cancel() { let (accs, args) = init_transfer_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 7000, true); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs index 6780ab28b..250490a6c 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs @@ -1,5 +1,5 @@ use anchor_lang::{prelude::Pubkey, system_program::System, Id, InstructionData, ToAccountMetas}; -use anchor_spl::token::Token; +use anchor_spl::{token::Token, token_2022::spl_token_2022}; use example_native_token_transfers::{ accounts::NotPausedConfig, config::Mode, instructions::TransferArgs, }; @@ -46,7 +46,6 @@ pub fn transfer_lock(ntt: &NTT, transfer: Transfer, args: TransferArgs) -> Instr let accounts = example_native_token_transfers::accounts::TransferLock { common: common(ntt, &transfer), inbox_rate_limit: ntt.inbox_rate_limit(chain_id), - token_authority: ntt.token_authority(), custody: ntt.custody(&transfer.mint), }; Instruction { @@ -56,19 +55,37 @@ pub fn transfer_lock(ntt: &NTT, transfer: Transfer, args: TransferArgs) -> Instr } } +pub fn approve_token_authority( + ntt: &NTT, + user_token_account: &Pubkey, + user: &Pubkey, + amount: u64, +) -> Instruction { + spl_token_2022::instruction::approve( + &spl_token::id(), // TODO: look into how token account was originally created + user_token_account, + &ntt.token_authority(), + &user, + &[user], + amount, + ) + .unwrap() +} + fn common(ntt: &NTT, transfer: &Transfer) -> example_native_token_transfers::accounts::Transfer { example_native_token_transfers::accounts::Transfer { payer: transfer.payer, config: NotPausedConfig { config: ntt.config(), }, + sender: transfer.from_authority, mint: transfer.mint, from: transfer.from, - from_authority: transfer.from_authority, token_program: Token::id(), seq: ntt.sequence(), outbox_item: transfer.outbox_item, outbox_rate_limit: ntt.outbox_rate_limit(), + token_authority: ntt.token_authority(), system_program: System::id(), } } diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index dd5a1d7cb..5a60229a1 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -26,7 +26,7 @@ use crate::{ common::submit::Submittable, sdk::instructions::{ admin::{set_paused, SetPaused}, - transfer::transfer, + transfer::{approve_token_authority, transfer}, }, }; use crate::{ @@ -99,6 +99,15 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: let (accs, args) = init_accs_args(ctx, test_data, outbox_item.pubkey(), 100, false); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, mode) .submit_with_signers(&[&test_data.user, &outbox_item], ctx) .await @@ -198,6 +207,15 @@ async fn test_burn_mode_burns_tokens() { .get_account_data_anchor(test_data.user_token_account) .await; + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Burning) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -237,6 +255,15 @@ async fn locking_mode_locks_tokens() { let mint_before: Mint = ctx.get_account_data_anchor(test_data.mint).await; + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -281,6 +308,15 @@ async fn test_rate_limit() { .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) .await; + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -303,6 +339,15 @@ async fn test_transfer_wrong_mode() { let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 100, false); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); // make sure we can't transfer in the wrong mode let err = transfer(&test_data.ntt, accs.clone(), args.clone(), Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) @@ -347,6 +392,15 @@ async fn test_large_tx_queue() { .get_account_data_anchor(test_data.ntt.outbox_rate_limit()) .await; + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -381,6 +435,15 @@ async fn test_cant_transfer_when_paused() { .await .unwrap(); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); let err = transfer(&test_data.ntt, accs.clone(), args.clone(), Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -403,6 +466,15 @@ async fn test_cant_transfer_when_paused() { .await .unwrap(); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -425,6 +497,15 @@ async fn test_large_tx_no_queue() { should_queue, ); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); let err = transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -448,6 +529,15 @@ async fn test_cant_release_queued() { let too_much = OUTBOUND_LIMIT + 1000; let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), too_much, true); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await @@ -513,6 +603,15 @@ async fn test_cant_release_twice() { let (accs, args) = init_accs_args(&mut ctx, &test_data, outbox_item.pubkey(), 100, false); + approve_token_authority( + &test_data.ntt, + &test_data.user_token_account, + &test_data.user.pubkey(), + args.amount, + ) + .submit_with_signers(&[&test_data.user], &mut ctx) + .await + .unwrap(); transfer(&test_data.ntt, accs, args, Mode::Locking) .submit_with_signers(&[&test_data.user, &outbox_item], &mut ctx) .await From f76f07a0e2013a7c97d15d33f6718e6808de9e10 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Wed, 21 Feb 2024 11:41:38 -0500 Subject: [PATCH 66/90] solana: solana: fix clippy --- .../tests/sdk/instructions/transfer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs index 250490a6c..9f2d497d6 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/transfer.rs @@ -65,7 +65,7 @@ pub fn approve_token_authority( &spl_token::id(), // TODO: look into how token account was originally created user_token_account, &ntt.token_authority(), - &user, + user, &[user], amount, ) From 666b3b32687d44441f97ecf26abdf841500a8979 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Wed, 21 Feb 2024 12:12:17 -0500 Subject: [PATCH 67/90] solana: fix solana version parse --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index f225ebf25..6e59eeecf 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -23,7 +23,7 @@ jobs: - name: Get solana version id: solana run: | - SOLANA_VERSION="$(awk '/solana-program =/ { print substr($3, 3, length($3)-3) }' solana/programs/example-native-token-transfers/Cargo.toml)" + SOLANA_VERSION="$(awk '/solana-program =/ { print substr($3, 3, length($3)-3) }' solana/Cargo.toml)" echo "::set-output name=version::${SOLANA_VERSION}" - name: Cache rust toolchain From 6690b7b764fe57e546199d663f75752ed8133f63 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 21 Feb 2024 13:45:29 -0500 Subject: [PATCH 68/90] solana: ProgramData idl generation --- .../src/instructions/admin.rs | 3 +++ .../src/instructions/initialize.rs | 3 +++ .../example-native-token-transfers/src/messages.rs | 10 ++++++++++ 3 files changed, 16 insertions(+) diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 500f1c523..1099bb73d 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -1,6 +1,9 @@ use anchor_lang::prelude::*; use wormhole_solana_utils::cpi::bpf_loader_upgradeable::{self, BpfLoaderUpgradeable}; +#[cfg(feature = "idl-build")] +use crate::messages::Hack; + use crate::{ chain_id::ChainId, config::Config, diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 2aa836b24..2796bb9bf 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -2,6 +2,9 @@ use anchor_lang::prelude::*; use anchor_spl::{associated_token::AssociatedToken, token_interface}; use wormhole_solana_utils::cpi::bpf_loader_upgradeable::BpfLoaderUpgradeable; +#[cfg(feature = "idl-build")] +use crate::messages::Hack; + use crate::{ bitmap::Bitmap, chain_id::ChainId, diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 4cb357795..4b5a99c94 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -356,6 +356,16 @@ impl Hack for PhantomData { } } +impl Hack for ProgramData { + fn __anchor_private_full_path() -> String { + String::new() + } + fn __anchor_private_insert_idl_defined(_a: &mut HashMap) {} + fn __anchor_private_gen_idl_type() -> Option { + None + } +} + #[cfg(test)] mod test { use crate::endpoints::wormhole::messages::WormholeEndpoint; From e2d7a33d8543700ff8a9435f7954c0c63c8b18d4 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 21 Feb 2024 14:03:15 -0500 Subject: [PATCH 69/90] solana: drop generics from typescript idl type --- solana/ts/sdk/index.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index e7debfbf9..c399b07bf 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -12,7 +12,7 @@ import { type TransactionSignature } from '@solana/web3.js' import { Keccak } from 'sha3' -import { type ExampleNativeTokenTransfers } from '../../target/types/example_native_token_transfers' +import { type ExampleNativeTokenTransfers as Idl } from '../../target/types/example_native_token_transfers' import { ManagerMessage } from './payloads/common' import { NativeTokenTransfer } from './payloads/transfers' import { WormholeEndpointMessage } from './payloads/wormhole' @@ -24,6 +24,18 @@ export { WormholeEndpointMessage } from './payloads/wormhole' export * from './utils/wormhole' +// This is a workaround for the fact that the anchor idl doesn't support generics +// yet. This type is used to remove the generics from the idl types. +type OmitGenerics = { + [P in keyof T]: T[P] extends Record<"generics", any> + ? never + : T[P] extends object + ? OmitGenerics + : T[P]; +}; + +export type ExampleNativeTokenTransfers = OmitGenerics + export type Config = IdlAccounts['config'] export type InboxItem = IdlAccounts['inboxItem'] From 9be6e5e6767e5a9ef1dce2de1505b556bf439bf7 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Wed, 21 Feb 2024 14:12:45 -0500 Subject: [PATCH 70/90] solana: solana: fix anchor test --- solana/Anchor.toml | 4 ++-- solana/tests/example-native-token-transfer.ts | 17 ++++++------- solana/ts/sdk/index.ts | 24 +++++++++++++------ solana/ts/sdk/utils/bpfLoaderUpgradeable.ts | 12 ++++++++++ solana/ts/sdk/utils/index.ts | 1 + 5 files changed, 41 insertions(+), 17 deletions(-) create mode 100644 solana/ts/sdk/utils/bpfLoaderUpgradeable.ts create mode 100644 solana/ts/sdk/utils/index.ts diff --git a/solana/Anchor.toml b/solana/Anchor.toml index 2115314be..141b37cea 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -5,7 +5,7 @@ seeds = false skip-lint = false [programs.localnet] -solana_multi_endpoint = "F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV" +example_native_token_transfers = "F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV" wormhole_governance = "7kK9JyavhgE5G8oErMziHeBzZiAu3J64oLMbNf8FpG4S" [registry] @@ -21,7 +21,7 @@ test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" [test] startup_wait = 5000 shutdown_wait = 2000 -upgradeable = false +upgradeable = true [[test.genesis]] address = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth" diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index 7912c310a..2852c5403 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -1,11 +1,12 @@ import * as anchor from '@coral-xyz/anchor' import { BN, type Program } from '@coral-xyz/anchor' import * as spl from '@solana/spl-token' -import { type ExampleNativeTokenTransfers } from '../target/types/example_native_token_transfers' +import { type ExampleNativeTokenTransfers } from '../ts/sdk' import { PostedMessageData } from '@certusone/wormhole-sdk/lib/cjs/solana/wormhole' import { expect } from 'chai' import { toChainId } from '@certusone/wormhole-sdk' import { MockEmitter, MockGuardians } from '@certusone/wormhole-sdk/lib/cjs/mock' +import * as fs from "fs"; import { type EndpointMessage, ManagerMessage, NativeTokenTransfer, NormalizedAmount, postVaa, WormholeEndpointMessage, NTT } from '../ts/sdk' @@ -15,9 +16,11 @@ describe('example-native-token-transfers', () => { // Configure the client to use the local cluster. anchor.setProvider(anchor.AnchorProvider.env()) + const payerSecretKey = Uint8Array.from(JSON.parse(fs.readFileSync(`${__dirname}/../keys/test.json`, { encoding: "utf-8" }))); + const payer = anchor.web3.Keypair.fromSecretKey(payerSecretKey); + const program = anchor.workspace.ExampleNativeTokenTransfers as Program const owner = anchor.web3.Keypair.generate() - const payer = anchor.web3.Keypair.generate() const ntt = new NTT({ program, wormholeId: 'worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth' @@ -30,8 +33,6 @@ describe('example-native-token-transfers', () => { before(async () => { // airdrop some tokens to payer - const signature = await program.provider.connection.requestAirdrop(payer.publicKey, 1000000000) - await program.provider.connection.confirmTransaction(signature) mint = await spl.createMint( program.provider.connection, payer, @@ -57,7 +58,7 @@ describe('example-native-token-transfers', () => { await ntt.initialize({ payer, - owner, + owner: payer, chain: 'solana', mint, outboundLimit: new BN(1000000), @@ -66,20 +67,20 @@ describe('example-native-token-transfers', () => { await ntt.registerEndpoint({ payer, - owner, + owner: payer, endpoint: ntt.program.programId }) await ntt.setWormholeEndpointSibling({ payer, - owner, + owner: payer, chain: 'ethereum', address: Buffer.from('endpoint'.padStart(32, '\0')), }) await ntt.setSibling({ payer, - owner, + owner: payer, chain: 'ethereum', address: Buffer.from('manager'.padStart(32, '\0')), limit: new BN(1000000) diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index c399b07bf..72084212c 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -16,6 +16,8 @@ import { type ExampleNativeTokenTransfers as Idl } from '../../target/types/exam import { ManagerMessage } from './payloads/common' import { NativeTokenTransfer } from './payloads/transfers' import { WormholeEndpointMessage } from './payloads/wormhole' +import { BPF_LOADER_UPGRADEABLE_PROGRAM_ID, programDataAddress } from './utils' +import * as splToken from '@solana/spl-token'; export { NormalizedAmount } from './normalized_amount' export { EndpointMessage, ManagerMessage } from './payloads/common' @@ -162,14 +164,16 @@ export class NTT { .initialize({ chainId, limit: args.outboundLimit, mode }) .accounts({ payer: args.payer.publicKey, - owner: args.owner.publicKey, + deployer: args.owner.publicKey, + programData: programDataAddress(this.program.programId), config: this.configAccountAddress(), mint: args.mint, seq: this.sequenceTrackerAccountAddress(), rateLimit: this.outboxRateLimitAccountAddress(), tokenProgram, tokenAuthority: this.tokenAuthorityAddress(), - custody: await this.custodyAccountAddress(args.mint) + custody: await this.custodyAccountAddress(args.mint), + bpfLoaderUpgradeableProgram: BPF_LOADER_UPGRADEABLE_PROGRAM_ID, }) .signers([args.payer, args.owner]) .rpc() @@ -215,9 +219,14 @@ export class NTT { const signers = [args.payer, args.fromAuthority, outboxItem] + const approveIx = splToken.createApproveInstruction( + args.from, + this.tokenAuthorityAddress(), + args.fromAuthority.publicKey, + BigInt(args.amount.toString()) + ); const tx = new Transaction() - tx.add(transferIx) - tx.add(releaseIx) + tx.add(approveIx, transferIx, releaseIx) await this.sendAndConfirmTransaction(tx, signers) return outboxItem.publicKey @@ -271,10 +280,11 @@ export class NTT { config: { config: this.configAccountAddress() }, mint, from: args.from, - fromAuthority: args.fromAuthority, + sender: args.fromAuthority, seq: this.sequenceTrackerAccountAddress(), outboxItem: args.outboxItem, outboxRateLimit: this.outboxRateLimitAccountAddress(), + tokenAuthority: this.tokenAuthorityAddress(), }, inboxRateLimit: this.inboxRateLimitAccountAddress(args.recipientChain) }) @@ -318,14 +328,14 @@ export class NTT { config: { config: this.configAccountAddress() }, mint, from: args.from, - fromAuthority: args.fromAuthority, + sender: args.fromAuthority, tokenProgram: await this.tokenProgram(config), seq: this.sequenceTrackerAccountAddress(), outboxItem: args.outboxItem, outboxRateLimit: this.outboxRateLimitAccountAddress(), + tokenAuthority: this.tokenAuthorityAddress(), }, inboxRateLimit: this.inboxRateLimitAccountAddress(args.recipientChain), - tokenAuthority: this.tokenAuthorityAddress(), custody: await this.custodyAccountAddress(config) }) .instruction() diff --git a/solana/ts/sdk/utils/bpfLoaderUpgradeable.ts b/solana/ts/sdk/utils/bpfLoaderUpgradeable.ts new file mode 100644 index 000000000..d0d14b429 --- /dev/null +++ b/solana/ts/sdk/utils/bpfLoaderUpgradeable.ts @@ -0,0 +1,12 @@ +import { PublicKey } from "@solana/web3.js"; + +export const BPF_LOADER_UPGRADEABLE_PROGRAM_ID = new PublicKey( + "BPFLoaderUpgradeab1e11111111111111111111111", +); + +export function programDataAddress(programId: PublicKey) { + return PublicKey.findProgramAddressSync( + [programId.toBuffer()], + BPF_LOADER_UPGRADEABLE_PROGRAM_ID, + )[0]; +} \ No newline at end of file diff --git a/solana/ts/sdk/utils/index.ts b/solana/ts/sdk/utils/index.ts new file mode 100644 index 000000000..8cde160fe --- /dev/null +++ b/solana/ts/sdk/utils/index.ts @@ -0,0 +1 @@ +export * from "./bpfLoaderUpgradeable"; \ No newline at end of file From 4ec60eaf09b78448cc0a1a2e45a8e110ecf0d03b Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 21 Feb 2024 14:45:24 -0500 Subject: [PATCH 71/90] solana: update inbox item PDA derivation the chain id and message are now hashed together --- .../src/instructions/redeem.rs | 5 +++-- .../example-native-token-transfers/src/messages.rs | 8 +++++--- .../example-native-token-transfers/tests/sdk/accounts.rs | 2 +- solana/ts/sdk/index.ts | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index beee6d537..d36e3b981 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -56,8 +56,9 @@ pub struct Redeem<'info> { space = 8 + InboxItem::INIT_SPACE, seeds = [ InboxItem::SEED_PREFIX, - endpoint_message.from_chain.id.to_be_bytes().as_ref(), - endpoint_message.message.manager_payload.keccak256().as_ref(), + endpoint_message.message.manager_payload.keccak256( + endpoint_message.from_chain + ).as_ref(), ], bump, )] diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 4b5a99c94..218d5643c 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -17,9 +17,11 @@ pub struct ManagerMessage { } impl ManagerMessage { - pub fn keccak256(&self) -> Hash { - let payload = TypePrefixedPayload::to_vec_payload(self); - solana_program::keccak::hash(&payload) + pub fn keccak256(&self, chain_id: ChainId) -> Hash { + let mut bytes: Vec = Vec::new(); + bytes.extend_from_slice(&chain_id.id.to_be_bytes()); + bytes.extend_from_slice(&TypePrefixedPayload::to_vec_payload(self)); + solana_program::keccak::hash(&bytes) } } diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 70133913e..1310f9058 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -101,12 +101,12 @@ impl NTT { manager_message: ManagerMessage, ) -> Pubkey { let mut hasher = Keccak256::new(); + hasher.update(&chain.to_be_bytes()); hasher.update(&TypePrefixedPayload::to_vec_payload(&manager_message)); let (inbox_item, _) = Pubkey::find_program_address( &[ InboxItem::SEED_PREFIX, - &chain.to_be_bytes(), &hasher.finalize(), ], &self.program, diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 72084212c..343399865 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -94,12 +94,12 @@ export class NTT { const chainId = coalesceChainId(chain) const serialized = ManagerMessage.serialize(managerMessage, NativeTokenTransfer.serialize) const hasher = new Keccak(256) + hasher.update(new BN(chainId).toBuffer('be', 2)) hasher.update(serialized) const hash = hasher.digest('hex') return this.derive_pda( [ Buffer.from('inbox_item'), - new BN(chainId).toBuffer('be', 2), Buffer.from(hash, 'hex') ]) } From 37917c6d86b9059308c28fcefa936f2230a1cbcd Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 21 Feb 2024 14:58:14 -0500 Subject: [PATCH 72/90] solana: add endpoint_payload to EndpointMessage --- .../src/instructions/release_outbound.rs | 1 + .../src/messages.rs | 30 +++++++++++++++---- .../tests/cancel_flow.rs | 2 +- .../tests/sdk/accounts.rs | 7 ++--- .../tests/transfer.rs | 3 +- solana/tests/example-native-token-transfer.ts | 5 ++-- solana/ts/sdk/payloads/common.ts | 12 ++++++-- 7 files changed, 43 insertions(+), 17 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs index b32ec8830..f62e374f6 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs @@ -103,6 +103,7 @@ pub fn release_outbound(ctx: Context, args: ReleaseOutboundArgs to_chain: accs.outbox_item.recipient_chain, }, }, + vec![], ); if accs.wormhole_bridge.fee() > 0 { diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 218d5643c..21645e6ed 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -182,6 +182,7 @@ pub struct EndpointMessage, // TODO: check sibling registration at the manager level pub message_data: EndpointMessageData, + pub endpoint_payload: Vec, } impl std::ops::Deref @@ -244,6 +245,7 @@ where source_manager: self.source_manager, manager_payload: self.manager_payload.clone(), }, + endpoint_payload: self.endpoint_payload.clone(), } } } @@ -252,13 +254,18 @@ impl EndpointMessage where A: AnchorDeserialize + AnchorSerialize + Space + Clone, { - pub fn new(source_manager: [u8; 32], manager_payload: ManagerMessage) -> Self { + pub fn new( + source_manager: [u8; 32], + manager_payload: ManagerMessage, + endpoint_payload: Vec, + ) -> Self { Self { _phantom: PhantomData, message_data: EndpointMessageData { source_manager, manager_payload, }, + endpoint_payload, } } } @@ -294,8 +301,15 @@ where // consumes the expected amount of bytes let _manager_payload_len: u16 = Readable::read(reader)?; let manager_payload = ManagerMessage::read(reader)?; - - Ok(EndpointMessage::new(source_manager, manager_payload)) + let endpoint_payload_len: u16 = Readable::read(reader)?; + let mut endpoint_payload = vec![0; endpoint_payload_len as usize]; + reader.read_exact(&mut endpoint_payload)?; + + Ok(EndpointMessage::new( + source_manager, + manager_payload, + endpoint_payload, + )) } } @@ -321,6 +335,7 @@ where source_manager, manager_payload, }, + endpoint_payload, } = self; E::PREFIX.write(writer)?; @@ -331,7 +346,11 @@ where // a better API would be // foo.write_with_prefix_be::(writer) // which writes the length as a big endian u16. - manager_payload.write(writer) + manager_payload.write(writer)?; + let len: u16 = u16::try_from(endpoint_payload.len()).expect("u16 overflow"); + len.write(writer)?; + writer.write_all(endpoint_payload)?; + Ok(()) } } @@ -376,7 +395,7 @@ mod test { // #[test] fn test_deserialize_endpoint_message() { - let data = hex::decode("9945ff10042942fafabe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe000000000000000000000000000000000000000000000000000000000011").unwrap(); + let data = hex::decode("9945ff10042942fafabe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe0000000000000000000000000000000000000000000000000000000000110000").unwrap(); let mut vec = &data[..]; let message: EndpointMessage = TypePrefixedPayload::read_payload(&mut vec).unwrap(); @@ -411,6 +430,7 @@ mod test { }, }, }, + endpoint_payload: vec![], }; assert_eq!(message, expected); assert_eq!(vec.len(), 0); diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 32080c29b..123c8b48e 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -116,7 +116,7 @@ async fn post_transfer_vaa( }, }; let endpoint_message: EndpointMessage = - EndpointMessage::new(OTHER_MANAGER, manager_message.clone()); + EndpointMessage::new(OTHER_MANAGER, manager_message.clone(), vec![]); let vaa = Vaa { version: 1, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 1310f9058..20c6190a3 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -101,14 +101,11 @@ impl NTT { manager_message: ManagerMessage, ) -> Pubkey { let mut hasher = Keccak256::new(); - hasher.update(&chain.to_be_bytes()); + hasher.update(chain.to_be_bytes()); hasher.update(&TypePrefixedPayload::to_vec_payload(&manager_message)); let (inbox_item, _) = Pubkey::find_program_address( - &[ - InboxItem::SEED_PREFIX, - &hasher.finalize(), - ], + &[InboxItem::SEED_PREFIX, &hasher.finalize()], &self.program, ); inbox_item diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 5a60229a1..1ee45d236 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -185,7 +185,8 @@ async fn test_transfer(ctx: &mut ProgramTestContext, test_data: &TestData, mode: to: [1u8; 32], to_chain: ChainId { id: 2 }, } - } + }, + vec![] ) ); diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index 2852c5403..ceb05843b 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -159,8 +159,9 @@ describe('example-native-token-transfers', () => { new NormalizedAmount(BigInt(10000), 8), toChainId('solana'), user.publicKey.toBuffer() - ) - ) + ), + ), + endpointPayload: Buffer.alloc(0) } const serialized = WormholeEndpointMessage.serialize(sendingEndpointMessage, a => ManagerMessage.serialize(a, NativeTokenTransfer.serialize)) diff --git a/solana/ts/sdk/payloads/common.ts b/solana/ts/sdk/payloads/common.ts index 841fb9ee0..048b17c78 100644 --- a/solana/ts/sdk/payloads/common.ts +++ b/solana/ts/sdk/payloads/common.ts @@ -5,10 +5,12 @@ export class EndpointMessage { static prefix: Buffer sourceManager: Buffer managerPayload: ManagerMessage + endpointPayload: Buffer - constructor(sourceManager: Buffer, managerPayload: ManagerMessage) { + constructor(sourceManager: Buffer, managerPayload: ManagerMessage, endpointPayload: Buffer) { this.sourceManager = sourceManager this.managerPayload = managerPayload + this.endpointPayload = endpointPayload } static deserialize(data: Buffer, deserializer: (data: Buffer) => ManagerMessage): EndpointMessage { @@ -22,13 +24,17 @@ export class EndpointMessage { const sourceManager = data.subarray(4, 36) const managerPayloadLen = data.readUInt16BE(36) const managerPayload = deserializer(data.subarray(38, 38 + managerPayloadLen)) - return new EndpointMessage(sourceManager, managerPayload) + const endpointPayloadLen = data.readUInt16BE(38 + managerPayloadLen) + const endpointPayload = data.subarray(40 + managerPayloadLen, 40 + managerPayloadLen + endpointPayloadLen) + return new EndpointMessage(sourceManager, managerPayload, endpointPayload) } static serialize(msg: EndpointMessage, serializer: (payload: ManagerMessage) => Buffer): Buffer { const payload = serializer(msg.managerPayload) assert(msg.sourceManager.length == 32, 'sourceManager must be 32 bytes') - const buffer = Buffer.concat([this.prefix, msg.sourceManager, new BN(payload.length).toBuffer('be', 2), payload]) + const payloadLen = new BN(payload.length).toBuffer('be', 2) + const endpointPayloadLen = new BN(msg.endpointPayload.length).toBuffer('be', 2) + const buffer = Buffer.concat([this.prefix, msg.sourceManager, payloadLen, payload, endpointPayloadLen, msg.endpointPayload]) return buffer } } From 7679935ff83da2aed7fb56ba4861cda2e86c7649 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Wed, 21 Feb 2024 15:35:58 -0500 Subject: [PATCH 73/90] rename workflows --- .github/workflows/{test.yml => evm.yml} | 4 ++-- .github/workflows/{build.yml => solana.yml} | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename .github/workflows/{test.yml => evm.yml} (94%) rename .github/workflows/{build.yml => solana.yml} (99%) diff --git a/.github/workflows/test.yml b/.github/workflows/evm.yml similarity index 94% rename from .github/workflows/test.yml rename to .github/workflows/evm.yml index 2cc58dbc7..be3fc52f9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/evm.yml @@ -1,4 +1,4 @@ -name: test +name: EVM CI on: workflow_dispatch: @@ -15,7 +15,7 @@ jobs: strategy: fail-fast: true - name: Foundry project + name: forge test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 diff --git a/.github/workflows/build.yml b/.github/workflows/solana.yml similarity index 99% rename from .github/workflows/build.yml rename to .github/workflows/solana.yml index 6e59eeecf..9ad600f8b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/solana.yml @@ -1,4 +1,4 @@ -name: Build +name: Solana CI on: workflow_dispatch: pull_request: From 00d66cf22651ef837e2751f8dc743d26a47fd2ce Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Wed, 21 Feb 2024 15:39:54 -0500 Subject: [PATCH 74/90] test anchor --- .github/workflows/solana.yml | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/.github/workflows/solana.yml b/.github/workflows/solana.yml index 9ad600f8b..2f40bf3fc 100644 --- a/.github/workflows/solana.yml +++ b/.github/workflows/solana.yml @@ -7,7 +7,8 @@ on: - main - dev jobs: - solana: + solana-sbf: + name: Solana Cargo SBF runs-on: ubuntu-20.04 env: RUSTFLAGS: -Dwarnings @@ -90,7 +91,7 @@ jobs: sh -c "$(curl -sSfL https://release.solana.com/v${SOLANA_VERSION}/install)" ~/.local/share/solana/install/active_release/bin/sdk/sbf/scripts/install.sh - - name: Run unit tests + - name: cargo build-sbf && cargo test-sbf env: RUST_BACKTRACE: "1" run: | @@ -110,3 +111,19 @@ jobs: for p in "${BPF_PACKAGES[@]}"; do cargo test-sbf --manifest-path "${p}" done + anchor-test: + name: Anchor Test + runs-on: ubuntu-latest + # Anchor Docker image: https://www.anchor-lang.com/docs/verifiable-builds#images + container: backpackapp/build:v0.29.0 + steps: + - uses: actions/checkout@v4 + - name: Set default Rust toolchain + run: rustup default stable + working-directory: ./solana + - name: yarn + run: yarn + working-directory: ./solana + - name: anchor test --arch sbf + run: anchor test --arch sbf + working-directory: ./solana \ No newline at end of file From 08f8e15bf34e0d33f9edba75f2c0281c96ca683c Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Wed, 21 Feb 2024 18:31:42 -0500 Subject: [PATCH 75/90] solana: specify toolchain --- solana/Anchor.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/solana/Anchor.toml b/solana/Anchor.toml index 141b37cea..b1c06ea55 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -1,4 +1,6 @@ [toolchain] +anchor_version = "0.29.0" # CLI +solana_version = "1.17.2" [features] seeds = false From d9e688c40cb8cae134050c481afea02c970a789e Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 21 Feb 2024 19:46:17 -0500 Subject: [PATCH 76/90] run make target in anchor test in CI --- .github/workflows/solana.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/solana.yml b/.github/workflows/solana.yml index 2f40bf3fc..93d181242 100644 --- a/.github/workflows/solana.yml +++ b/.github/workflows/solana.yml @@ -125,5 +125,5 @@ jobs: run: yarn working-directory: ./solana - name: anchor test --arch sbf - run: anchor test --arch sbf - working-directory: ./solana \ No newline at end of file + run: make test-anchor + working-directory: ./solana From 4a0ab6612220abeda9593c019a801aa6fe0a2950 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Wed, 21 Feb 2024 19:49:23 -0500 Subject: [PATCH 77/90] fix make target name --- .github/workflows/solana.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/solana.yml b/.github/workflows/solana.yml index 93d181242..c596fe040 100644 --- a/.github/workflows/solana.yml +++ b/.github/workflows/solana.yml @@ -125,5 +125,5 @@ jobs: run: yarn working-directory: ./solana - name: anchor test --arch sbf - run: make test-anchor + run: make anchor-test working-directory: ./solana From 7681c8633041aa9ed28ff1505750c077ed2c59a8 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Thu, 22 Feb 2024 09:26:58 -0500 Subject: [PATCH 78/90] solana: hello npm --- .github/workflows/solana.yml | 3 - solana/.gitignore | 1 - solana/Anchor.toml | 3 - solana/Makefile | 10 +- solana/yarn.lock | 5117 ---------------------------------- 5 files changed, 9 insertions(+), 5125 deletions(-) delete mode 100644 solana/yarn.lock diff --git a/.github/workflows/solana.yml b/.github/workflows/solana.yml index c596fe040..c1f862847 100644 --- a/.github/workflows/solana.yml +++ b/.github/workflows/solana.yml @@ -121,9 +121,6 @@ jobs: - name: Set default Rust toolchain run: rustup default stable working-directory: ./solana - - name: yarn - run: yarn - working-directory: ./solana - name: anchor test --arch sbf run: make anchor-test working-directory: ./solana diff --git a/solana/.gitignore b/solana/.gitignore index 8d401163f..d243ecc13 100644 --- a/solana/.gitignore +++ b/solana/.gitignore @@ -5,4 +5,3 @@ target **/*.rs.bk node_modules test-ledger -.yarn diff --git a/solana/Anchor.toml b/solana/Anchor.toml index b1c06ea55..72dd44a42 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -30,10 +30,7 @@ address = "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth" program = "programs/example-native-token-transfers/tests/fixtures/mainnet_core_bridge.so" [test.validator] -bind_address = "0.0.0.0" url = "https://api.mainnet-beta.solana.com" -ledger = ".anchor/test-ledger" -rpc_port = 8899 ticks_per_slot = 16 [[test.validator.account]] diff --git a/solana/Makefile b/solana/Makefile index 58d2ab3f7..5f9baca20 100644 --- a/solana/Makefile +++ b/solana/Makefile @@ -12,5 +12,13 @@ target/idl/example_native_token_transfers.json: _anchor-build: @anchor build -anchor-test: build target/idl/example_native_token_transfers.json +anchor-test: node_modules build target/idl/example_native_token_transfers.json anchor test --skip-build + +node_modules: + npm ci + +.PHONY: clean +clean: + anchor clean + rm -rf .anchor node_modules \ No newline at end of file diff --git a/solana/yarn.lock b/solana/yarn.lock deleted file mode 100644 index a3c5451df..000000000 --- a/solana/yarn.lock +++ /dev/null @@ -1,5117 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@aashutoshrathi/word-wrap@^1.2.3": - version "1.2.6" - resolved "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz" - integrity sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA== - -"@apollo/client@^3.5.8": - version "3.9.4" - resolved "https://registry.npmjs.org/@apollo/client/-/client-3.9.4.tgz" - integrity sha512-Ip6dxjshDT2Dp6foLASTnKBW45Fytew/5JZutZwgc78hVrrGpO9UtZA9xteHXYdap0wIgCxCfeIQwbSu1ZdQpw== - dependencies: - "@graphql-typed-document-node/core" "^3.1.1" - "@wry/caches" "^1.0.0" - "@wry/equality" "^0.5.6" - "@wry/trie" "^0.5.0" - graphql-tag "^2.12.6" - hoist-non-react-statics "^3.3.2" - optimism "^0.18.0" - prop-types "^15.7.2" - rehackt "0.0.4" - response-iterator "^0.2.6" - symbol-observable "^4.0.0" - ts-invariant "^0.10.3" - tslib "^2.3.0" - zen-observable-ts "^1.2.5" - -"@babel/runtime@^7.17.2", "@babel/runtime@^7.23.4": - version "7.23.9" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz" - integrity sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw== - dependencies: - regenerator-runtime "^0.14.0" - -"@babel/runtime@7.20.13": - version "7.20.13" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.20.13.tgz" - integrity sha512-gt3PKXs0DBoL9xCvOIIZ2NEqAGZqHjAnmVbfQtB620V0uReIQutpel14KcneZuer7UioY8ALKZ7iocavvzTNFA== - dependencies: - regenerator-runtime "^0.13.11" - -"@certusone/wormhole-sdk-proto-web@0.0.7": - version "0.0.7" - resolved "https://registry.npmjs.org/@certusone/wormhole-sdk-proto-web/-/wormhole-sdk-proto-web-0.0.7.tgz" - integrity sha512-GCe1/bcqMS0Mt+hsWp4SE4NLL59pWmK0lhQXO0oqAKl0G9AuuTdudySMDF/sLc7z5H2w34bSuSrIEKvPuuSC+w== - dependencies: - "@improbable-eng/grpc-web" "^0.15.0" - protobufjs "^7.0.0" - rxjs "^7.5.6" - -"@certusone/wormhole-sdk-wasm@^0.0.1": - version "0.0.1" - resolved "https://registry.npmjs.org/@certusone/wormhole-sdk-wasm/-/wormhole-sdk-wasm-0.0.1.tgz" - integrity sha512-LdIwLhOyr4pPs2jqYubqC7d4UkqYBX0EG/ppspQlW3qlVE0LZRMrH6oVzzLMyHtV0Rw7O9sIKzORW/T3mrJv2w== - dependencies: - "@types/long" "^4.0.2" - "@types/node" "^18.0.3" - -"@certusone/wormhole-sdk@^0.10.10": - version "0.10.10" - resolved "https://registry.npmjs.org/@certusone/wormhole-sdk/-/wormhole-sdk-0.10.10.tgz" - integrity sha512-2pYQ2/+cSfh/LVtOTXQDrTeZdXHgzq/hjkTevzW5+rEqITE54qUlnMhcVtSJQe+Yvgg3awrP2mIfDW3nvwPIPA== - dependencies: - "@certusone/wormhole-sdk-proto-web" "0.0.7" - "@certusone/wormhole-sdk-wasm" "^0.0.1" - "@coral-xyz/borsh" "0.2.6" - "@mysten/sui.js" "0.32.2" - "@project-serum/anchor" "^0.25.0" - "@solana/spl-token" "^0.3.5" - "@solana/web3.js" "^1.66.2" - "@terra-money/terra.js" "3.1.9" - "@xpla/xpla.js" "^0.2.1" - algosdk "^2.4.0" - aptos "1.5.0" - axios "^0.24.0" - bech32 "^2.0.0" - binary-parser "^2.2.1" - bs58 "^4.0.1" - elliptic "^6.5.4" - js-base64 "^3.6.1" - near-api-js "^1.0.0" - optionalDependencies: - "@injectivelabs/networks" "1.10.12" - "@injectivelabs/sdk-ts" "1.10.72" - "@injectivelabs/utils" "1.10.12" - -"@classic-terra/terra.proto@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@classic-terra/terra.proto/-/terra.proto-1.1.0.tgz" - integrity sha512-bYhQG5LUaGF0KPRY9hYT/HEcd1QExZPQd6zLV/rQkCe/eDxfwFRLzZHpaaAdfWoAAZjsRWqJbUCqCg7gXBbJpw== - dependencies: - "@improbable-eng/grpc-web" "^0.14.1" - google-protobuf "^3.17.3" - long "^4.0.0" - protobufjs "~6.11.2" - -"@confio/ics23@^0.6.8": - version "0.6.8" - resolved "https://registry.npmjs.org/@confio/ics23/-/ics23-0.6.8.tgz" - integrity sha512-wB6uo+3A50m0sW/EWcU64xpV/8wShZ6bMTa7pF8eYsTrSkQA7oLUIJcs/wb8g4y2Oyq701BaGiO6n/ak5WXO1w== - dependencies: - "@noble/hashes" "^1.0.0" - protobufjs "^6.8.8" - -"@coral-xyz/anchor@^0.29.0": - version "0.29.0" - resolved "https://registry.npmjs.org/@coral-xyz/anchor/-/anchor-0.29.0.tgz" - integrity sha512-eny6QNG0WOwqV0zQ7cs/b1tIuzZGmP7U7EcH+ogt4Gdbl8HDmIYVMh/9aTmYZPaFWjtUaI8qSn73uYEXWfATdA== - dependencies: - "@coral-xyz/borsh" "^0.29.0" - "@noble/hashes" "^1.3.1" - "@solana/web3.js" "^1.68.0" - bn.js "^5.1.2" - bs58 "^4.0.1" - buffer-layout "^1.2.2" - camelcase "^6.3.0" - cross-fetch "^3.1.5" - crypto-hash "^1.3.0" - eventemitter3 "^4.0.7" - pako "^2.0.3" - snake-case "^3.0.4" - superstruct "^0.15.4" - toml "^3.0.0" - -"@coral-xyz/borsh@^0.29.0": - version "0.29.0" - resolved "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.29.0.tgz" - integrity sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ== - dependencies: - bn.js "^5.1.2" - buffer-layout "^1.2.0" - -"@coral-xyz/borsh@0.2.6": - version "0.2.6" - resolved "https://registry.npmjs.org/@coral-xyz/borsh/-/borsh-0.2.6.tgz" - integrity sha512-y6nmHw1bFcJib7sMHsQPpC8r47xhqDZVvhUdna7NUPzpSbOZG6f46N21+aXsQ2w/tG8Ggls488J/ZmwbgVmyjg== - dependencies: - bn.js "^5.1.2" - buffer-layout "^1.2.0" - -"@cosmjs/amino@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/amino/-/amino-0.30.1.tgz" - integrity sha512-yNHnzmvAlkETDYIpeCTdVqgvrdt1qgkOXwuRVi8s27UKI5hfqyE9fJ/fuunXE6ZZPnKkjIecDznmuUOMrMvw4w== - dependencies: - "@cosmjs/crypto" "^0.30.1" - "@cosmjs/encoding" "^0.30.1" - "@cosmjs/math" "^0.30.1" - "@cosmjs/utils" "^0.30.1" - -"@cosmjs/crypto@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/crypto/-/crypto-0.30.1.tgz" - integrity sha512-rAljUlake3MSXs9xAm87mu34GfBLN0h/1uPPV6jEwClWjNkAMotzjC0ab9MARy5FFAvYHL3lWb57bhkbt2GtzQ== - dependencies: - "@cosmjs/encoding" "^0.30.1" - "@cosmjs/math" "^0.30.1" - "@cosmjs/utils" "^0.30.1" - "@noble/hashes" "^1" - bn.js "^5.2.0" - elliptic "^6.5.4" - libsodium-wrappers "^0.7.6" - -"@cosmjs/encoding@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/encoding/-/encoding-0.30.1.tgz" - integrity sha512-rXmrTbgqwihORwJ3xYhIgQFfMSrwLu1s43RIK9I8EBudPx3KmnmyAKzMOVsRDo9edLFNuZ9GIvysUCwQfq3WlQ== - dependencies: - base64-js "^1.3.0" - bech32 "^1.1.4" - readonly-date "^1.0.0" - -"@cosmjs/json-rpc@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/json-rpc/-/json-rpc-0.30.1.tgz" - integrity sha512-pitfC/2YN9t+kXZCbNuyrZ6M8abnCC2n62m+JtU9vQUfaEtVsgy+1Fk4TRQ175+pIWSdBMFi2wT8FWVEE4RhxQ== - dependencies: - "@cosmjs/stream" "^0.30.1" - xstream "^11.14.0" - -"@cosmjs/math@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/math/-/math-0.30.1.tgz" - integrity sha512-yaoeI23pin9ZiPHIisa6qqLngfnBR/25tSaWpkTm8Cy10MX70UF5oN4+/t1heLaM6SSmRrhk3psRkV4+7mH51Q== - dependencies: - bn.js "^5.2.0" - -"@cosmjs/proto-signing@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/proto-signing/-/proto-signing-0.30.1.tgz" - integrity sha512-tXh8pPYXV4aiJVhTKHGyeZekjj+K9s2KKojMB93Gcob2DxUjfKapFYBMJSgfKPuWUPEmyr8Q9km2hplI38ILgQ== - dependencies: - "@cosmjs/amino" "^0.30.1" - "@cosmjs/crypto" "^0.30.1" - "@cosmjs/encoding" "^0.30.1" - "@cosmjs/math" "^0.30.1" - "@cosmjs/utils" "^0.30.1" - cosmjs-types "^0.7.1" - long "^4.0.0" - -"@cosmjs/socket@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/socket/-/socket-0.30.1.tgz" - integrity sha512-r6MpDL+9N+qOS/D5VaxnPaMJ3flwQ36G+vPvYJsXArj93BjgyFB7BwWwXCQDzZ+23cfChPUfhbINOenr8N2Kow== - dependencies: - "@cosmjs/stream" "^0.30.1" - isomorphic-ws "^4.0.1" - ws "^7" - xstream "^11.14.0" - -"@cosmjs/stargate@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/stargate/-/stargate-0.30.1.tgz" - integrity sha512-RdbYKZCGOH8gWebO7r6WvNnQMxHrNXInY/gPHPzMjbQF6UatA6fNM2G2tdgS5j5u7FTqlCI10stNXrknaNdzog== - dependencies: - "@confio/ics23" "^0.6.8" - "@cosmjs/amino" "^0.30.1" - "@cosmjs/encoding" "^0.30.1" - "@cosmjs/math" "^0.30.1" - "@cosmjs/proto-signing" "^0.30.1" - "@cosmjs/stream" "^0.30.1" - "@cosmjs/tendermint-rpc" "^0.30.1" - "@cosmjs/utils" "^0.30.1" - cosmjs-types "^0.7.1" - long "^4.0.0" - protobufjs "~6.11.3" - xstream "^11.14.0" - -"@cosmjs/stream@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/stream/-/stream-0.30.1.tgz" - integrity sha512-Fg0pWz1zXQdoxQZpdHRMGvUH5RqS6tPv+j9Eh7Q953UjMlrwZVo0YFLC8OTf/HKVf10E4i0u6aM8D69Q6cNkgQ== - dependencies: - xstream "^11.14.0" - -"@cosmjs/tendermint-rpc@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/tendermint-rpc/-/tendermint-rpc-0.30.1.tgz" - integrity sha512-Z3nCwhXSbPZJ++v85zHObeUggrEHVfm1u18ZRwXxFE9ZMl5mXTybnwYhczuYOl7KRskgwlB+rID0WYACxj4wdQ== - dependencies: - "@cosmjs/crypto" "^0.30.1" - "@cosmjs/encoding" "^0.30.1" - "@cosmjs/json-rpc" "^0.30.1" - "@cosmjs/math" "^0.30.1" - "@cosmjs/socket" "^0.30.1" - "@cosmjs/stream" "^0.30.1" - "@cosmjs/utils" "^0.30.1" - axios "^0.21.2" - readonly-date "^1.0.0" - xstream "^11.14.0" - -"@cosmjs/utils@^0.30.1": - version "0.30.1" - resolved "https://registry.npmjs.org/@cosmjs/utils/-/utils-0.30.1.tgz" - integrity sha512-KvvX58MGMWh7xA+N+deCfunkA/ZNDvFLw4YbOmX3f/XBIkqrVY7qlotfy2aNb1kgp6h4B6Yc8YawJPDTfvWX7g== - -"@eslint-community/eslint-utils@^4.1.2", "@eslint-community/eslint-utils@^4.2.0", "@eslint-community/eslint-utils@^4.4.0": - version "4.4.0" - resolved "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== - dependencies: - eslint-visitor-keys "^3.3.0" - -"@eslint-community/regexpp@^4.5.1", "@eslint-community/regexpp@^4.6.0", "@eslint-community/regexpp@^4.6.1": - version "4.10.0" - resolved "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz" - integrity sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA== - -"@eslint/eslintrc@^2.1.4": - version "2.1.4" - resolved "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz" - integrity sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ== - dependencies: - ajv "^6.12.4" - debug "^4.3.2" - espree "^9.6.0" - globals "^13.19.0" - ignore "^5.2.0" - import-fresh "^3.2.1" - js-yaml "^4.1.0" - minimatch "^3.1.2" - strip-json-comments "^3.1.1" - -"@eslint/js@8.56.0": - version "8.56.0" - resolved "https://registry.npmjs.org/@eslint/js/-/js-8.56.0.tgz" - integrity sha512-gMsVel9D7f2HLkBma9VbtzZRehRogVRfbr++f06nL2vnCGCNlzOD+/MUov/F4p8myyAHspEhVobgjpX64q5m6A== - -"@ethereumjs/common@^2.6.4": - version "2.6.5" - resolved "https://registry.npmjs.org/@ethereumjs/common/-/common-2.6.5.tgz" - integrity sha512-lRyVQOeCDaIVtgfbowla32pzeDv2Obr8oR8Put5RdUBNRGr1VGPGQNGP6elWIpgK3YdpzqTOh4GyUGOureVeeA== - dependencies: - crc-32 "^1.2.0" - ethereumjs-util "^7.1.5" - -"@ethereumjs/tx@3.5.2": - version "3.5.2" - resolved "https://registry.npmjs.org/@ethereumjs/tx/-/tx-3.5.2.tgz" - integrity sha512-gQDNJWKrSDGu2w7w0PzVXVBNMzb7wwdDOmOqczmhNjqFxFuIbhVJDwiGEnxFNC2/b8ifcZzY7MLcluizohRzNw== - dependencies: - "@ethereumjs/common" "^2.6.4" - ethereumjs-util "^7.1.5" - -"@ethersproject/abi@^5.7.0", "@ethersproject/abi@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/abi/-/abi-5.7.0.tgz" - integrity sha512-351ktp42TiRcYB3H1OP8yajPeAQstMW/yCFokj/AthP9bLHzQFPlOrxOcwYEDkUAICmOHljvN4K39OMTMUa9RA== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/abstract-provider@^5.7.0", "@ethersproject/abstract-provider@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/abstract-provider/-/abstract-provider-5.7.0.tgz" - integrity sha512-R41c9UkchKCpAqStMYUpdunjo3pkEvZC3FAwZn5S5MGbXoMQOHIdHItezTETxAO5bevtMApSyEhn9+CHcDsWBw== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - -"@ethersproject/abstract-signer@^5.7.0", "@ethersproject/abstract-signer@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/abstract-signer/-/abstract-signer-5.7.0.tgz" - integrity sha512-a16V8bq1/Cz+TGCkE2OPMTOUDLS3grCpdjoJCYNnVBbdYEMSgKrU0+B90s8b6H+ByYTBZN7a3g76jdIJi7UfKQ== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/address@^5.7.0", "@ethersproject/address@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/address/-/address-5.7.0.tgz" - integrity sha512-9wYhYt7aghVGo758POM5nqcOMaE168Q6aRLJZwUmiqSrAungkG74gSSeKEIR7ukixesdRZGPgVqme6vmxs1fkA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - -"@ethersproject/base64@^5.7.0", "@ethersproject/base64@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/base64/-/base64-5.7.0.tgz" - integrity sha512-Dr8tcHt2mEbsZr/mwTPIQAf3Ai0Bks/7gTw9dSqk1mQvhW3XvRlmDJr/4n+wg1JmCl16NZue17CDh8xb/vZ0sQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - -"@ethersproject/basex@^5.7.0", "@ethersproject/basex@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/basex/-/basex-5.7.0.tgz" - integrity sha512-ywlh43GwZLv2Voc2gQVTKBoVQ1mti3d8HK5aMxsfu/nRDnMmNqaSJ3r3n85HBByT8OpoY96SXM1FogC533T4zw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - -"@ethersproject/bignumber@^5.7.0", "@ethersproject/bignumber@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/bignumber/-/bignumber-5.7.0.tgz" - integrity sha512-n1CAdIHRWjSucQO3MC1zPSVgV/6dy/fjL9pMrPP9peL+QxEg9wOsVqwD4+818B6LUEtaXzVHQiuivzRoxPxUGw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - bn.js "^5.2.1" - -"@ethersproject/bytes@^5.6.1", "@ethersproject/bytes@^5.7.0", "@ethersproject/bytes@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.7.0.tgz" - integrity sha512-nsbxwgFXWh9NyYWo+U8atvmMsSdKJprTcICAkvbBffT75qDocbuggBU0SJiVK2MuTrp0q+xvLkTnGMPK1+uA9A== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/constants@^5.7.0", "@ethersproject/constants@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/constants/-/constants-5.7.0.tgz" - integrity sha512-DHI+y5dBNvkpYUMiRQyxRBYBefZkJfo70VUkUAsRjcPs47muV9evftfZ0PJVCXYbAiCgght0DtcF9srFQmIgWA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - -"@ethersproject/contracts@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/contracts/-/contracts-5.7.0.tgz" - integrity sha512-5GJbzEU3X+d33CdfPhcyS+z8MzsTrBGk/sc+G+59+tPa9yFkl6HQ9D6L0QMgNTA9q8dT0XKxxkyp883XsQvbbg== - dependencies: - "@ethersproject/abi" "^5.7.0" - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - -"@ethersproject/hash@^5.7.0", "@ethersproject/hash@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/hash/-/hash-5.7.0.tgz" - integrity sha512-qX5WrQfnah1EFnO5zJv1v46a8HW0+E5xuBBDTwMFZLuVTx0tbU2kkx15NqdjxecrLGatQN9FGQKpb1FKdHCt+g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/hdnode@^5.7.0", "@ethersproject/hdnode@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/hdnode/-/hdnode-5.7.0.tgz" - integrity sha512-OmyYo9EENBPPf4ERhR7oj6uAtUAhYGqOnIS+jE5pTXvdKBS99ikzq1E7Iv0ZQZ5V36Lqx1qZLeak0Ra16qpeOg== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/json-wallets@^5.7.0", "@ethersproject/json-wallets@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/json-wallets/-/json-wallets-5.7.0.tgz" - integrity sha512-8oee5Xgu6+RKgJTkvEMl2wDgSPSAQ9MB/3JYjFV9jlKvcYHUXZC+cQp0njgmxdHkYWn8s6/IqIZYm0YWCjO/0g== - dependencies: - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/pbkdf2" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - aes-js "3.0.0" - scrypt-js "3.0.1" - -"@ethersproject/keccak256@^5.6.1", "@ethersproject/keccak256@^5.7.0", "@ethersproject/keccak256@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/keccak256/-/keccak256-5.7.0.tgz" - integrity sha512-2UcPboeL/iW+pSg6vZ6ydF8tCnv3Iu/8tUmLLzWWGzxWKFFqOBQFLo6uLUv6BDrLgCDfN28RJ/wtByx+jZ4KBg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - js-sha3 "0.8.0" - -"@ethersproject/logger@^5.7.0", "@ethersproject/logger@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.7.0.tgz" - integrity sha512-0odtFdXu/XHtjQXJYA3u9G0G8btm0ND5Cu8M7i5vhEcE8/HmF4Lbdqanwyv4uQTr2tx6b7fQRmgLrsnpQlmnig== - -"@ethersproject/networks@^5.7.0", "@ethersproject/networks@5.7.1": - version "5.7.1" - resolved "https://registry.npmjs.org/@ethersproject/networks/-/networks-5.7.1.tgz" - integrity sha512-n/MufjFYv3yFcUyfhnXotyDlNdFb7onmkSy8aQERi2PjNcnWQ66xXxa3XlS8nCcA8aJKJjIIMNJTC7tu80GwpQ== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/pbkdf2@^5.7.0", "@ethersproject/pbkdf2@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/pbkdf2/-/pbkdf2-5.7.0.tgz" - integrity sha512-oR/dBRZR6GTyaofd86DehG72hY6NpAjhabkhxgr3X2FpJtJuodEl2auADWBZfhDHgVCbu3/H/Ocq2uC6dpNjjw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - -"@ethersproject/properties@^5.7.0", "@ethersproject/properties@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/properties/-/properties-5.7.0.tgz" - integrity sha512-J87jy8suntrAkIZtecpxEPxY//szqr1mlBaYlQ0r4RCaiD2hjheqF9s1LVE8vVuJCXisjIP+JgtK/Do54ej4Sw== - dependencies: - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/providers@5.7.2": - version "5.7.2" - resolved "https://registry.npmjs.org/@ethersproject/providers/-/providers-5.7.2.tgz" - integrity sha512-g34EWZ1WWAVgr4aptGlVBF8mhl3VWjv+8hoAnzStu8Ah22VHBsuGzP17eb6xDVRzw895G4W7vvx60lFFur/1Rg== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/base64" "^5.7.0" - "@ethersproject/basex" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/networks" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/web" "^5.7.0" - bech32 "1.1.4" - ws "7.4.6" - -"@ethersproject/random@^5.7.0", "@ethersproject/random@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/random/-/random-5.7.0.tgz" - integrity sha512-19WjScqRA8IIeWclFme75VMXSBvi4e6InrUNuaR4s5pTF2qNhcGdCUwdxUVGtDDqC00sDLCO93jPQoDUH4HVmQ== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/rlp@^5.7.0", "@ethersproject/rlp@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/rlp/-/rlp-5.7.0.tgz" - integrity sha512-rBxzX2vK8mVF7b0Tol44t5Tb8gomOHkj5guL+HhzQ1yBh/ydjGnpw6at+X6Iw0Kp3OzzzkcKp8N9r0W4kYSs9w== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/sha2@^5.7.0", "@ethersproject/sha2@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.7.0.tgz" - integrity sha512-gKlH42riwb3KYp0reLsFTokByAKoJdgFCwI+CCiX/k+Jm2mbNs6oOaCjYQSlI1+XBVejwH2KrmCbMAT/GnRDQw== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - hash.js "1.1.7" - -"@ethersproject/signing-key@^5.6.2", "@ethersproject/signing-key@^5.7.0", "@ethersproject/signing-key@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/signing-key/-/signing-key-5.7.0.tgz" - integrity sha512-MZdy2nL3wO0u7gkB4nA/pEf8lu1TlFswPNmy8AiYkfKTdO6eXBJyUdmHO/ehm/htHw9K/qF8ujnTyUAD+Ry54Q== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - bn.js "^5.2.1" - elliptic "6.5.4" - hash.js "1.1.7" - -"@ethersproject/solidity@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/solidity/-/solidity-5.7.0.tgz" - integrity sha512-HmabMd2Dt/raavyaGukF4XxizWKhKQ24DoLtdNbBmNKUOPqwjsKQSdV9GQtj9CBEea9DlzETlVER1gYeXXBGaA== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/sha2" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/strings@^5.7.0", "@ethersproject/strings@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/strings/-/strings-5.7.0.tgz" - integrity sha512-/9nu+lj0YswRNSH0NXYqrh8775XNyEdUQAuf3f+SmOrnVewcJ5SBNAjF7lpgehKi4abvNNXyf+HX86czCdJ8Mg== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/transactions@^5.7.0", "@ethersproject/transactions@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/transactions/-/transactions-5.7.0.tgz" - integrity sha512-kmcNicCp1lp8qanMTC3RIikGgoJ80ztTyvtsFvCYpSCfkjhD0jZ2LOrnbcuxuToLIUYYf+4XwD1rP+B/erDIhQ== - dependencies: - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/rlp" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - -"@ethersproject/units@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/units/-/units-5.7.0.tgz" - integrity sha512-pD3xLMy3SJu9kG5xDGI7+xhTEmGXlEqXU4OfNapmfnxLVY4EMSSRp7j1k7eezutBPH7RBN/7QPnwR7hzNlEFeg== - dependencies: - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/constants" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - -"@ethersproject/wallet@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/wallet/-/wallet-5.7.0.tgz" - integrity sha512-MhmXlJXEJFBFVKrDLB4ZdDzxcBxQ3rLyCkhNqVu3CDYvR97E+8r01UgrI+TI99Le+aYm/in/0vp86guJuM7FCA== - dependencies: - "@ethersproject/abstract-provider" "^5.7.0" - "@ethersproject/abstract-signer" "^5.7.0" - "@ethersproject/address" "^5.7.0" - "@ethersproject/bignumber" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/hdnode" "^5.7.0" - "@ethersproject/json-wallets" "^5.7.0" - "@ethersproject/keccak256" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/random" "^5.7.0" - "@ethersproject/signing-key" "^5.7.0" - "@ethersproject/transactions" "^5.7.0" - "@ethersproject/wordlists" "^5.7.0" - -"@ethersproject/web@^5.7.0", "@ethersproject/web@5.7.1": - version "5.7.1" - resolved "https://registry.npmjs.org/@ethersproject/web/-/web-5.7.1.tgz" - integrity sha512-Gueu8lSvyjBWL4cYsWsjh6MtMwM0+H4HvqFPZfB6dV8ctbP9zFAO73VG1cMWae0FLPCtz0peKPpZY8/ugJJX2w== - dependencies: - "@ethersproject/base64" "^5.7.0" - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@ethersproject/wordlists@^5.7.0", "@ethersproject/wordlists@5.7.0": - version "5.7.0" - resolved "https://registry.npmjs.org/@ethersproject/wordlists/-/wordlists-5.7.0.tgz" - integrity sha512-S2TFNJNfHWVHNE6cNDjbVlZ6MgE17MIxMbMg2zv3wn+3XSJGosL1m9ZVv3GXCf/2ymSsQ+hRI5IzoMJTG6aoVA== - dependencies: - "@ethersproject/bytes" "^5.7.0" - "@ethersproject/hash" "^5.7.0" - "@ethersproject/logger" "^5.7.0" - "@ethersproject/properties" "^5.7.0" - "@ethersproject/strings" "^5.7.0" - -"@graphql-typed-document-node/core@^3.1.1": - version "3.2.0" - resolved "https://registry.npmjs.org/@graphql-typed-document-node/core/-/core-3.2.0.tgz" - integrity sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ== - -"@humanwhocodes/config-array@^0.11.13": - version "0.11.14" - resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz" - integrity sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg== - dependencies: - "@humanwhocodes/object-schema" "^2.0.2" - debug "^4.3.1" - minimatch "^3.0.5" - -"@humanwhocodes/module-importer@^1.0.1": - version "1.0.1" - resolved "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz" - integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA== - -"@humanwhocodes/object-schema@^2.0.2": - version "2.0.2" - resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz" - integrity sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw== - -"@improbable-eng/grpc-web@^0.14.1": - version "0.14.1" - resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.14.1.tgz" - integrity sha512-XaIYuunepPxoiGVLLHmlnVminUGzBTnXr8Wv7khzmLWbNw4TCwJKX09GSMJlKhu/TRk6gms0ySFxewaETSBqgw== - dependencies: - browser-headers "^0.4.1" - -"@improbable-eng/grpc-web@^0.15.0": - version "0.15.0" - resolved "https://registry.npmjs.org/@improbable-eng/grpc-web/-/grpc-web-0.15.0.tgz" - integrity sha512-ERft9/0/8CmYalqOVnJnpdDry28q+j+nAlFFARdjyxXDJ+Mhgv9+F600QC8BR9ygOfrXRlAk6CvST2j+JCpQPg== - dependencies: - browser-headers "^0.4.1" - -"@injectivelabs/core-proto-ts@^0.0.14": - version "0.0.14" - resolved "https://registry.npmjs.org/@injectivelabs/core-proto-ts/-/core-proto-ts-0.0.14.tgz" - integrity sha512-NZWlgBzgVrXow9IknFQHvcYKX4QkUD25taRigoNYQK8PDn4+VXd9xM5WFUDRhzm2smTCguyl/+MghpEp4oTPWw== - dependencies: - "@injectivelabs/grpc-web" "^0.0.1" - google-protobuf "^3.14.0" - protobufjs "^7.0.0" - rxjs "^7.4.0" - -"@injectivelabs/exceptions@^1.10.12", "@injectivelabs/exceptions@^1.14.5": - version "1.14.5" - resolved "https://registry.npmjs.org/@injectivelabs/exceptions/-/exceptions-1.14.5.tgz" - integrity sha512-WQ+hxpKz4g4+ZXNTXLFKpf9D9uosleZLqC++2+wK81IQ/lcwi5GrTLYdasOhJeu3c+LKWxHQRHJfSsvt8TQWbA== - dependencies: - "@injectivelabs/grpc-web" "^0.0.1" - "@injectivelabs/ts-types" "^1.14.5" - http-status-codes "^2.2.0" - link-module-alias "^1.2.0" - shx "^0.3.2" - -"@injectivelabs/grpc-web-node-http-transport@^0.0.2": - version "0.0.2" - resolved "https://registry.npmjs.org/@injectivelabs/grpc-web-node-http-transport/-/grpc-web-node-http-transport-0.0.2.tgz" - integrity sha512-rpyhXLiGY/UMs6v6YmgWHJHiO9l0AgDyVNv+jcutNVt4tQrmNvnpvz2wCAGOFtq5LuX/E9ChtTVpk3gWGqXcGA== - -"@injectivelabs/grpc-web-react-native-transport@^0.0.2": - version "0.0.2" - resolved "https://registry.npmjs.org/@injectivelabs/grpc-web-react-native-transport/-/grpc-web-react-native-transport-0.0.2.tgz" - integrity sha512-mk+aukQXnYNgPsPnu3KBi+FD0ZHQpazIlaBZ2jNZG7QAVmxTWtv3R66Zoq99Wx2dnE946NsZBYAoa0K5oSjnow== - -"@injectivelabs/grpc-web@^0.0.1", "@injectivelabs/grpc-web@>=0.0.1": - version "0.0.1" - resolved "https://registry.npmjs.org/@injectivelabs/grpc-web/-/grpc-web-0.0.1.tgz" - integrity sha512-Pu5YgaZp+OvR5UWfqbrPdHer3+gDf+b5fQoY+t2VZx1IAVHX8bzbN9EreYTvTYtFeDpYRWM8P7app2u4EX5wTw== - dependencies: - browser-headers "^0.4.1" - -"@injectivelabs/indexer-proto-ts@1.10.8-rc.4": - version "1.10.8-rc.4" - resolved "https://registry.npmjs.org/@injectivelabs/indexer-proto-ts/-/indexer-proto-ts-1.10.8-rc.4.tgz" - integrity sha512-IwbepTfsHHAv3Z36As6yH/+HIplOEpUu6SFHBCVgdSIaQ8GuvTib4HETiVnV4mjYqoyVgWs+zLSAfih46rdMJQ== - dependencies: - "@injectivelabs/grpc-web" "^0.0.1" - google-protobuf "^3.14.0" - protobufjs "^7.0.0" - rxjs "^7.4.0" - -"@injectivelabs/mito-proto-ts@1.0.9": - version "1.0.9" - resolved "https://registry.npmjs.org/@injectivelabs/mito-proto-ts/-/mito-proto-ts-1.0.9.tgz" - integrity sha512-+TZMvJ4SHwcn6SFPdqaiQFZdNhjH7hyRFozY15nOTC2utdGij9jEsjz1NsyOejfYDA0s1z5Wm1SgrMYKaVpAmQ== - dependencies: - "@injectivelabs/grpc-web" "^0.0.1" - google-protobuf "^3.14.0" - protobufjs "^7.0.0" - rxjs "^7.4.0" - -"@injectivelabs/networks@^1.10.12", "@injectivelabs/networks@1.10.12": - version "1.10.12" - resolved "https://registry.npmjs.org/@injectivelabs/networks/-/networks-1.10.12.tgz" - integrity sha512-tTHyLls1Nik5QTs/S03qqG2y/ITvNwI8CJOQbMmmsr1CL2CdjJBtzRYn9Dyx2p8XgzRFf9hmlybpe20tq9O3SA== - dependencies: - "@injectivelabs/exceptions" "^1.10.12" - "@injectivelabs/ts-types" "^1.10.12" - "@injectivelabs/utils" "^1.10.12" - link-module-alias "^1.2.0" - shx "^0.3.2" - -"@injectivelabs/networks@^1.14.5": - version "1.14.5" - resolved "https://registry.npmjs.org/@injectivelabs/networks/-/networks-1.14.5.tgz" - integrity sha512-9GINd/pPBX6Jyc26pmlLC54s7nLlXsBLZ/1fo8a0nvHkrrODRDE4IldP6KsA9OLVomMPk5TyBUgYLGgM3ST9GA== - dependencies: - "@injectivelabs/exceptions" "^1.14.5" - "@injectivelabs/ts-types" "^1.14.5" - "@injectivelabs/utils" "^1.14.5" - link-module-alias "^1.2.0" - shx "^0.3.2" - -"@injectivelabs/sdk-ts@1.10.72": - version "1.10.72" - resolved "https://registry.npmjs.org/@injectivelabs/sdk-ts/-/sdk-ts-1.10.72.tgz" - integrity sha512-A5mHNNBgO4fI1c/7CZ0bGfVXliy8laP+VaYZ++aWh1YyudoZw4CTCEmLetZRy7AUU3XcfbHa8sAImRi7db+v6Q== - dependencies: - "@apollo/client" "^3.5.8" - "@cosmjs/amino" "^0.30.1" - "@cosmjs/proto-signing" "^0.30.1" - "@cosmjs/stargate" "^0.30.1" - "@ethersproject/bytes" "^5.7.0" - "@injectivelabs/core-proto-ts" "^0.0.14" - "@injectivelabs/exceptions" "^1.10.12" - "@injectivelabs/grpc-web" "^0.0.1" - "@injectivelabs/grpc-web-node-http-transport" "^0.0.2" - "@injectivelabs/grpc-web-react-native-transport" "^0.0.2" - "@injectivelabs/indexer-proto-ts" "1.10.8-rc.4" - "@injectivelabs/mito-proto-ts" "1.0.9" - "@injectivelabs/networks" "^1.10.12" - "@injectivelabs/test-utils" "^1.10.12" - "@injectivelabs/token-metadata" "^1.10.42" - "@injectivelabs/ts-types" "^1.10.12" - "@injectivelabs/utils" "^1.10.12" - "@metamask/eth-sig-util" "^4.0.0" - axios "^0.27.2" - bech32 "^2.0.0" - bip39 "^3.0.4" - cosmjs-types "^0.7.1" - eth-crypto "^2.6.0" - ethereumjs-util "^7.1.4" - ethers "^5.7.2" - google-protobuf "^3.21.0" - graphql "^16.3.0" - http-status-codes "^2.2.0" - js-sha3 "^0.8.0" - jscrypto "^1.0.3" - keccak256 "^1.0.6" - link-module-alias "^1.2.0" - rxjs "^7.8.0" - secp256k1 "^4.0.3" - shx "^0.3.2" - snakecase-keys "^5.4.1" - -"@injectivelabs/test-utils@^1.10.12": - version "1.14.3" - resolved "https://registry.npmjs.org/@injectivelabs/test-utils/-/test-utils-1.14.3.tgz" - integrity sha512-dVe262sACa7YkRr7mfXx58yI/ieuQqm3IMGq7EMweFKI6Kh2gh8FAM2bsDgm1cGewEIhJ9tWh6OM5uNheeVamg== - dependencies: - axios "^0.21.1" - bignumber.js "^9.0.1" - link-module-alias "^1.2.0" - shx "^0.3.2" - snakecase-keys "^5.1.2" - store2 "^2.12.0" - -"@injectivelabs/token-metadata@^1.10.42": - version "1.14.5" - resolved "https://registry.npmjs.org/@injectivelabs/token-metadata/-/token-metadata-1.14.5.tgz" - integrity sha512-GiIiNDixfvbfEjzZG7ixtGYmJllFIcA2Xl1LnsK5yawT8Q+/SoSIJig4tE+0CC/AaGHS1GxDKySrIdMse7PZ0w== - dependencies: - "@injectivelabs/exceptions" "^1.14.5" - "@injectivelabs/networks" "^1.14.5" - "@injectivelabs/ts-types" "^1.14.5" - "@injectivelabs/utils" "^1.14.5" - "@types/lodash.values" "^4.3.6" - copyfiles "^2.4.1" - jsonschema "^1.4.0" - link-module-alias "^1.2.0" - lodash "^4.17.21" - lodash.values "^4.3.0" - shx "^0.3.2" - -"@injectivelabs/ts-types@^1.10.12", "@injectivelabs/ts-types@^1.14.5": - version "1.14.5" - resolved "https://registry.npmjs.org/@injectivelabs/ts-types/-/ts-types-1.14.5.tgz" - integrity sha512-dwmEJE90vMr1zkQhz5lX2280sBMe2GvAj98vOHoL2RLTo0OQkJZrirUHwsTkexJf7sFZIT2PlmLCfix9Ulcp5A== - dependencies: - link-module-alias "^1.2.0" - shx "^0.3.2" - -"@injectivelabs/utils@^1.10.12", "@injectivelabs/utils@1.10.12": - version "1.10.12" - resolved "https://registry.npmjs.org/@injectivelabs/utils/-/utils-1.10.12.tgz" - integrity sha512-c8al79nxIJgV1cBAdW2TPDGldj/8gm5k0h5TIN/AJs8/AeIjpTwwVGfLY3QvPOpRsxuQ9CjBkTXrAcSL1wwkcw== - dependencies: - "@injectivelabs/exceptions" "^1.10.12" - "@injectivelabs/ts-types" "^1.10.12" - axios "^0.21.1" - bignumber.js "^9.0.1" - http-status-codes "^2.2.0" - link-module-alias "^1.2.0" - shx "^0.3.2" - snakecase-keys "^5.1.2" - store2 "^2.12.0" - -"@injectivelabs/utils@^1.14.5": - version "1.14.5" - resolved "https://registry.npmjs.org/@injectivelabs/utils/-/utils-1.14.5.tgz" - integrity sha512-L2ul/7rgop8RLJBhlXjt6Q/A6fXeRZ3hhCZFXGXmA63vz9RSqOFHILiRp6hAFsuZbiITjmVx0eubFPaQU0MymA== - dependencies: - "@injectivelabs/exceptions" "^1.14.5" - "@injectivelabs/ts-types" "^1.14.5" - axios "^0.21.1" - bignumber.js "^9.0.1" - http-status-codes "^2.2.0" - link-module-alias "^1.2.0" - shx "^0.3.2" - snakecase-keys "^5.1.2" - store2 "^2.12.0" - -"@metamask/eth-sig-util@^4.0.0": - version "4.0.1" - resolved "https://registry.npmjs.org/@metamask/eth-sig-util/-/eth-sig-util-4.0.1.tgz" - integrity sha512-tghyZKLHZjcdlDqCA3gNZmLeR0XvOE9U1qoQO9ohyAZT6Pya+H9vkBPcsyXytmYLNgVoin7CKCmweo/R43V+tQ== - dependencies: - ethereumjs-abi "^0.6.8" - ethereumjs-util "^6.2.1" - ethjs-util "^0.1.6" - tweetnacl "^1.0.3" - tweetnacl-util "^0.15.1" - -"@mysten/bcs@0.7.1": - version "0.7.1" - resolved "https://registry.npmjs.org/@mysten/bcs/-/bcs-0.7.1.tgz" - integrity sha512-wFPb8bkhwrbiStfZMV5rFM7J+umpke59/dNjDp+UYJKykNlW23LCk2ePyEUvGdb62HGJM1jyOJ8g4egE3OmdKA== - dependencies: - bs58 "^5.0.0" - -"@mysten/sui.js@0.32.2": - version "0.32.2" - resolved "https://registry.npmjs.org/@mysten/sui.js/-/sui.js-0.32.2.tgz" - integrity sha512-/Hm4xkGolJhqj8FvQr7QSHDTlxIvL52mtbOao9f75YjrBh7y1Uh9kbJSY7xiTF1NY9sv6p5hUVlYRJuM0Hvn9A== - dependencies: - "@mysten/bcs" "0.7.1" - "@noble/curves" "^1.0.0" - "@noble/hashes" "^1.3.0" - "@scure/bip32" "^1.3.0" - "@scure/bip39" "^1.2.0" - "@suchipi/femver" "^1.0.0" - jayson "^4.0.0" - rpc-websockets "^7.5.1" - superstruct "^1.0.3" - tweetnacl "^1.0.3" - -"@noble/curves@^1.0.0", "@noble/curves@^1.2.0", "@noble/curves@~1.3.0": - version "1.3.0" - resolved "https://registry.npmjs.org/@noble/curves/-/curves-1.3.0.tgz" - integrity sha512-t01iSXPuN+Eqzb4eBX0S5oubSqXbK/xXa1Ne18Hj8f9pStxztHCE2gfboSp/dZRLSqfuLpRK2nDXDK+W9puocA== - dependencies: - "@noble/hashes" "1.3.3" - -"@noble/hashes@^1", "@noble/hashes@^1.0.0", "@noble/hashes@^1.2.0", "@noble/hashes@^1.3.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.3.2", "@noble/hashes@~1.3.2", "@noble/hashes@1.3.3": - version "1.3.3" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.3.tgz" - integrity sha512-V7/fPHgl+jsVPXqqeOzT8egNj2iBIVt+ECeMMG8TdcnTikP3oaBtUVqpT/gYCR68aEBJSF+XbYUxStjbFMqIIA== - -"@noble/hashes@~1.1.1", "@noble/hashes@1.1.3": - version "1.1.3" - resolved "https://registry.npmjs.org/@noble/hashes/-/hashes-1.1.3.tgz" - integrity sha512-CE0FCR57H2acVI5UOzIGSSIYxZ6v/HOhDR0Ro9VLyhnzLwx0o8W1mmgaqlEUx4049qJDlIBRztv5k+MM8vbO3A== - -"@nodelib/fs.scandir@2.1.5": - version "2.1.5" - resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" - integrity sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g== - dependencies: - "@nodelib/fs.stat" "2.0.5" - run-parallel "^1.1.9" - -"@nodelib/fs.stat@^2.0.2", "@nodelib/fs.stat@2.0.5": - version "2.0.5" - resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz" - integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== - -"@nodelib/fs.walk@^1.2.3", "@nodelib/fs.walk@^1.2.8": - version "1.2.8" - resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz" - integrity sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg== - dependencies: - "@nodelib/fs.scandir" "2.1.5" - fastq "^1.6.0" - -"@project-serum/anchor@^0.25.0": - version "0.25.0" - resolved "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.25.0.tgz" - integrity sha512-E6A5Y/ijqpfMJ5psJvbw0kVTzLZFUcOFgs6eSM2M2iWE1lVRF18T6hWZVNl6zqZsoz98jgnNHtVGJMs+ds9A7A== - dependencies: - "@project-serum/borsh" "^0.2.5" - "@solana/web3.js" "^1.36.0" - base64-js "^1.5.1" - bn.js "^5.1.2" - bs58 "^4.0.1" - buffer-layout "^1.2.2" - camelcase "^5.3.1" - cross-fetch "^3.1.5" - crypto-hash "^1.3.0" - eventemitter3 "^4.0.7" - js-sha256 "^0.9.0" - pako "^2.0.3" - snake-case "^3.0.4" - superstruct "^0.15.4" - toml "^3.0.0" - -"@project-serum/borsh@^0.2.5": - version "0.2.5" - resolved "https://registry.npmjs.org/@project-serum/borsh/-/borsh-0.2.5.tgz" - integrity sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q== - dependencies: - bn.js "^5.1.2" - buffer-layout "^1.2.0" - -"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": - version "1.1.2" - resolved "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz" - integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== - -"@protobufjs/base64@^1.1.2": - version "1.1.2" - resolved "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz" - integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== - -"@protobufjs/codegen@^2.0.4": - version "2.0.4" - resolved "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz" - integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== - -"@protobufjs/eventemitter@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz" - integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== - -"@protobufjs/fetch@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz" - integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== - dependencies: - "@protobufjs/aspromise" "^1.1.1" - "@protobufjs/inquire" "^1.1.0" - -"@protobufjs/float@^1.0.2": - version "1.0.2" - resolved "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz" - integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== - -"@protobufjs/inquire@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz" - integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== - -"@protobufjs/path@^1.1.2": - version "1.1.2" - resolved "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz" - integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== - -"@protobufjs/pool@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz" - integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== - -"@protobufjs/utf8@^1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz" - integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== - -"@scure/base@~1.1.0", "@scure/base@~1.1.4": - version "1.1.5" - resolved "https://registry.npmjs.org/@scure/base/-/base-1.1.5.tgz" - integrity sha512-Brj9FiG2W1MRQSTB212YVPRrcbjkv48FoZi/u4l/zds/ieRrqsh7aUf6CLwkAq61oKXr/ZlTzlY66gLIj3TFTQ== - -"@scure/bip32@^1.3.0": - version "1.3.3" - resolved "https://registry.npmjs.org/@scure/bip32/-/bip32-1.3.3.tgz" - integrity sha512-LJaN3HwRbfQK0X1xFSi0Q9amqOgzQnnDngIt+ZlsBC3Bm7/nE7K0kwshZHyaru79yIVRv/e1mQAjZyuZG6jOFQ== - dependencies: - "@noble/curves" "~1.3.0" - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" - -"@scure/bip39@^1.2.0": - version "1.2.2" - resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.2.2.tgz" - integrity sha512-HYf9TUXG80beW+hGAt3TRM8wU6pQoYur9iNypTROm42dorCGmLnFe3eWjz3gOq6G62H2WRh0FCzAR1PI+29zIA== - dependencies: - "@noble/hashes" "~1.3.2" - "@scure/base" "~1.1.4" - -"@scure/bip39@1.1.0": - version "1.1.0" - resolved "https://registry.npmjs.org/@scure/bip39/-/bip39-1.1.0.tgz" - integrity sha512-pwrPOS16VeTKg98dYXQyIjJEcWfz7/1YJIwxUEPFfQPtc86Ym/1sVgQ2RLoD43AazMk2l/unK4ITySSpW2+82w== - dependencies: - "@noble/hashes" "~1.1.1" - "@scure/base" "~1.1.0" - -"@solana/buffer-layout-utils@^0.2.0": - version "0.2.0" - resolved "https://registry.npmjs.org/@solana/buffer-layout-utils/-/buffer-layout-utils-0.2.0.tgz" - integrity sha512-szG4sxgJGktbuZYDg2FfNmkMi0DYQoVjN2h7ta1W1hPrwzarcFLBq9UpX1UjNXsNpT9dn+chgprtWGioUAr4/g== - dependencies: - "@solana/buffer-layout" "^4.0.0" - "@solana/web3.js" "^1.32.0" - bigint-buffer "^1.1.5" - bignumber.js "^9.0.1" - -"@solana/buffer-layout@^4.0.0", "@solana/buffer-layout@^4.0.1": - version "4.0.1" - resolved "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz" - integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== - dependencies: - buffer "~6.0.3" - -"@solana/codecs-core@2.0.0-experimental.8618508": - version "2.0.0-experimental.8618508" - resolved "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.0.0-experimental.8618508.tgz" - integrity sha512-JCz7mKjVKtfZxkuDtwMAUgA7YvJcA2BwpZaA1NOLcted4OMC4Prwa3DUe3f3181ixPYaRyptbF0Ikq2MbDkYEA== - -"@solana/codecs-data-structures@2.0.0-experimental.8618508": - version "2.0.0-experimental.8618508" - resolved "https://registry.npmjs.org/@solana/codecs-data-structures/-/codecs-data-structures-2.0.0-experimental.8618508.tgz" - integrity sha512-sLpjL9sqzaDdkloBPV61Rht1tgaKq98BCtIKRuyscIrmVPu3wu0Bavk2n/QekmUzaTsj7K1pVSniM0YqCdnEBw== - dependencies: - "@solana/codecs-core" "2.0.0-experimental.8618508" - "@solana/codecs-numbers" "2.0.0-experimental.8618508" - -"@solana/codecs-numbers@2.0.0-experimental.8618508": - version "2.0.0-experimental.8618508" - resolved "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.0.0-experimental.8618508.tgz" - integrity sha512-EXQKfzFr3CkKKNzKSZPOOOzchXsFe90TVONWsSnVkonO9z+nGKALE0/L9uBmIFGgdzhhU9QQVFvxBMclIDJo2Q== - dependencies: - "@solana/codecs-core" "2.0.0-experimental.8618508" - -"@solana/codecs-strings@2.0.0-experimental.8618508": - version "2.0.0-experimental.8618508" - resolved "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-2.0.0-experimental.8618508.tgz" - integrity sha512-b2yhinr1+oe+JDmnnsV0641KQqqDG8AQ16Z/x7GVWO+AWHMpRlHWVXOq8U1yhPMA4VXxl7i+D+C6ql0VGFp0GA== - dependencies: - "@solana/codecs-core" "2.0.0-experimental.8618508" - "@solana/codecs-numbers" "2.0.0-experimental.8618508" - -"@solana/options@2.0.0-experimental.8618508": - version "2.0.0-experimental.8618508" - resolved "https://registry.npmjs.org/@solana/options/-/options-2.0.0-experimental.8618508.tgz" - integrity sha512-fy/nIRAMC3QHvnKi63KEd86Xr/zFBVxNW4nEpVEU2OT0gCEKwHY4Z55YHf7XujhyuM3PNpiBKg/YYw5QlRU4vg== - dependencies: - "@solana/codecs-core" "2.0.0-experimental.8618508" - "@solana/codecs-numbers" "2.0.0-experimental.8618508" - -"@solana/spl-token-metadata@^0.1.2": - version "0.1.2" - resolved "https://registry.npmjs.org/@solana/spl-token-metadata/-/spl-token-metadata-0.1.2.tgz" - integrity sha512-hJYnAJNkDrtkE2Q41YZhCpeOGU/0JgRFXbtrtOuGGeKc3pkEUHB9DDoxZAxx+XRno13GozUleyBi0qypz4c3bw== - dependencies: - "@solana/codecs-core" "2.0.0-experimental.8618508" - "@solana/codecs-data-structures" "2.0.0-experimental.8618508" - "@solana/codecs-numbers" "2.0.0-experimental.8618508" - "@solana/codecs-strings" "2.0.0-experimental.8618508" - "@solana/options" "2.0.0-experimental.8618508" - "@solana/spl-type-length-value" "0.1.0" - -"@solana/spl-token@^0.3.5": - version "0.3.11" - resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.3.11.tgz" - integrity sha512-bvohO3rIMSVL24Pb+I4EYTJ6cL82eFpInEXD/I8K8upOGjpqHsKUoAempR/RnUlI1qSFNyFlWJfu6MNUgfbCQQ== - dependencies: - "@solana/buffer-layout" "^4.0.0" - "@solana/buffer-layout-utils" "^0.2.0" - "@solana/spl-token-metadata" "^0.1.2" - buffer "^6.0.3" - -"@solana/spl-token@^0.4.0": - version "0.4.0" - resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.4.0.tgz" - integrity sha512-jjBIBG9IsclqQVl5Y82npGE6utdCh7Z9VFcF5qgJa5EUq2XgspW3Dt1wujWjH/vQDRnkp9zGO+BqQU/HhX/3wg== - dependencies: - "@solana/buffer-layout" "^4.0.0" - "@solana/buffer-layout-utils" "^0.2.0" - "@solana/spl-token-metadata" "^0.1.2" - buffer "^6.0.3" - -"@solana/spl-type-length-value@0.1.0": - version "0.1.0" - resolved "https://registry.npmjs.org/@solana/spl-type-length-value/-/spl-type-length-value-0.1.0.tgz" - integrity sha512-JBMGB0oR4lPttOZ5XiUGyvylwLQjt1CPJa6qQ5oM+MBCndfjz2TKKkw0eATlLLcYmq1jBVsNlJ2cD6ns2GR7lA== - dependencies: - buffer "^6.0.3" - -"@solana/web3.js@^1.2.0", "@solana/web3.js@^1.32.0", "@solana/web3.js@^1.36.0", "@solana/web3.js@^1.66.2", "@solana/web3.js@^1.68.0", "@solana/web3.js@^1.87.6", "@solana/web3.js@^1.88.0", "@solana/web3.js@^1.89.1": - version "1.90.0" - resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.90.0.tgz" - integrity sha512-p0cb/COXb8NNVSMkGMPwqQ6NvObZgUitN80uOedMB+jbYWOKOeJBuPnzhenkIV9RX0krGwyuY1Ltn5O8MGFsEw== - dependencies: - "@babel/runtime" "^7.23.4" - "@noble/curves" "^1.2.0" - "@noble/hashes" "^1.3.2" - "@solana/buffer-layout" "^4.0.1" - agentkeepalive "^4.5.0" - bigint-buffer "^1.1.5" - bn.js "^5.2.1" - borsh "^0.7.0" - bs58 "^4.0.1" - buffer "6.0.3" - fast-stable-stringify "^1.0.0" - jayson "^4.1.0" - node-fetch "^2.7.0" - rpc-websockets "^7.5.1" - superstruct "^0.14.2" - -"@stylistic/eslint-plugin-js@^1.6.1", "@stylistic/eslint-plugin-js@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-js/-/eslint-plugin-js-1.6.1.tgz" - integrity sha512-gHRxkbA5p8S1fnChE7Yf5NFltRZCzbCuQOcoTe93PSKBC4GqVjZmlWUSLz9pJKHvDAUTjWkfttWHIOaFYPEhRQ== - dependencies: - acorn "^8.11.3" - escape-string-regexp "^4.0.0" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - -"@stylistic/eslint-plugin-jsx@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-jsx/-/eslint-plugin-jsx-1.6.1.tgz" - integrity sha512-uJQcg3iqrhm3EH15ZjxmZ1YmXXexkLKFEgxkWA3RYjgAVTx8k7xGJwClK/JnjKDGdbFRiDQPjxt964R1vsaFaQ== - dependencies: - "@stylistic/eslint-plugin-js" "^1.6.1" - estraverse "^5.3.0" - picomatch "^3.0.1" - -"@stylistic/eslint-plugin-plus@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-plus/-/eslint-plugin-plus-1.6.1.tgz" - integrity sha512-nYIXfdYN+pBVmm0vPCKQFg/IK35tf3ZGz+0WENUL6ww1+jKM6/i36FalRFculiHzO+wOpJ3/yXWJC3PCbwGFZQ== - dependencies: - "@typescript-eslint/utils" "^6.20.0" - -"@stylistic/eslint-plugin-ts@^1.6.1", "@stylistic/eslint-plugin-ts@1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@stylistic/eslint-plugin-ts/-/eslint-plugin-ts-1.6.1.tgz" - integrity sha512-eZxrFaLhPJVUQmtsRXKiuzSou0nlHevKc1WsfhxUJ9p8juv3G3YlbbGeYg4AP1fNlEmWs/lZQAP2WfzQOdBNvQ== - dependencies: - "@stylistic/eslint-plugin-js" "1.6.1" - "@typescript-eslint/utils" "^6.20.0" - -"@stylistic/eslint-plugin@^1.6.1": - version "1.6.1" - resolved "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-1.6.1.tgz" - integrity sha512-De7Sw86OtIf7SsMgjLCf4bTeI3085Plyh4l0Rg1V42BTFo/Q6Pz7Cbu31rEk/UHFiEna/YO8Hxj80jFP3ObrQw== - dependencies: - "@stylistic/eslint-plugin-js" "1.6.1" - "@stylistic/eslint-plugin-jsx" "1.6.1" - "@stylistic/eslint-plugin-plus" "1.6.1" - "@stylistic/eslint-plugin-ts" "1.6.1" - -"@suchipi/femver@^1.0.0": - version "1.0.0" - resolved "https://registry.npmjs.org/@suchipi/femver/-/femver-1.0.0.tgz" - integrity sha512-bprE8+K5V+DPX7q2e2K57ImqNBdfGHDIWaGI5xHxZoxbKOuQZn4wzPiUxOAHnsUr3w3xHrWXwN7gnG/iIuEMIg== - -"@terra-money/legacy.proto@npm:@terra-money/terra.proto@^0.1.7": - version "0.1.7" - resolved "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-0.1.7.tgz" - integrity sha512-NXD7f6pQCulvo6+mv6MAPzhOkUzRjgYVuHZE/apih+lVnPG5hDBU0rRYnOGGofwvKT5/jQoOENnFn/gioWWnyQ== - dependencies: - google-protobuf "^3.17.3" - long "^4.0.0" - protobufjs "~6.11.2" - -"@terra-money/terra.js@3.1.9": - version "3.1.9" - resolved "https://registry.npmjs.org/@terra-money/terra.js/-/terra.js-3.1.9.tgz" - integrity sha512-JulSvOHLM56fL7s+cIjIbZeWPBluq883X1soWxA4TG5rKkDythT/DHeLXr3jP5Ld/26VENPSg6lNvK7cEYKpiw== - dependencies: - "@classic-terra/terra.proto" "^1.1.0" - "@terra-money/terra.proto" "^2.1.0" - axios "^0.27.2" - bech32 "^2.0.0" - bip32 "^2.0.6" - bip39 "^3.0.3" - bufferutil "^4.0.3" - decimal.js "^10.2.1" - jscrypto "^1.0.1" - readable-stream "^3.6.0" - secp256k1 "^4.0.2" - tmp "^0.2.1" - utf-8-validate "^5.0.5" - ws "^7.5.9" - -"@terra-money/terra.proto@^2.1.0": - version "2.1.0" - resolved "https://registry.npmjs.org/@terra-money/terra.proto/-/terra.proto-2.1.0.tgz" - integrity sha512-rhaMslv3Rkr+QsTQEZs64FKA4QlfO0DfQHaR6yct/EovenMkibDEQ63dEL6yJA6LCaEQGYhyVB9JO9pTUA8ybw== - dependencies: - "@improbable-eng/grpc-web" "^0.14.1" - google-protobuf "^3.17.3" - long "^4.0.0" - protobufjs "~6.11.2" - -"@types/bn.js@^4.11.3": - version "4.11.6" - resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-4.11.6.tgz" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== - dependencies: - "@types/node" "*" - -"@types/bn.js@^5.1.0": - version "5.1.5" - resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.5.tgz" - integrity sha512-V46N0zwKRF5Q00AZ6hWtN0T8gGmDUaUzLWQvHFo5yThtVwK/VCenFY3wXVbOvNfajEpsTfQM4IN9k/d6gUVX3A== - dependencies: - "@types/node" "*" - -"@types/bn.js@5.1.1": - version "5.1.1" - resolved "https://registry.npmjs.org/@types/bn.js/-/bn.js-5.1.1.tgz" - integrity sha512-qNrYbZqMx0uJAfKnKclPh+dTwK33KfLHYqtyODwd5HnXOjnkhc4qgn3BrK6RWyGZm5+sIFE7Q7Vz6QQtJB7w7g== - dependencies: - "@types/node" "*" - -"@types/chai@^4.3.0": - version "4.3.11" - resolved "https://registry.npmjs.org/@types/chai/-/chai-4.3.11.tgz" - integrity sha512-qQR1dr2rGIHYlJulmr8Ioq3De0Le9E4MJ5AiaeAETJJpndT1uUNHsGFK3L/UIu+rbkQSdj8J/w2bCsBZc/Y5fQ== - -"@types/connect@^3.4.33": - version "3.4.38" - resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz" - integrity sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug== - dependencies: - "@types/node" "*" - -"@types/json-schema@^7.0.12": - version "7.0.15" - resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz" - integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" - integrity sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ== - -"@types/lodash.values@^4.3.6": - version "4.3.9" - resolved "https://registry.npmjs.org/@types/lodash.values/-/lodash.values-4.3.9.tgz" - integrity sha512-IJ20OEfqNwm3k8ENwoM3q0yOs4UMpgtD4GqxB4lwBHToGthHWqhyh5DdSgQjioocz0QK2SSBkJfCq95ZTV8BTw== - dependencies: - "@types/lodash" "*" - -"@types/lodash@*": - version "4.14.202" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.202.tgz" - integrity sha512-OvlIYQK9tNneDlS0VN54LLd5uiPCBOp7gS5Z0f1mjoJYBrtStzgmJBxONW3U6OZqdtNzZPmn9BS/7WI7BFFcFQ== - -"@types/long@^4.0.1", "@types/long@^4.0.2": - version "4.0.2" - resolved "https://registry.npmjs.org/@types/long/-/long-4.0.2.tgz" - integrity sha512-MqTGEo5bj5t157U6fA/BiDynNkn0YknVdh48CMPkTSpFTVmvao5UQmm7uEF6xBEo7qIMAlY/JSleYaE6VOdpaA== - -"@types/mocha@^9.0.0": - version "9.1.1" - resolved "https://registry.npmjs.org/@types/mocha/-/mocha-9.1.1.tgz" - integrity sha512-Z61JK7DKDtdKTWwLeElSEBcWGRLY8g95ic5FoQqI9CMx0ns/Ghep3B4DfcEimiKMvtamNVULVNKEsiwV3aQmXw== - -"@types/node@*", "@types/node@>=13.7.0": - version "20.11.5" - resolved "https://registry.npmjs.org/@types/node/-/node-20.11.5.tgz" - integrity sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w== - dependencies: - undici-types "~5.26.4" - -"@types/node@^12.12.54": - version "12.20.55" - resolved "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz" - integrity sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ== - -"@types/node@^18.0.3": - version "18.19.15" - resolved "https://registry.npmjs.org/@types/node/-/node-18.19.15.tgz" - integrity sha512-AMZ2UWx+woHNfM11PyAEQmfSxi05jm9OlkxczuHeEqmvwPkYj6MWv44gbzDPefYOLysTOFyI3ziiy2ONmUZfpA== - dependencies: - undici-types "~5.26.4" - -"@types/node@10.12.18": - version "10.12.18" - resolved "https://registry.npmjs.org/@types/node/-/node-10.12.18.tgz" - integrity sha512-fh+pAqt4xRzPfqA6eh3Z2y6fyZavRIumvjhaCL753+TVkGKGhpPeyrJG2JftD0T9q4GF00KjefsQ+PQNDdWQaQ== - -"@types/pbkdf2@^3.0.0": - version "3.1.2" - resolved "https://registry.npmjs.org/@types/pbkdf2/-/pbkdf2-3.1.2.tgz" - integrity sha512-uRwJqmiXmh9++aSu1VNEn3iIxWOhd8AHXNSdlaLfdAAdSTY9jYVeGWnzejM3dvrkbqE3/hyQkQQ29IFATEGlew== - dependencies: - "@types/node" "*" - -"@types/secp256k1@^4.0.1": - version "4.0.6" - resolved "https://registry.npmjs.org/@types/secp256k1/-/secp256k1-4.0.6.tgz" - integrity sha512-hHxJU6PAEUn0TP4S/ZOzuTUvJWuZ6eIKeNKb5RBpODvSl6hp1Wrw4s7ATY50rklRCScUDpHzVA/DQdSjJ3UoYQ== - dependencies: - "@types/node" "*" - -"@types/semver@^7.5.0": - version "7.5.6" - resolved "https://registry.npmjs.org/@types/semver/-/semver-7.5.6.tgz" - integrity sha512-dn1l8LaMea/IjDoHNd9J52uBbInB796CDffS6VdIxvqYCPSG0V0DzHp76GpaWnlhg88uYyPbXCDIowa86ybd5A== - -"@types/ws@^7.4.4": - version "7.4.7" - resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz" - integrity sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww== - dependencies: - "@types/node" "*" - -"@typescript-eslint/eslint-plugin@^6.21.0", "@typescript-eslint/eslint-plugin@^6.4.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.21.0.tgz" - integrity sha512-oy9+hTPCUFpngkEZUSzbf9MxI65wbKFoQYsgPdILTfbUldp5ovUuphZVe4i30emU9M/kP+T64Di0mxl7dSw3MA== - dependencies: - "@eslint-community/regexpp" "^4.5.1" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/type-utils" "6.21.0" - "@typescript-eslint/utils" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - graphemer "^1.4.0" - ignore "^5.2.4" - natural-compare "^1.4.0" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/parser@^6.0.0 || ^6.0.0-alpha", "@typescript-eslint/parser@^6.4.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz" - integrity sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ== - dependencies: - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - -"@typescript-eslint/scope-manager@6.21.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.21.0.tgz" - integrity sha512-OwLUIWZJry80O99zvqXVEioyniJMa+d2GrqpUTqi5/v5D5rOrppJVBPa0yKCblcigC0/aYAzxxqQ1B+DS2RYsg== - dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - -"@typescript-eslint/type-utils@6.21.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.21.0.tgz" - integrity sha512-rZQI7wHfao8qMX3Rd3xqeYSMCL3SoiSQLBATSiVKARdFGCYSRvmViieZjqc58jKgs8Y8i9YvVVhRbHSTA4VBag== - dependencies: - "@typescript-eslint/typescript-estree" "6.21.0" - "@typescript-eslint/utils" "6.21.0" - debug "^4.3.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/types@6.21.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.21.0.tgz" - integrity sha512-1kFmZ1rOm5epu9NZEZm1kckCDGj5UJEf7P1kliH4LKu/RkwpsfqqGmY2OOcUs18lSlQBKLDYBOGxRVtrMN5lpg== - -"@typescript-eslint/typescript-estree@6.21.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.21.0.tgz" - integrity sha512-6npJTkZcO+y2/kr+z0hc4HwNfrrP4kNYh57ek7yCNlrBjWQ1Y0OS7jiZTkgumrvkX5HkEKXFZkkdFNkaW2wmUQ== - dependencies: - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/visitor-keys" "6.21.0" - debug "^4.3.4" - globby "^11.1.0" - is-glob "^4.0.3" - minimatch "9.0.3" - semver "^7.5.4" - ts-api-utils "^1.0.1" - -"@typescript-eslint/utils@^6.20.0", "@typescript-eslint/utils@6.21.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.21.0.tgz" - integrity sha512-NfWVaC8HP9T8cbKQxHcsJBY5YE1O33+jpMwN45qzWWaPDZgLIbo12toGMWnmhvCpd3sIxkpDw3Wv1B3dYrbDQQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - "@types/json-schema" "^7.0.12" - "@types/semver" "^7.5.0" - "@typescript-eslint/scope-manager" "6.21.0" - "@typescript-eslint/types" "6.21.0" - "@typescript-eslint/typescript-estree" "6.21.0" - semver "^7.5.4" - -"@typescript-eslint/visitor-keys@6.21.0": - version "6.21.0" - resolved "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.21.0.tgz" - integrity sha512-JJtkDduxLi9bivAB+cYOVMtbkqdPOhZ+ZI5LC47MIRrDV4Yn2o+ZnW10Nkmr28xRpSpdJ6Sm42Hjf2+REYXm0A== - dependencies: - "@typescript-eslint/types" "6.21.0" - eslint-visitor-keys "^3.4.1" - -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.npmjs.org/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== - -"@ungap/structured-clone@^1.2.0": - version "1.2.0" - resolved "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz" - integrity sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ== - -"@wry/caches@^1.0.0": - version "1.0.1" - resolved "https://registry.npmjs.org/@wry/caches/-/caches-1.0.1.tgz" - integrity sha512-bXuaUNLVVkD20wcGBWRyo7j9N3TxePEWFZj2Y+r9OoUzfqmavM84+mFykRicNsBqatba5JLay1t48wxaXaWnlA== - dependencies: - tslib "^2.3.0" - -"@wry/context@^0.7.0": - version "0.7.4" - resolved "https://registry.npmjs.org/@wry/context/-/context-0.7.4.tgz" - integrity sha512-jmT7Sb4ZQWI5iyu3lobQxICu2nC/vbUhP0vIdd6tHC9PTfenmRmuIFqktc6GH9cgi+ZHnsLWPvfSvc4DrYmKiQ== - dependencies: - tslib "^2.3.0" - -"@wry/equality@^0.5.6": - version "0.5.7" - resolved "https://registry.npmjs.org/@wry/equality/-/equality-0.5.7.tgz" - integrity sha512-BRFORjsTuQv5gxcXsuDXx6oGRhuVsEGwZy6LOzRRfgu+eSfxbhUQ9L9YtSEIuIjY/o7g3iWFjrc5eSY1GXP2Dw== - dependencies: - tslib "^2.3.0" - -"@wry/trie@^0.4.3": - version "0.4.3" - resolved "https://registry.npmjs.org/@wry/trie/-/trie-0.4.3.tgz" - integrity sha512-I6bHwH0fSf6RqQcnnXLJKhkSXG45MFral3GxPaY4uAl0LYDZM+YDVDAiU9bYwjTuysy1S0IeecWtmq1SZA3M1w== - dependencies: - tslib "^2.3.0" - -"@wry/trie@^0.5.0": - version "0.5.0" - resolved "https://registry.npmjs.org/@wry/trie/-/trie-0.5.0.tgz" - integrity sha512-FNoYzHawTMk/6KMQoEG5O4PuioX19UbwdQKF44yw0nLfOypfQdjtfZzo/UIJWAJ23sNIFbD1Ug9lbaDGMwbqQA== - dependencies: - tslib "^2.3.0" - -"@xpla/xpla.js@^0.2.1": - version "0.2.3" - resolved "https://registry.npmjs.org/@xpla/xpla.js/-/xpla.js-0.2.3.tgz" - integrity sha512-Tfk7hCGWXtwr08reY3Pi6dmzIqFbzri9jcyzJdfNmdo4cN0PMwpRJuZZcPmtxiIUnNef3AN1E/6nJUD5MKniuA== - dependencies: - "@ethersproject/bytes" "^5.6.1" - "@ethersproject/keccak256" "^5.6.1" - "@ethersproject/signing-key" "^5.6.2" - "@terra-money/legacy.proto" "npm:@terra-money/terra.proto@^0.1.7" - "@terra-money/terra.proto" "^2.1.0" - axios "^0.26.1" - bech32 "^2.0.0" - bip32 "^2.0.6" - bip39 "^3.0.3" - bufferutil "^4.0.3" - crypto-addr-codec "^0.1.7" - decimal.js "^10.2.1" - elliptic "^6.5.4" - ethereumjs-util "^7.1.5" - jscrypto "^1.0.1" - readable-stream "^3.6.0" - secp256k1 "^4.0.2" - tmp "^0.2.1" - utf-8-validate "^5.0.5" - ws "^7.5.8" - -acorn-jsx@^5.3.2: - version "5.3.2" - resolved "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz" - integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ== - -"acorn@^6.0.0 || ^7.0.0 || ^8.0.0", acorn@7.1.1: - version "7.1.1" - resolved "https://registry.npmjs.org/acorn/-/acorn-7.1.1.tgz" - integrity sha512-add7dgA5ppRPxCFJoAGfMDi7PIBXq1RtGo7BhbLaxwrXPOmw8gq48Y9ozT01hUKy9byMjlR20EJhu5zlkErEkg== - -acorn@^8.11.3: - version "8.11.3" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== - -acorn@^8.9.0: - version "8.11.3" - resolved "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz" - integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg== - -aes-js@3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/aes-js/-/aes-js-3.0.0.tgz" - integrity sha512-H7wUZRn8WpTq9jocdxQ2c8x2sKo9ZVmzfRE13GiNJXfp7NcKYEdvl3vspKjXox6RIG2VtaRe4JFvxG4rqp2Zuw== - -agentkeepalive@^4.5.0: - version "4.5.0" - resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.5.0.tgz" - integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== - dependencies: - humanize-ms "^1.2.1" - -ajv@^6.12.4: - version "6.12.6" - resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" - integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== - dependencies: - fast-deep-equal "^3.1.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -algo-msgpack-with-bigint@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/algo-msgpack-with-bigint/-/algo-msgpack-with-bigint-2.1.1.tgz" - integrity sha512-F1tGh056XczEaEAqu7s+hlZUDWwOBT70Eq0lfMpBP2YguSQVyxRbprLq5rELXKQOyOaixTWYhMeMQMzP0U5FoQ== - -algosdk@^2.4.0: - version "2.7.0" - resolved "https://registry.npmjs.org/algosdk/-/algosdk-2.7.0.tgz" - integrity sha512-sBE9lpV7bup3rZ+q2j3JQaFAE9JwZvjWKX00vPlG8e9txctXbgLL56jZhSWZndqhDI9oI+0P4NldkuQIWdrUyg== - dependencies: - algo-msgpack-with-bigint "^2.1.1" - buffer "^6.0.3" - hi-base32 "^0.5.1" - js-sha256 "^0.9.0" - js-sha3 "^0.8.0" - js-sha512 "^0.8.0" - json-bigint "^1.0.0" - tweetnacl "^1.0.3" - vlq "^2.0.4" - -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== - -ansi-regex@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz" - integrity sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ== - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -ansi-styles@^4.0.0, ansi-styles@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz" - integrity sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg== - dependencies: - color-convert "^2.0.1" - -anymatch@~3.1.2: - version "3.1.3" - resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz" - integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== - dependencies: - normalize-path "^3.0.0" - picomatch "^2.0.4" - -aptos@1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/aptos/-/aptos-1.5.0.tgz" - integrity sha512-N7OuRtU7IYHkDkNx+4QS3g/QQGCp+36KzYn3oXPmT7Kttfuv+UKliQVdjy3cLmwd/DCQSh9ObTovwdxnHjUn0g== - dependencies: - "@noble/hashes" "1.1.3" - "@scure/bip39" "1.1.0" - axios "0.27.2" - form-data "4.0.0" - tweetnacl "1.0.3" - -argparse@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz" - integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== - -array-buffer-byte-length@^1.0.0, array-buffer-byte-length@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz" - integrity sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg== - dependencies: - call-bind "^1.0.5" - is-array-buffer "^3.0.4" - -array-includes@^3.1.7: - version "3.1.7" - resolved "https://registry.npmjs.org/array-includes/-/array-includes-3.1.7.tgz" - integrity sha512-dlcsNBIiWhPkHdOEEKnehA+RNUWDc4UqFtnIXU4uuYDPtA4LDkr7qip2p0VvFAEXNDr0yWZ9PJyIRiGjRLQzwQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - get-intrinsic "^1.2.1" - is-string "^1.0.7" - -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - -array.prototype.filter@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/array.prototype.filter/-/array.prototype.filter-1.0.3.tgz" - integrity sha512-VizNcj/RGJiUyQBgzwxzE5oHdeuXY5hSbbmKMlphj1cy1Vl7Pn2asCGbSrru6hSQjmCzqTBPVWAF/whmEOVHbw== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-array-method-boxes-properly "^1.0.0" - is-string "^1.0.7" - -array.prototype.findlastindex@^1.2.3: - version "1.2.4" - resolved "https://registry.npmjs.org/array.prototype.findlastindex/-/array.prototype.findlastindex-1.2.4.tgz" - integrity sha512-hzvSHUshSpCflDR1QMUBLHGHP1VIEBegT4pix9H/Z92Xw3ySoy6c2qh7lJWTJnRJ8JCZ9bJNCgTyYaJGcJu6xQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.3.0" - es-shim-unscopables "^1.0.2" - -array.prototype.flat@^1.3.2: - version "1.3.2" - resolved "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.2.tgz" - integrity sha512-djYB+Zx2vLewY8RWlNCUdHjDXs2XOgm602S9E7P/UpHgfeHL00cRiIF+IN/G/aUJ7kGPb6yO/ErDI5V2s8iycA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -array.prototype.flatmap@^1.3.2: - version "1.3.2" - resolved "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.2.tgz" - integrity sha512-Ewyx0c9PmpcsByhSW4r+9zDU7sGjFc86qf/kKtuSCRdhfbk0SNLLkaT5qvcHnRGgc5NP/ly/y+qkXkqONX54CQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - es-shim-unscopables "^1.0.0" - -arraybuffer.prototype.slice@^1.0.2: - version "1.0.3" - resolved "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz" - integrity sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A== - dependencies: - array-buffer-byte-length "^1.0.1" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.2.1" - get-intrinsic "^1.2.3" - is-array-buffer "^3.0.4" - is-shared-array-buffer "^1.0.2" - -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz" - integrity sha512-3CYzex9M9FGQjCGMGyi6/31c8GJbgb0qGyrx5HWxPd0aCwh4cB2YjMb2Xf9UuoogrMrlO9cTqnB5rI5GHZTcUA== - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" - integrity sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q== - -available-typed-arrays@^1.0.5, available-typed-arrays@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.6.tgz" - integrity sha512-j1QzY8iPNPG4o4xmO3ptzpRxTciqD3MgEHtifP/YnJpIo58Xu+ne4BejlbkuaLfXn/nz6HFiw29bLpj2PNMdGg== - -axios@^0.21.1: - version "0.21.4" - resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -axios@^0.21.2: - version "0.21.4" - resolved "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz" - integrity sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg== - dependencies: - follow-redirects "^1.14.0" - -axios@^0.24.0: - version "0.24.0" - resolved "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz" - integrity sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA== - dependencies: - follow-redirects "^1.14.4" - -axios@^0.26.1: - version "0.26.1" - resolved "https://registry.npmjs.org/axios/-/axios-0.26.1.tgz" - integrity sha512-fPwcX4EvnSHuInCMItEhAGnaSEXRBjtzh9fOtsE6E1G6p7vl7edEeZe11QHf18+6+9gR5PbKV/sGKNaD8YaMeA== - dependencies: - follow-redirects "^1.14.8" - -axios@^0.27.2: - version "0.27.2" - resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== - dependencies: - follow-redirects "^1.14.9" - form-data "^4.0.0" - -axios@0.27.2: - version "0.27.2" - resolved "https://registry.npmjs.org/axios/-/axios-0.27.2.tgz" - integrity sha512-t+yRIyySRTp/wua5xEr+z1q60QmLq8ABsS5O9Me1AsE5dfKqgnCFzwiCZZ/cGNd1lq4/7akDWMxdhVlucjmnOQ== - dependencies: - follow-redirects "^1.14.9" - form-data "^4.0.0" - -balanced-match@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz" - integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== - -base-x@^3.0.2, base-x@^3.0.8: - version "3.0.9" - resolved "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz" - integrity sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ== - dependencies: - safe-buffer "^5.0.1" - -base-x@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz" - integrity sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw== - -base64-js@^1.3.0, base64-js@^1.3.1, base64-js@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" - integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== - -bech32@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - -bech32@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz" - integrity sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg== - -bech32@1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/bech32/-/bech32-1.1.4.tgz" - integrity sha512-s0IrSOzLlbvX7yp4WBfPITzpAU8sqQcpsmwXDiKwrG4r491vwCO/XpejasRNl0piBMe/DvP4Tz0mIS/X1DPJBQ== - -big-integer@1.6.36: - version "1.6.36" - resolved "https://registry.npmjs.org/big-integer/-/big-integer-1.6.36.tgz" - integrity sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg== - -bigint-buffer@^1.1.5: - version "1.1.5" - resolved "https://registry.npmjs.org/bigint-buffer/-/bigint-buffer-1.1.5.tgz" - integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== - dependencies: - bindings "^1.3.0" - -bignumber.js@^9.0.0, bignumber.js@^9.0.1: - version "9.1.2" - resolved "https://registry.npmjs.org/bignumber.js/-/bignumber.js-9.1.2.tgz" - integrity sha512-2/mKyZH9K85bzOEfhXDBFZTGd1CTs+5IHpeFQo9luiBG7hghdC851Pj2WAhb6E3R6b9tZj/XKhbg4fum+Kepug== - -binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== - -binary-parser@^2.2.1: - version "2.2.1" - resolved "https://registry.npmjs.org/binary-parser/-/binary-parser-2.2.1.tgz" - integrity sha512-5ATpz/uPDgq5GgEDxTB4ouXCde7q2lqAQlSdBRQVl/AJnxmQmhIfyxJx+0MGu//D5rHQifkfGbWWlaysG0o9NA== - -bindings@^1.3.0, bindings@^1.5.0: - version "1.5.0" - resolved "https://registry.npmjs.org/bindings/-/bindings-1.5.0.tgz" - integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== - dependencies: - file-uri-to-path "1.0.0" - -bip32@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/bip32/-/bip32-2.0.6.tgz" - integrity sha512-HpV5OMLLGTjSVblmrtYRfFFKuQB+GArM0+XP8HGWfJ5vxYBqo+DesvJwOdC2WJ3bCkZShGf0QIfoIpeomVzVdA== - dependencies: - "@types/node" "10.12.18" - bs58check "^2.1.1" - create-hash "^1.2.0" - create-hmac "^1.1.7" - tiny-secp256k1 "^1.1.3" - typeforce "^1.11.5" - wif "^2.0.6" - -bip39@^3.0.3, bip39@^3.0.4: - version "3.1.0" - resolved "https://registry.npmjs.org/bip39/-/bip39-3.1.0.tgz" - integrity sha512-c9kiwdk45Do5GL0vJMe7tS95VjCii65mYAH7DfWl3uW8AVzXKQVUm64i3hzVybBDMp9r7j9iNxR85+ul8MdN/A== - dependencies: - "@noble/hashes" "^1.2.0" - -bip66@^1.1.5: - version "1.1.5" - resolved "https://registry.npmjs.org/bip66/-/bip66-1.1.5.tgz" - integrity sha512-nemMHz95EmS38a26XbbdxIYj5csHd3RMP3H5bwQknX0WYHF01qhpufP42mLOwVICuH2JmhIhXiWs89MfUGL7Xw== - dependencies: - safe-buffer "^5.0.1" - -blakejs@^1.1.0: - version "1.2.1" - resolved "https://registry.npmjs.org/blakejs/-/blakejs-1.2.1.tgz" - integrity sha512-QXUSXI3QVc/gJME0dBpXrag1kbzOqCjCX8/b54ntNyW6sjtoqxqRk3LTmXzaJoh71zMsDCjM+47jS7XiwN/+fQ== - -bn.js@^4.11.0, bn.js@^4.11.8: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== - -bn.js@^5.1.2, bn.js@^5.2.0, bn.js@^5.2.1, bn.js@5.2.1: - version "5.2.1" - resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz" - integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== - -borsh@^0.7.0: - version "0.7.0" - resolved "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz" - integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== - dependencies: - bn.js "^5.2.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -brace-expansion@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz" - integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== - dependencies: - balanced-match "^1.0.0" - -braces@^3.0.2, braces@~3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== - dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" - integrity sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w== - -browser-headers@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/browser-headers/-/browser-headers-0.4.1.tgz" - integrity sha512-CA9hsySZVo9371qEHjHZtYxV2cFtVj5Wj/ZHi8ooEsrtm4vOnl9Y9HmyYWk9q+05d7K3rdoAE0j3MVEFVvtQtg== - -browser-stdout@1.3.1: - version "1.3.1" - resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" - integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== - -browserify-aes@^1.0.6, browserify-aes@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" - integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== - dependencies: - buffer-xor "^1.0.3" - cipher-base "^1.0.0" - create-hash "^1.1.0" - evp_bytestokey "^1.0.3" - inherits "^2.0.1" - safe-buffer "^5.0.1" - -bs58@^4.0.0, bs58@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz" - integrity sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw== - dependencies: - base-x "^3.0.2" - -bs58@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz" - integrity sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ== - dependencies: - base-x "^4.0.0" - -bs58check@^2.1.1, bs58check@^2.1.2, bs58check@<3.0.0: - version "2.1.2" - resolved "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz" - integrity sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA== - dependencies: - bs58 "^4.0.0" - create-hash "^1.1.0" - safe-buffer "^5.1.2" - -buffer-from@^1.0.0, buffer-from@^1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - -buffer-layout@^1.2.0, buffer-layout@^1.2.2: - version "1.2.2" - resolved "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz" - integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== - -buffer-xor@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" - integrity sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ== - -buffer@^6.0.3, buffer@~6.0.3, buffer@6.0.3: - version "6.0.3" - resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" - integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -bufferutil@^4.0.1, bufferutil@^4.0.3: - version "4.0.8" - resolved "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.8.tgz" - integrity sha512-4T53u4PdgsXqKaIctwF8ifXlRTTmEPJ8iEPWFdGZvcf7sbwYo6FKFEX9eNNAnzFZ7EzJAQ3CJeOtCRA4rDp7Pw== - dependencies: - node-gyp-build "^4.3.0" - -builtin-modules@^3.3.0: - version "3.3.0" - resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz" - integrity sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw== - -builtins@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz" - integrity sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ== - dependencies: - semver "^7.0.0" - -call-bind@^1.0.2, call-bind@^1.0.5, call-bind@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/call-bind/-/call-bind-1.0.6.tgz" - integrity sha512-Mj50FLHtlsoVfRfnHaZvyrooHcrlceNZdL/QBvJJVd9Ta55qCQK0gs4ss2oZDeV9zFCs6ewzYgVE5yfVmfFpVg== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.3" - set-function-length "^1.2.0" - -callsites@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" - integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== - -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0, camelcase@^6.3.0: - version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" - integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== - -capability@^0.2.5: - version "0.2.5" - resolved "https://registry.npmjs.org/capability/-/capability-0.2.5.tgz" - integrity sha512-rsJZYVCgXd08sPqwmaIqjAd5SUTfonV0z/gDJ8D6cN8wQphky1kkAYEqQ+hmDxTw7UihvBfjUVUSY+DBEe44jg== - -chai@^4.3.4: - version "4.4.1" - resolved "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz" - integrity sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.3" - deep-eql "^4.1.3" - get-func-name "^2.0.2" - loupe "^2.3.6" - pathval "^1.1.1" - type-detect "^4.0.8" - -chalk@^2.4.1: - version "2.4.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -chalk@^4.0.0, chalk@^4.1.0: - version "4.1.2" - resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" - integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== - dependencies: - ansi-styles "^4.1.0" - supports-color "^7.1.0" - -check-error@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz" - integrity sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg== - dependencies: - get-func-name "^2.0.2" - -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== - dependencies: - anymatch "~3.1.2" - braces "~3.0.2" - glob-parent "~5.1.2" - is-binary-path "~2.1.0" - is-glob "~4.0.1" - normalize-path "~3.0.0" - readdirp "~3.6.0" - optionalDependencies: - fsevents "~2.3.2" - -cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" - integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -cliui@^7.0.2: - version "7.0.4" - resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" - integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== - dependencies: - string-width "^4.2.0" - strip-ansi "^6.0.0" - wrap-ansi "^7.0.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-convert@^2.0.1: - version "2.0.1" - resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" - integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== - dependencies: - color-name "~1.1.4" - -color-name@~1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" - integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" - integrity sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw== - -combined-stream@^1.0.8: - version "1.0.8" - resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@^2.20.3: - version "2.20.3" - resolved "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" - integrity sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg== - -copyfiles@^2.4.1: - version "2.4.1" - resolved "https://registry.npmjs.org/copyfiles/-/copyfiles-2.4.1.tgz" - integrity sha512-fereAvAvxDrQDOXybk3Qu3dPbOoKoysFMWtkY3mv5BsL8//OSZVL5DCLYqgRfY5cWirgRzlC+WSrxp6Bo3eNZg== - dependencies: - glob "^7.0.5" - minimatch "^3.0.3" - mkdirp "^1.0.4" - noms "0.0.0" - through2 "^2.0.1" - untildify "^4.0.0" - yargs "^16.1.0" - -core-util-is@~1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz" - integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ== - -cosmjs-types@^0.7.1: - version "0.7.2" - resolved "https://registry.npmjs.org/cosmjs-types/-/cosmjs-types-0.7.2.tgz" - integrity sha512-vf2uLyktjr/XVAgEq0DjMxeAWh1yYREe7AMHDKd7EiHVqxBPCaBS+qEEQUkXbR9ndnckqr1sUG8BQhazh4X5lA== - dependencies: - long "^4.0.0" - protobufjs "~6.11.2" - -crc-32@^1.2.0: - version "1.2.2" - resolved "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz" - integrity sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ== - -create-hash@^1.1.0, create-hash@^1.1.2, create-hash@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" - integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== - dependencies: - cipher-base "^1.0.1" - inherits "^2.0.1" - md5.js "^1.3.4" - ripemd160 "^2.0.1" - sha.js "^2.4.0" - -create-hmac@^1.1.4, create-hmac@^1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" - integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== - dependencies: - cipher-base "^1.0.3" - create-hash "^1.1.0" - inherits "^2.0.1" - ripemd160 "^2.0.0" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -cross-fetch@^3.1.5: - version "3.1.8" - resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz" - integrity sha512-cvA+JwZoU0Xq+h6WkMvAUqPEYy92Obet6UdKLfW60qn99ftItKjB5T+BkyWOFWe2pUyfQ+IJHmpOTznqk1M6Kg== - dependencies: - node-fetch "^2.6.12" - -cross-spawn@^7.0.2: - version "7.0.3" - resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" - integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== - dependencies: - path-key "^3.1.0" - shebang-command "^2.0.0" - which "^2.0.1" - -crypto-addr-codec@^0.1.7: - version "0.1.8" - resolved "https://registry.npmjs.org/crypto-addr-codec/-/crypto-addr-codec-0.1.8.tgz" - integrity sha512-GqAK90iLLgP3FvhNmHbpT3wR6dEdaM8hZyZtLX29SPardh3OA13RFLHDR6sntGCgRWOfiHqW6sIyohpNqOtV/g== - dependencies: - base-x "^3.0.8" - big-integer "1.6.36" - blakejs "^1.1.0" - bs58 "^4.0.1" - ripemd160-min "0.0.6" - safe-buffer "^5.2.0" - sha3 "^2.1.1" - -crypto-hash@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/crypto-hash/-/crypto-hash-1.3.0.tgz" - integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== - -debug@^3.2.7: - version "3.2.7" - resolved "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz" - integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== - dependencies: - ms "^2.1.1" - -debug@^4.3.1, debug@^4.3.2, debug@4.3.3: - version "4.3.3" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== - dependencies: - ms "2.1.2" - -debug@^4.3.4: - version "4.3.4" - resolved "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz" - integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== - dependencies: - ms "2.1.2" - -decamelize@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/decamelize/-/decamelize-4.0.0.tgz" - integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== - -decimal.js@^10.2.1: - version "10.4.3" - resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz" - integrity sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA== - -deep-eql@^4.1.3: - version "4.1.3" - resolved "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz" - integrity sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw== - dependencies: - type-detect "^4.0.0" - -deep-is@^0.1.3: - version "0.1.4" - resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz" - integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== - -define-data-property@^1.0.1, define-data-property@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.2.tgz" - integrity sha512-SRtsSqsDbgpJBbW3pABMCOt6rQyeM8s8RiyeSN8jYG8sYmt/kGJejbydttUsnDs1tadr19tvhT4ShwMyoqAm4g== - dependencies: - es-errors "^1.3.0" - get-intrinsic "^1.2.2" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" - -define-properties@^1.1.3, define-properties@^1.2.0, define-properties@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz" - integrity sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg== - dependencies: - define-data-property "^1.0.1" - has-property-descriptors "^1.0.0" - object-keys "^1.1.1" - -delay@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz" - integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" - integrity sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ== - -depd@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz" - integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" - integrity sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ== - -diff@^3.1.0: - version "3.5.0" - resolved "https://registry.npmjs.org/diff/-/diff-3.5.0.tgz" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== - -diff@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/diff/-/diff-5.0.0.tgz" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - -doctrine@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz" - integrity sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw== - dependencies: - esutils "^2.0.2" - -doctrine@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz" - integrity sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w== - dependencies: - esutils "^2.0.2" - -dot-case@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/dot-case/-/dot-case-3.0.4.tgz" - integrity sha512-Kv5nKlh6yRrdrGvxeJ2e5y2eRUpkUosIW4A2AS38zwSz27zu7ufDwQPi5Jhs3XAlGNetl3bmnGhQsMtkKJnj3w== - dependencies: - no-case "^3.0.4" - tslib "^2.0.3" - -drbg.js@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz" - integrity sha512-F4wZ06PvqxYLFEZKkFxTDcns9oFNk34hvmJSEwdzsxVQ8YI5YaxtACgQatkYgv2VI2CFkUd2Y+xosPQnHv809g== - dependencies: - browserify-aes "^1.0.6" - create-hash "^1.1.2" - create-hmac "^1.1.4" - -eccrypto@1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/eccrypto/-/eccrypto-1.1.6.tgz" - integrity sha512-d78ivVEzu7Tn0ZphUUaL43+jVPKTMPFGtmgtz1D0LrFn7cY3K8CdrvibuLz2AAkHBLKZtR8DMbB2ukRYFk987A== - dependencies: - acorn "7.1.1" - elliptic "6.5.4" - es6-promise "4.2.8" - nan "2.14.0" - optionalDependencies: - secp256k1 "3.7.1" - -elliptic@^6.4.0, elliptic@^6.4.1, elliptic@^6.5.2, elliptic@^6.5.4, elliptic@6.5.4: - version "6.5.4" - resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - -emoji-regex@^8.0.0: - version "8.0.0" - resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" - integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== - -error-polyfill@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/error-polyfill/-/error-polyfill-0.1.3.tgz" - integrity sha512-XHJk60ufE+TG/ydwp4lilOog549iiQF2OAPhkk9DdiYWMrltz5yhDz/xnKuenNwP7gy3dsibssO5QpVhkrSzzg== - dependencies: - capability "^0.2.5" - o3 "^1.0.3" - u3 "^0.1.1" - -es-abstract@^1.22.1, es-abstract@^1.22.3: - version "1.22.3" - resolved "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.3.tgz" - integrity sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA== - dependencies: - array-buffer-byte-length "^1.0.0" - arraybuffer.prototype.slice "^1.0.2" - available-typed-arrays "^1.0.5" - call-bind "^1.0.5" - es-set-tostringtag "^2.0.1" - es-to-primitive "^1.2.1" - function.prototype.name "^1.1.6" - get-intrinsic "^1.2.2" - get-symbol-description "^1.0.0" - globalthis "^1.0.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.0" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - internal-slot "^1.0.5" - is-array-buffer "^3.0.2" - is-callable "^1.2.7" - is-negative-zero "^2.0.2" - is-regex "^1.1.4" - is-shared-array-buffer "^1.0.2" - is-string "^1.0.7" - is-typed-array "^1.1.12" - is-weakref "^1.0.2" - object-inspect "^1.13.1" - object-keys "^1.1.1" - object.assign "^4.1.4" - regexp.prototype.flags "^1.5.1" - safe-array-concat "^1.0.1" - safe-regex-test "^1.0.0" - string.prototype.trim "^1.2.8" - string.prototype.trimend "^1.0.7" - string.prototype.trimstart "^1.0.7" - typed-array-buffer "^1.0.0" - typed-array-byte-length "^1.0.0" - typed-array-byte-offset "^1.0.0" - typed-array-length "^1.0.4" - unbox-primitive "^1.0.2" - which-typed-array "^1.1.13" - -es-array-method-boxes-properly@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/es-array-method-boxes-properly/-/es-array-method-boxes-properly-1.0.0.tgz" - integrity sha512-wd6JXUmyHmt8T5a2xreUwKcGPq6f1f+WwIJkijUqiGcJz1qqnZgP6XIK+QyIWU5lT7imeNxUll48bziG+TSYcA== - -es-errors@^1.0.0, es-errors@^1.2.1, es-errors@^1.3.0: - version "1.3.0" - resolved "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz" - integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== - -es-set-tostringtag@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.2.tgz" - integrity sha512-BuDyupZt65P9D2D2vA/zqcI3G5xRsklm5N3xCwuiy+/vKy8i0ifdsQP1sLgO4tZDSCaQUSnmC48khknGMV3D2Q== - dependencies: - get-intrinsic "^1.2.2" - has-tostringtag "^1.0.0" - hasown "^2.0.0" - -es-shim-unscopables@^1.0.0, es-shim-unscopables@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.0.2.tgz" - integrity sha512-J3yBRXCzDu4ULnQwxyToo/OjdMx6akgVC7K6few0a7F/0wLtmKKN7I73AH5T2836UuXRqN7Qg+IIUw/+YJksRw== - dependencies: - hasown "^2.0.0" - -es-to-primitive@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz" - integrity sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-promise@^4.0.3, es6-promise@4.2.8: - version "4.2.8" - resolved "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== - -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz" - integrity sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ== - dependencies: - es6-promise "^4.0.3" - -escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" - integrity sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg== - -escape-string-regexp@^4.0.0, escape-string-regexp@4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" - integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== - -eslint-compat-utils@^0.1.2: - version "0.1.2" - resolved "https://registry.npmjs.org/eslint-compat-utils/-/eslint-compat-utils-0.1.2.tgz" - integrity sha512-Jia4JDldWnFNIru1Ehx1H5s9/yxiRHY/TimCuUc0jNexew3cF1gI6CYZil1ociakfWO3rRqFjl1mskBblB3RYg== - -eslint-config-standard-with-typescript@^43.0.1: - version "43.0.1" - resolved "https://registry.npmjs.org/eslint-config-standard-with-typescript/-/eslint-config-standard-with-typescript-43.0.1.tgz" - integrity sha512-WfZ986+qzIzX6dcr4yGUyVb/l9N3Z8wPXCc5z/70fljs3UbWhhV+WxrfgsqMToRzuuyX9MqZ974pq2UPhDTOcA== - dependencies: - "@typescript-eslint/parser" "^6.4.0" - eslint-config-standard "17.1.0" - -eslint-config-standard@17.1.0: - version "17.1.0" - resolved "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-17.1.0.tgz" - integrity sha512-IwHwmaBNtDK4zDHQukFDW5u/aTb8+meQWZvNFWkiGmbWjD6bqyuSSBxxXKkCftCUzc1zwCH2m/baCNDLGmuO5Q== - -eslint-import-resolver-node@^0.3.9: - version "0.3.9" - resolved "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.9.tgz" - integrity sha512-WFj2isz22JahUv+B788TlO3N6zL3nNJGU8CcZbPZvVEkBPaJdCV4vy5wyghty5ROFbCRnm132v8BScu5/1BQ8g== - dependencies: - debug "^3.2.7" - is-core-module "^2.13.0" - resolve "^1.22.4" - -eslint-module-utils@^2.8.0: - version "2.8.0" - resolved "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.8.0.tgz" - integrity sha512-aWajIYfsqCKRDgUfjEXNN/JlrzauMuSEy5sbd7WXbtW3EH6A6MpwEh42c7qD+MqQo9QMJ6fWLAeIJynx0g6OAw== - dependencies: - debug "^3.2.7" - -eslint-plugin-es-x@^7.5.0: - version "7.5.0" - resolved "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.5.0.tgz" - integrity sha512-ODswlDSO0HJDzXU0XvgZ3lF3lS3XAZEossh15Q2UHjwrJggWeBoKqqEsLTZLXl+dh5eOAozG0zRcYtuE35oTuQ== - dependencies: - "@eslint-community/eslint-utils" "^4.1.2" - "@eslint-community/regexpp" "^4.6.0" - eslint-compat-utils "^0.1.2" - -eslint-plugin-import@^2.25.2, eslint-plugin-import@^2.29.1: - version "2.29.1" - resolved "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.29.1.tgz" - integrity sha512-BbPC0cuExzhiMo4Ff1BTVwHpjjv28C5R+btTOGaCRC7UEz801up0JadwkeSk5Ued6TG34uaczuVuH6qyy5YUxw== - dependencies: - array-includes "^3.1.7" - array.prototype.findlastindex "^1.2.3" - array.prototype.flat "^1.3.2" - array.prototype.flatmap "^1.3.2" - debug "^3.2.7" - doctrine "^2.1.0" - eslint-import-resolver-node "^0.3.9" - eslint-module-utils "^2.8.0" - hasown "^2.0.0" - is-core-module "^2.13.1" - is-glob "^4.0.3" - minimatch "^3.1.2" - object.fromentries "^2.0.7" - object.groupby "^1.0.1" - object.values "^1.1.7" - semver "^6.3.1" - tsconfig-paths "^3.15.0" - -"eslint-plugin-n@^15.0.0 || ^16.0.0 ", eslint-plugin-n@^16.6.2: - version "16.6.2" - resolved "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-16.6.2.tgz" - integrity sha512-6TyDmZ1HXoFQXnhCTUjVFULReoBPOAjpuiKELMkeP40yffI/1ZRO+d9ug/VC6fqISo2WkuIBk3cvuRPALaWlOQ== - dependencies: - "@eslint-community/eslint-utils" "^4.4.0" - builtins "^5.0.1" - eslint-plugin-es-x "^7.5.0" - get-tsconfig "^4.7.0" - globals "^13.24.0" - ignore "^5.2.4" - is-builtin-module "^3.2.1" - is-core-module "^2.12.1" - minimatch "^3.1.2" - resolve "^1.22.2" - semver "^7.5.3" - -eslint-plugin-promise@^6.0.0, eslint-plugin-promise@^6.1.1: - version "6.1.1" - resolved "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.1.1.tgz" - integrity sha512-tjqWDwVZQo7UIPMeDReOpUgHCmCiH+ePnVT+5zVapL0uuHnegBUs2smM13CzOs2Xb5+MHMRFTs9v24yjba4Oig== - -eslint-scope@^7.2.2: - version "7.2.2" - resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz" - integrity sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg== - dependencies: - esrecurse "^4.3.0" - estraverse "^5.2.0" - -eslint-visitor-keys@^3.3.0, eslint-visitor-keys@^3.4.1, eslint-visitor-keys@^3.4.3: - version "3.4.3" - resolved "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz" - integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== - -eslint@*, "eslint@^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8", "eslint@^6.0.0 || ^7.0.0 || >=8.0.0", "eslint@^7.0.0 || ^8.0.0", eslint@^8.0.1, eslint@^8.56.0, eslint@>=6.0.0, eslint@>=7.0.0, eslint@>=8, eslint@>=8.40.0: - version "8.56.0" - resolved "https://registry.npmjs.org/eslint/-/eslint-8.56.0.tgz" - integrity sha512-Go19xM6T9puCOWntie1/P997aXxFsOi37JIHRWI514Hc6ZnaHGKY9xFhrU65RT6CcBEzZoGG1e6Nq+DT04ZtZQ== - dependencies: - "@eslint-community/eslint-utils" "^4.2.0" - "@eslint-community/regexpp" "^4.6.1" - "@eslint/eslintrc" "^2.1.4" - "@eslint/js" "8.56.0" - "@humanwhocodes/config-array" "^0.11.13" - "@humanwhocodes/module-importer" "^1.0.1" - "@nodelib/fs.walk" "^1.2.8" - "@ungap/structured-clone" "^1.2.0" - ajv "^6.12.4" - chalk "^4.0.0" - cross-spawn "^7.0.2" - debug "^4.3.2" - doctrine "^3.0.0" - escape-string-regexp "^4.0.0" - eslint-scope "^7.2.2" - eslint-visitor-keys "^3.4.3" - espree "^9.6.1" - esquery "^1.4.2" - esutils "^2.0.2" - fast-deep-equal "^3.1.3" - file-entry-cache "^6.0.1" - find-up "^5.0.0" - glob-parent "^6.0.2" - globals "^13.19.0" - graphemer "^1.4.0" - ignore "^5.2.0" - imurmurhash "^0.1.4" - is-glob "^4.0.0" - is-path-inside "^3.0.3" - js-yaml "^4.1.0" - json-stable-stringify-without-jsonify "^1.0.1" - levn "^0.4.1" - lodash.merge "^4.6.2" - minimatch "^3.1.2" - natural-compare "^1.4.0" - optionator "^0.9.3" - strip-ansi "^6.0.1" - text-table "^0.2.0" - -espree@^9.6.0, espree@^9.6.1: - version "9.6.1" - resolved "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz" - integrity sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ== - dependencies: - acorn "^8.9.0" - acorn-jsx "^5.3.2" - eslint-visitor-keys "^3.4.1" - -esquery@^1.4.2: - version "1.5.0" - resolved "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz" - integrity sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg== - dependencies: - estraverse "^5.1.0" - -esrecurse@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz" - integrity sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag== - dependencies: - estraverse "^5.2.0" - -estraverse@^5.1.0, estraverse@^5.2.0, estraverse@^5.3.0: - version "5.3.0" - resolved "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz" - integrity sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -eth-crypto@^2.6.0: - version "2.6.0" - resolved "https://registry.npmjs.org/eth-crypto/-/eth-crypto-2.6.0.tgz" - integrity sha512-GCX4ffFYRUGgnuWR5qxcZIRQJ1KEqPFiyXU9yVy7s6dtXIMlUXZQ2h+5ID6rFaOHWbpJbjfkC6YdhwtwRYCnug== - dependencies: - "@babel/runtime" "7.20.13" - "@ethereumjs/tx" "3.5.2" - "@types/bn.js" "5.1.1" - eccrypto "1.1.6" - ethereumjs-util "7.1.5" - ethers "5.7.2" - secp256k1 "5.0.0" - -ethereum-cryptography@^0.1.3: - version "0.1.3" - resolved "https://registry.npmjs.org/ethereum-cryptography/-/ethereum-cryptography-0.1.3.tgz" - integrity sha512-w8/4x1SGGzc+tO97TASLja6SLd3fRIK2tLVcV2Gx4IB21hE19atll5Cq9o3d0ZmAYC/8aw0ipieTSiekAea4SQ== - dependencies: - "@types/pbkdf2" "^3.0.0" - "@types/secp256k1" "^4.0.1" - blakejs "^1.1.0" - browserify-aes "^1.2.0" - bs58check "^2.1.2" - create-hash "^1.2.0" - create-hmac "^1.1.7" - hash.js "^1.1.7" - keccak "^3.0.0" - pbkdf2 "^3.0.17" - randombytes "^2.1.0" - safe-buffer "^5.1.2" - scrypt-js "^3.0.0" - secp256k1 "^4.0.1" - setimmediate "^1.0.5" - -ethereumjs-abi@^0.6.8: - version "0.6.8" - resolved "https://registry.npmjs.org/ethereumjs-abi/-/ethereumjs-abi-0.6.8.tgz" - integrity sha512-Tx0r/iXI6r+lRsdvkFDlut0N08jWMnKRZ6Gkq+Nmw75lZe4e6o3EkSnkaBP5NF6+m5PTGAr9JP43N3LyeoglsA== - dependencies: - bn.js "^4.11.8" - ethereumjs-util "^6.0.0" - -ethereumjs-util@^6.0.0: - version "6.2.1" - resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - -ethereumjs-util@^6.2.1: - version "6.2.1" - resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-6.2.1.tgz" - integrity sha512-W2Ktez4L01Vexijrm5EB6w7dg4n/TgpoYU4avuT5T3Vmnw/eCRtiBrJfQYS/DCSvDIOLn2k57GcHdeBcgVxAqw== - dependencies: - "@types/bn.js" "^4.11.3" - bn.js "^4.11.0" - create-hash "^1.1.2" - elliptic "^6.5.2" - ethereum-cryptography "^0.1.3" - ethjs-util "0.1.6" - rlp "^2.2.3" - -ethereumjs-util@^7.1.4, ethereumjs-util@^7.1.5, ethereumjs-util@7.1.5: - version "7.1.5" - resolved "https://registry.npmjs.org/ethereumjs-util/-/ethereumjs-util-7.1.5.tgz" - integrity sha512-SDl5kKrQAudFBUe5OJM9Ac6WmMyYmXX/6sTmLZ3ffG2eY6ZIGBes3pEDxNN6V72WyOw4CPD5RomKdsa8DAAwLg== - dependencies: - "@types/bn.js" "^5.1.0" - bn.js "^5.1.2" - create-hash "^1.1.2" - ethereum-cryptography "^0.1.3" - rlp "^2.2.4" - -ethers@^5.7.2, ethers@5.7.2: - version "5.7.2" - resolved "https://registry.npmjs.org/ethers/-/ethers-5.7.2.tgz" - integrity sha512-wswUsmWo1aOK8rR7DIKiWSw9DbLWe6x98Jrn8wcTflTVvaXhAMaB5zGAXy0GYQEQp9iO1iSHWVyARQm11zUtyg== - dependencies: - "@ethersproject/abi" "5.7.0" - "@ethersproject/abstract-provider" "5.7.0" - "@ethersproject/abstract-signer" "5.7.0" - "@ethersproject/address" "5.7.0" - "@ethersproject/base64" "5.7.0" - "@ethersproject/basex" "5.7.0" - "@ethersproject/bignumber" "5.7.0" - "@ethersproject/bytes" "5.7.0" - "@ethersproject/constants" "5.7.0" - "@ethersproject/contracts" "5.7.0" - "@ethersproject/hash" "5.7.0" - "@ethersproject/hdnode" "5.7.0" - "@ethersproject/json-wallets" "5.7.0" - "@ethersproject/keccak256" "5.7.0" - "@ethersproject/logger" "5.7.0" - "@ethersproject/networks" "5.7.1" - "@ethersproject/pbkdf2" "5.7.0" - "@ethersproject/properties" "5.7.0" - "@ethersproject/providers" "5.7.2" - "@ethersproject/random" "5.7.0" - "@ethersproject/rlp" "5.7.0" - "@ethersproject/sha2" "5.7.0" - "@ethersproject/signing-key" "5.7.0" - "@ethersproject/solidity" "5.7.0" - "@ethersproject/strings" "5.7.0" - "@ethersproject/transactions" "5.7.0" - "@ethersproject/units" "5.7.0" - "@ethersproject/wallet" "5.7.0" - "@ethersproject/web" "5.7.1" - "@ethersproject/wordlists" "5.7.0" - -ethjs-util@^0.1.6, ethjs-util@0.1.6: - version "0.1.6" - resolved "https://registry.npmjs.org/ethjs-util/-/ethjs-util-0.1.6.tgz" - integrity sha512-CUnVOQq7gSpDHZVVrQW8ExxUETWrnrvXYvYz55wOU8Uj4VCgw56XC2B/fVqQN+f7gmrnRHSLVnFAwsCuNwji8w== - dependencies: - is-hex-prefixed "1.0.0" - strip-hex-prefix "1.0.0" - -eventemitter3@^4.0.7: - version "4.0.7" - resolved "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - -evp_bytestokey@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" - integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== - dependencies: - md5.js "^1.3.4" - safe-buffer "^5.1.1" - -eyes@^0.1.8: - version "0.1.8" - resolved "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz" - integrity sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ== - -fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: - version "3.1.3" - resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" - integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== - -fast-glob@^3.2.9: - version "3.3.2" - resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== - dependencies: - "@nodelib/fs.stat" "^2.0.2" - "@nodelib/fs.walk" "^1.2.3" - glob-parent "^5.1.2" - merge2 "^1.3.0" - micromatch "^4.0.4" - -fast-json-stable-stringify@^2.0.0: - version "2.1.0" - resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" - integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== - -fast-levenshtein@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" - integrity sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw== - -fast-stable-stringify@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz" - integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== - -fastestsmallesttextencoderdecoder@^1.0.22: - version "1.0.22" - resolved "https://registry.npmjs.org/fastestsmallesttextencoderdecoder/-/fastestsmallesttextencoderdecoder-1.0.22.tgz" - integrity sha512-Pb8d48e+oIuY4MaM64Cd7OW1gt4nxCHs7/ddPPZ/Ic3sg8yVGM7O9wDvZ7us6ScaUupzM+pfBolwtYhN1IxBIw== - -fastq@^1.6.0: - version "1.17.1" - resolved "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz" - integrity sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w== - dependencies: - reusify "^1.0.4" - -file-entry-cache@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz" - integrity sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg== - dependencies: - flat-cache "^3.0.4" - -file-uri-to-path@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz" - integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== - -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== - dependencies: - to-regex-range "^5.0.1" - -find-up@^5.0.0, find-up@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz" - integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== - dependencies: - locate-path "^6.0.0" - path-exists "^4.0.0" - -flat-cache@^3.0.4: - version "3.2.0" - resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz" - integrity sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw== - dependencies: - flatted "^3.2.9" - keyv "^4.5.3" - rimraf "^3.0.2" - -flat@^5.0.2: - version "5.0.2" - resolved "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz" - integrity sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ== - -flatted@^3.2.9: - version "3.2.9" - resolved "https://registry.npmjs.org/flatted/-/flatted-3.2.9.tgz" - integrity sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ== - -follow-redirects@^1.14.0, follow-redirects@^1.14.4, follow-redirects@^1.14.8, follow-redirects@^1.14.9: - version "1.15.5" - resolved "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz" - integrity sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw== - -for-each@^0.3.3: - version "0.3.3" - resolved "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz" - integrity sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw== - dependencies: - is-callable "^1.1.3" - -form-data@^4.0.0, form-data@4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz" - integrity sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.8" - mime-types "^2.1.12" - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" - integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== - -fsevents@~2.3.2: - version "2.3.3" - resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz" - integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== - -function-bind@^1.1.2: - version "1.1.2" - resolved "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz" - integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== - -function.prototype.name@^1.1.6: - version "1.1.6" - resolved "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz" - integrity sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - functions-have-names "^1.2.3" - -functions-have-names@^1.2.3: - version "1.2.3" - resolved "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz" - integrity sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ== - -get-caller-file@^2.0.5: - version "2.0.5" - resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" - integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== - -get-func-name@^2.0.1, get-func-name@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz" - integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== - -get-intrinsic@^1.1.3, get-intrinsic@^1.2.1, get-intrinsic@^1.2.2, get-intrinsic@^1.2.3, get-intrinsic@^1.2.4: - version "1.2.4" - resolved "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz" - integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ== - dependencies: - es-errors "^1.3.0" - function-bind "^1.1.2" - has-proto "^1.0.1" - has-symbols "^1.0.3" - hasown "^2.0.0" - -get-symbol-description@^1.0.0: - version "1.0.2" - resolved "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz" - integrity sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg== - dependencies: - call-bind "^1.0.5" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - -get-tsconfig@^4.7.0: - version "4.7.2" - resolved "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.7.2.tgz" - integrity sha512-wuMsz4leaj5hbGgg4IvDU0bqJagpftG5l5cXIAvo8uZrqn0NJqwtfupTN00VnkQJPcIRrxYrm1Ue24btpCha2A== - dependencies: - resolve-pkg-maps "^1.0.0" - -glob-parent@^5.1.2, glob-parent@~5.1.2: - version "5.1.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" - integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== - dependencies: - is-glob "^4.0.1" - -glob-parent@^6.0.2: - version "6.0.2" - resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz" - integrity sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A== - dependencies: - is-glob "^4.0.3" - -glob@^7.0.0, glob@^7.0.5, glob@^7.1.3, glob@7.2.0: - version "7.2.0" - resolved "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -globals@^13.19.0, globals@^13.24.0: - version "13.24.0" - resolved "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz" - integrity sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ== - dependencies: - type-fest "^0.20.2" - -globalthis@^1.0.1, globalthis@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/globalthis/-/globalthis-1.0.3.tgz" - integrity sha512-sFdI5LyBiNTHjRd7cGPWapiHWMOXKyuBNX/cWJ3NfzrZQVa8GI/8cofCl74AOVqq9W5kNmguTIzJ/1s2gyI9wA== - dependencies: - define-properties "^1.1.3" - -globby@^11.1.0: - version "11.1.0" - resolved "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - -google-protobuf@^3.14.0, google-protobuf@^3.17.3, google-protobuf@^3.21.0: - version "3.21.2" - resolved "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.21.2.tgz" - integrity sha512-3MSOYFO5U9mPGikIYCzK0SaThypfGgS6bHqrUGXG3DPHCrb+txNqeEcns1W0lkGfk0rCyNXm7xB9rMxnCiZOoA== - -gopd@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz" - integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA== - dependencies: - get-intrinsic "^1.1.3" - -graphemer@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz" - integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== - -graphql-tag@^2.12.6: - version "2.12.6" - resolved "https://registry.npmjs.org/graphql-tag/-/graphql-tag-2.12.6.tgz" - integrity sha512-FdSNcu2QQcWnM2VNvSCCDCVS5PpPqpzgFT8+GXzqJuoDd0CBncxCY278u4mhRO7tMgo2JjgJA5aZ+nWSQ/Z+xg== - dependencies: - tslib "^2.1.0" - -"graphql@^0.8.0 || ^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0 || ^17.0.0", "graphql@^0.9.0 || ^0.10.0 || ^0.11.0 || ^0.12.0 || ^0.13.0 || ^14.0.0 || ^15.0.0 || ^16.0.0", "graphql@^15.0.0 || ^16.0.0", graphql@^16.3.0: - version "16.8.1" - resolved "https://registry.npmjs.org/graphql/-/graphql-16.8.1.tgz" - integrity sha512-59LZHPdGZVh695Ud9lRzPBVTtlX9ZCV150Er2W43ro37wVof0ctenSaskPPjN7lVTIN8mSZt8PHUNKZuNQUuxw== - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.npmjs.org/growl/-/growl-1.10.5.tgz" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== - -has-bigints@^1.0.1, has-bigints@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz" - integrity sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ== - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" - integrity sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw== - -has-flag@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" - integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== - -has-property-descriptors@^1.0.0, has-property-descriptors@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.1.tgz" - integrity sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg== - dependencies: - get-intrinsic "^1.2.2" - -has-proto@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz" - integrity sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg== - -has-symbols@^1.0.2, has-symbols@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz" - integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== - -has-tostringtag@^1.0.0, has-tostringtag@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz" - integrity sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw== - dependencies: - has-symbols "^1.0.3" - -hash-base@^3.0.0: - version "3.1.0" - resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz" - integrity sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA== - dependencies: - inherits "^2.0.4" - readable-stream "^3.6.0" - safe-buffer "^5.2.0" - -hash.js@^1.0.0, hash.js@^1.0.3, hash.js@^1.1.7, hash.js@1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -hasown@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz" - integrity sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA== - dependencies: - function-bind "^1.1.2" - -he@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/he/-/he-1.2.0.tgz" - integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== - -hi-base32@^0.5.1: - version "0.5.1" - resolved "https://registry.npmjs.org/hi-base32/-/hi-base32-0.5.1.tgz" - integrity sha512-EmBBpvdYh/4XxsnUybsPag6VikPYnN30td+vQk+GI3qpahVEG9+gTkG0aXVxTjBqQ5T6ijbWIu77O+C5WFWsnA== - -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" - integrity sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg== - dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" - -hoist-non-react-statics@^3.3.2: - version "3.3.2" - resolved "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz" - integrity sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw== - dependencies: - react-is "^16.7.0" - -http-errors@^1.7.2: - version "1.8.1" - resolved "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz" - integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.2.0" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.1" - -http-status-codes@^2.2.0: - version "2.3.0" - resolved "https://registry.npmjs.org/http-status-codes/-/http-status-codes-2.3.0.tgz" - integrity sha512-RJ8XvFvpPM/Dmc5SV+dC4y5PCeOhT3x1Hq0NU3rjGeg5a/CqlhZ7uudknPwZFz4aeAXDcbAyaeP7GAo9lvngtA== - -humanize-ms@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" - integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== - dependencies: - ms "^2.0.0" - -ieee754@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" - integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== - -ignore@^5.2.0, ignore@^5.2.4: - version "5.3.1" - resolved "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz" - integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== - -import-fresh@^3.2.1: - version "3.3.0" - resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" - integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== - dependencies: - parent-module "^1.0.0" - resolve-from "^4.0.0" - -imurmurhash@^0.1.4: - version "0.1.4" - resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" - integrity sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA== - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" - integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3, inherits@2, inherits@2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -internal-slot@^1.0.5: - version "1.0.7" - resolved "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz" - integrity sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g== - dependencies: - es-errors "^1.3.0" - hasown "^2.0.0" - side-channel "^1.0.4" - -interpret@^1.0.0: - version "1.4.0" - resolved "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz" - integrity sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA== - -is-array-buffer@^3.0.2, is-array-buffer@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz" - integrity sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw== - dependencies: - call-bind "^1.0.2" - get-intrinsic "^1.2.1" - -is-bigint@^1.0.1: - version "1.0.4" - resolved "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz" - integrity sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg== - dependencies: - has-bigints "^1.0.1" - -is-binary-path@~2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" - integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== - dependencies: - binary-extensions "^2.0.0" - -is-boolean-object@^1.1.0: - version "1.1.2" - resolved "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz" - integrity sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-builtin-module@^3.2.1: - version "3.2.1" - resolved "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz" - integrity sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A== - dependencies: - builtin-modules "^3.3.0" - -is-callable@^1.1.3, is-callable@^1.1.4, is-callable@^1.2.7: - version "1.2.7" - resolved "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz" - integrity sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA== - -is-core-module@^2.12.1, is-core-module@^2.13.0, is-core-module@^2.13.1: - version "2.13.1" - resolved "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz" - integrity sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw== - dependencies: - hasown "^2.0.0" - -is-date-object@^1.0.1: - version "1.0.5" - resolved "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz" - integrity sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ== - dependencies: - has-tostringtag "^1.0.0" - -is-extglob@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" - integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== - -is-fullwidth-code-point@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" - integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== - -is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: - version "4.0.3" - resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz" - integrity sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg== - dependencies: - is-extglob "^2.1.1" - -is-hex-prefixed@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/is-hex-prefixed/-/is-hex-prefixed-1.0.0.tgz" - integrity sha512-WvtOiug1VFrE9v1Cydwm+FnXd3+w9GaeVUss5W4v/SLy3UW00vP+6iNF2SdnfiBoLy4bTqVdkftNGTUeOFVsbA== - -is-negative-zero@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz" - integrity sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA== - -is-number-object@^1.0.4: - version "1.0.7" - resolved "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz" - integrity sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ== - dependencies: - has-tostringtag "^1.0.0" - -is-number@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" - integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== - -is-path-inside@^3.0.3: - version "3.0.3" - resolved "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz" - integrity sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ== - -is-plain-obj@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - -is-regex@^1.1.4: - version "1.1.4" - resolved "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz" - integrity sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg== - dependencies: - call-bind "^1.0.2" - has-tostringtag "^1.0.0" - -is-shared-array-buffer@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.2.tgz" - integrity sha512-sqN2UDu1/0y6uvXyStCOzyhAjCSlHceFoMKJW8W9EU9cvic/QdsZ0kEU93HEy3IUEFZIiH/3w+AH/UQbPHNdhA== - dependencies: - call-bind "^1.0.2" - -is-string@^1.0.5, is-string@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz" - integrity sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg== - dependencies: - has-tostringtag "^1.0.0" - -is-symbol@^1.0.2, is-symbol@^1.0.3: - version "1.0.4" - resolved "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz" - integrity sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg== - dependencies: - has-symbols "^1.0.2" - -is-typed-array@^1.1.10, is-typed-array@^1.1.12, is-typed-array@^1.1.13, is-typed-array@^1.1.9: - version "1.1.13" - resolved "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz" - integrity sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw== - dependencies: - which-typed-array "^1.1.14" - -is-unicode-supported@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" - integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== - -is-weakref@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz" - integrity sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ== - dependencies: - call-bind "^1.0.2" - -isarray@^2.0.5: - version "2.0.5" - resolved "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz" - integrity sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw== - -isarray@~1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" - integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== - -isarray@0.0.1: - version "0.0.1" - resolved "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz" - integrity sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ== - -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" - integrity sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw== - -isomorphic-ws@^4.0.1: - version "4.0.1" - resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz" - integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== - -jayson@^4.0.0, jayson@^4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/jayson/-/jayson-4.1.0.tgz" - integrity sha512-R6JlbyLN53Mjku329XoRT2zJAE6ZgOQ8f91ucYdMCD4nkGCF9kZSrcGXpHIU4jeKj58zUZke2p+cdQchU7Ly7A== - dependencies: - "@types/connect" "^3.4.33" - "@types/node" "^12.12.54" - "@types/ws" "^7.4.4" - commander "^2.20.3" - delay "^5.0.0" - es6-promisify "^5.0.0" - eyes "^0.1.8" - isomorphic-ws "^4.0.1" - json-stringify-safe "^5.0.1" - JSONStream "^1.3.5" - uuid "^8.3.2" - ws "^7.4.5" - -js-base64@^3.6.1: - version "3.7.6" - resolved "https://registry.npmjs.org/js-base64/-/js-base64-3.7.6.tgz" - integrity sha512-NPrWuHFxFUknr1KqJRDgUQPexQF0uIJWjeT+2KjEePhitQxQEx5EJBG1lVn5/hc8aLycTpXrDOgPQ6Zq+EDiTA== - -js-sha256@^0.9.0: - version "0.9.0" - resolved "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz" - integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== - -js-sha3@^0.8.0, js-sha3@0.8.0: - version "0.8.0" - resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-sha512@^0.8.0: - version "0.8.0" - resolved "https://registry.npmjs.org/js-sha512/-/js-sha512-0.8.0.tgz" - integrity sha512-PWsmefG6Jkodqt+ePTvBZCSMFgN7Clckjd0O7su3I0+BW2QWUTJNzjktHsztGLhncP2h8mcF9V9Y2Ha59pAViQ== - -"js-tokens@^3.0.0 || ^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^4.1.0, js-yaml@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz" - integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== - dependencies: - argparse "^2.0.1" - -jscrypto@^1.0.1, jscrypto@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/jscrypto/-/jscrypto-1.0.3.tgz" - integrity sha512-lryZl0flhodv4SZHOqyb1bx5sKcJxj0VBo0Kzb4QMAg3L021IC9uGpl0RCZa+9KJwlRGSK2C80ITcwbe19OKLQ== - -json-bigint@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/json-bigint/-/json-bigint-1.0.0.tgz" - integrity sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ== - dependencies: - bignumber.js "^9.0.0" - -json-buffer@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz" - integrity sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ== - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-stable-stringify-without-jsonify@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz" - integrity sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw== - -json-stringify-safe@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" - integrity sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA== - -json5@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - -jsonparse@^1.2.0: - version "1.3.1" - resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz" - integrity sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg== - -jsonschema@^1.4.0: - version "1.4.1" - resolved "https://registry.npmjs.org/jsonschema/-/jsonschema-1.4.1.tgz" - integrity sha512-S6cATIPVv1z0IlxdN+zUk5EPjkGCdnhN4wVSBlvoUO1tOLJootbo9CquNJmbIh4yikWHiUedhRYrNPn1arpEmQ== - -JSONStream@^1.3.5: - version "1.3.5" - resolved "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - -keccak@^3.0.0, keccak@^3.0.2: - version "3.0.4" - resolved "https://registry.npmjs.org/keccak/-/keccak-3.0.4.tgz" - integrity sha512-3vKuW0jV8J3XNTzvfyicFR5qvxrSAGl7KIhvgOu5cmWwM7tZRj3fMbj/pfIf4be7aznbc+prBWGjywox/g2Y6Q== - dependencies: - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - readable-stream "^3.6.0" - -keccak256@^1.0.6: - version "1.0.6" - resolved "https://registry.npmjs.org/keccak256/-/keccak256-1.0.6.tgz" - integrity sha512-8GLiM01PkdJVGUhR1e6M/AvWnSqYS0HaERI+K/QtStGDGlSTx2B1zTqZk4Zlqu5TxHJNTxWAdP9Y+WI50OApUw== - dependencies: - bn.js "^5.2.0" - buffer "^6.0.3" - keccak "^3.0.2" - -keyv@^4.5.3: - version "4.5.4" - resolved "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz" - integrity sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw== - dependencies: - json-buffer "3.0.1" - -levn@^0.4.1: - version "0.4.1" - resolved "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz" - integrity sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ== - dependencies: - prelude-ls "^1.2.1" - type-check "~0.4.0" - -libsodium-wrappers@^0.7.6: - version "0.7.13" - resolved "https://registry.npmjs.org/libsodium-wrappers/-/libsodium-wrappers-0.7.13.tgz" - integrity sha512-kasvDsEi/r1fMzKouIDv7B8I6vNmknXwGiYodErGuESoFTohGSKZplFtVxZqHaoQ217AynyIFgnOVRitpHs0Qw== - dependencies: - libsodium "^0.7.13" - -libsodium@^0.7.13: - version "0.7.13" - resolved "https://registry.npmjs.org/libsodium/-/libsodium-0.7.13.tgz" - integrity sha512-mK8ju0fnrKXXfleL53vtp9xiPq5hKM0zbDQtcxQIsSmxNgSxqCj6R7Hl9PkrNe2j29T4yoDaF7DJLK9/i5iWUw== - -link-module-alias@^1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/link-module-alias/-/link-module-alias-1.2.0.tgz" - integrity sha512-ahPjXepbSVKbahTB6LxR//VHm8HPfI+QQygCH+E82spBY4HR5VPJTvlhKBc9F7muVxnS6C1rRfoPOXAbWO/fyw== - dependencies: - chalk "^2.4.1" - -locate-path@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz" - integrity sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw== - dependencies: - p-locate "^5.0.0" - -lodash.merge@^4.6.2: - version "4.6.2" - resolved "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz" - integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== - -lodash.values@^4.3.0: - version "4.3.0" - resolved "https://registry.npmjs.org/lodash.values/-/lodash.values-4.3.0.tgz" - integrity sha512-r0RwvdCv8id9TUblb/O7rYPwVy6lerCbcawrfdo9iC/1t1wsNMJknO79WNBgwkH0hIeJ08jmvvESbFpNb4jH0Q== - -lodash@^4.17.21: - version "4.17.21" - resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@4.1.0: - version "4.1.0" - resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" - integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== - dependencies: - chalk "^4.1.0" - is-unicode-supported "^0.1.0" - -long@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/long/-/long-4.0.0.tgz" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - -long@^5.0.0: - version "5.2.3" - resolved "https://registry.npmjs.org/long/-/long-5.2.3.tgz" - integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== - -loose-envify@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" - integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== - dependencies: - js-tokens "^3.0.0 || ^4.0.0" - -loupe@^2.3.6: - version "2.3.7" - resolved "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz" - integrity sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA== - dependencies: - get-func-name "^2.0.1" - -lower-case@^2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/lower-case/-/lower-case-2.0.2.tgz" - integrity sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg== - dependencies: - tslib "^2.0.3" - -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -map-obj@^4.1.0: - version "4.3.0" - resolved "https://registry.npmjs.org/map-obj/-/map-obj-4.3.0.tgz" - integrity sha512-hdN1wVrZbb29eBGiGjJbeP8JbKjq1urkHJ/LIP/NY48MZ1QVXUsQBV1G1zvYFHn1XE06cwjBsOI2K3Ulnj1YXQ== - -md5.js@^1.3.4: - version "1.3.5" - resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" - integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - safe-buffer "^5.1.2" - -merge2@^1.3.0, merge2@^1.4.1: - version "1.4.1" - resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" - integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== - -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== - dependencies: - braces "^3.0.2" - picomatch "^2.3.1" - -mime-db@1.52.0: - version "1.52.0" - resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz" - integrity sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg== - -mime-types@^2.1.12: - version "2.1.35" - resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz" - integrity sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw== - dependencies: - mime-db "1.52.0" - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" - integrity sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg== - -minimatch@^3.0.3: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.5: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.1.2: - version "3.1.2" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== - dependencies: - brace-expansion "^1.1.7" - -minimatch@9.0.3: - version "9.0.3" - resolved "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz" - integrity sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg== - dependencies: - brace-expansion "^2.0.1" - -minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.6: - version "1.2.8" - resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz" - integrity sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA== - -mkdirp@^0.5.1: - version "0.5.6" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz" - integrity sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw== - dependencies: - minimist "^1.2.6" - -mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -"mocha@^3.X.X || ^4.X.X || ^5.X.X || ^6.X.X || ^7.X.X || ^8.X.X || ^9.X.X || ^10.X.X", mocha@^9.0.3: - version "9.2.2" - resolved "https://registry.npmjs.org/mocha/-/mocha-9.2.2.tgz" - integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "4.2.1" - ms "2.1.3" - nanoid "3.3.1" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" - -ms@^2.0.0, ms@^2.1.1, ms@2.1.3: - version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" - integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== - -ms@2.1.2: - version "2.1.2" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" - integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== - -mustache@^4.0.0: - version "4.2.0" - resolved "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz" - integrity sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ== - -nan@^2.13.2, nan@^2.14.0, nan@2.14.0: - version "2.14.0" - resolved "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz" - integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== - -nanoid@3.3.1: - version "3.3.1" - resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.3.1.tgz" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - -natural-compare@^1.4.0: - version "1.4.0" - resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" - integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw== - -near-api-js@^1.0.0: - version "1.1.0" - resolved "https://registry.npmjs.org/near-api-js/-/near-api-js-1.1.0.tgz" - integrity sha512-qYKv1mYsaDZc2uYndhS+ttDhR9+60qFc+ZjD6lWsAxr3ZskMjRwPffDGQZYhC7BRDQMe1HEbk6d5mf+TVm0Lqg== - dependencies: - bn.js "5.2.1" - borsh "^0.7.0" - bs58 "^4.0.0" - depd "^2.0.0" - error-polyfill "^0.1.3" - http-errors "^1.7.2" - js-sha256 "^0.9.0" - mustache "^4.0.0" - node-fetch "^2.6.1" - text-encoding-utf-8 "^1.0.2" - tweetnacl "^1.0.1" - -no-case@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/no-case/-/no-case-3.0.4.tgz" - integrity sha512-fgAN3jGAh+RoxUGZHTSOLJIqUc2wmoBwGR4tbpNAKmmovFoWq0OdRkb0VkldReO2a2iBT/OEulG9XSUc10r3zg== - dependencies: - lower-case "^2.0.2" - tslib "^2.0.3" - -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-2.0.2.tgz" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - -node-addon-api@^5.0.0: - version "5.1.0" - resolved "https://registry.npmjs.org/node-addon-api/-/node-addon-api-5.1.0.tgz" - integrity sha512-eh0GgfEkpnoWDq+VY8OyvYhFEzBk6jIYbRKdIlyTiAXIVJ8PyBaKb0rp7oDtoddbdoHWhq8wwr+XZ81F1rpNdA== - -node-fetch@^2.6.1, node-fetch@^2.6.12, node-fetch@^2.7.0: - version "2.7.0" - resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz" - integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== - dependencies: - whatwg-url "^5.0.0" - -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: - version "4.8.0" - resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz" - integrity sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og== - -noms@0.0.0: - version "0.0.0" - resolved "https://registry.npmjs.org/noms/-/noms-0.0.0.tgz" - integrity sha512-lNDU9VJaOPxUmXcLb+HQFeUgQQPtMI24Gt6hgfuMHRJgMRHMF/qZ4HJD3GDru4sSw9IQl2jPjAYnQrdIeLbwow== - dependencies: - inherits "^2.0.1" - readable-stream "~1.0.31" - -normalize-path@^3.0.0, normalize-path@~3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" - integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== - -o3@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/o3/-/o3-1.0.3.tgz" - integrity sha512-f+4n+vC6s4ysy7YO7O2gslWZBUu8Qj2i2OUJOvjRxQva7jVjYjB29jrr9NCjmxZQR0gzrOcv1RnqoYOeMs5VRQ== - dependencies: - capability "^0.2.5" - -object-assign@^4.1.1: - version "4.1.1" - resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" - integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== - -object-inspect@^1.13.1: - version "1.13.1" - resolved "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz" - integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ== - -object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - -object.assign@^4.1.4: - version "4.1.5" - resolved "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz" - integrity sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ== - dependencies: - call-bind "^1.0.5" - define-properties "^1.2.1" - has-symbols "^1.0.3" - object-keys "^1.1.1" - -object.fromentries@^2.0.7: - version "2.0.7" - resolved "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.7.tgz" - integrity sha512-UPbPHML6sL8PI/mOqPwsH4G6iyXcCGzLin8KvEPenOZN5lpCNBZZQ+V62vdjB1mQHrmqGQt5/OJzemUA+KJmEA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -object.groupby@^1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/object.groupby/-/object.groupby-1.0.2.tgz" - integrity sha512-bzBq58S+x+uo0VjurFT0UktpKHOZmv4/xePiOA1nbB9pMqpGK7rUPNgf+1YC+7mE+0HzhTMqNUuCqvKhj6FnBw== - dependencies: - array.prototype.filter "^1.0.3" - call-bind "^1.0.5" - define-properties "^1.2.1" - es-abstract "^1.22.3" - es-errors "^1.0.0" - -object.values@^1.1.7: - version "1.1.7" - resolved "https://registry.npmjs.org/object.values/-/object.values-1.1.7.tgz" - integrity sha512-aU6xnDFYT3x17e/f0IiiwlGPTy2jzMySGfUB4fq6z7CV8l85CWHDk5ErhyhpfDHhrOMwGFhSQkhMGHaIotA6Ng== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" - integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== - dependencies: - wrappy "1" - -optimism@^0.18.0: - version "0.18.0" - resolved "https://registry.npmjs.org/optimism/-/optimism-0.18.0.tgz" - integrity sha512-tGn8+REwLRNFnb9WmcY5IfpOqeX2kpaYJ1s6Ae3mn12AeydLkR3j+jSCmVQFoXqU8D41PAJ1RG1rCRNWmNZVmQ== - dependencies: - "@wry/caches" "^1.0.0" - "@wry/context" "^0.7.0" - "@wry/trie" "^0.4.3" - tslib "^2.3.0" - -optionator@^0.9.3: - version "0.9.3" - resolved "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz" - integrity sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg== - dependencies: - "@aashutoshrathi/word-wrap" "^1.2.3" - deep-is "^0.1.3" - fast-levenshtein "^2.0.6" - levn "^0.4.1" - prelude-ls "^1.2.1" - type-check "^0.4.0" - -p-limit@^3.0.2: - version "3.1.0" - resolved "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz" - integrity sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ== - dependencies: - yocto-queue "^0.1.0" - -p-locate@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz" - integrity sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw== - dependencies: - p-limit "^3.0.2" - -pako@^2.0.3: - version "2.1.0" - resolved "https://registry.npmjs.org/pako/-/pako-2.1.0.tgz" - integrity sha512-w+eufiZ1WuJYgPXbV/PO3NCMEc3xqylkKHzp8bxp1uW4qaSNQUkwmLLEc3kKsfz8lpV1F8Ht3U1Cm+9Srog2ug== - -parent-module@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" - integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== - dependencies: - callsites "^3.0.0" - -path-exists@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" - integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" - integrity sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg== - -path-key@^3.1.0: - version "3.1.1" - resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" - integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== - -path-parse@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz" - integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== - -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== - -pbkdf2@^3.0.17: - version "3.1.2" - resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz" - integrity sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA== - dependencies: - create-hash "^1.1.2" - create-hmac "^1.1.4" - ripemd160 "^2.0.1" - safe-buffer "^5.0.1" - sha.js "^2.4.8" - -picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: - version "2.3.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz" - integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== - -picomatch@^3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/picomatch/-/picomatch-3.0.1.tgz" - integrity sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag== - -prelude-ls@^1.2.1: - version "1.2.1" - resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz" - integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== - -prettier@^2.6.2: - version "2.8.8" - resolved "https://registry.npmjs.org/prettier/-/prettier-2.8.8.tgz" - integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== - -process-nextick-args@~2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" - integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== - -prop-types@^15.7.2: - version "15.8.1" - resolved "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz" - integrity sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg== - dependencies: - loose-envify "^1.4.0" - object-assign "^4.1.1" - react-is "^16.13.1" - -protobufjs@^6.8.8: - version "6.11.4" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" - integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^4.0.0" - -protobufjs@^7.0.0: - version "7.2.6" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-7.2.6.tgz" - integrity sha512-dgJaEDDL6x8ASUZ1YqWciTRrdOuYNzoOf27oHNfdyvKqHr5i0FV7FSLU+aIeFjyFgVxrpTOtQUi0BLLBymZaBw== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/node" ">=13.7.0" - long "^5.0.0" - -protobufjs@~6.11.2: - version "6.11.4" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" - integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^4.0.0" - -protobufjs@~6.11.3: - version "6.11.4" - resolved "https://registry.npmjs.org/protobufjs/-/protobufjs-6.11.4.tgz" - integrity sha512-5kQWPaJHi1WoCpjTGszzQ32PG2F4+wRY6BmAT4Vfw56Q2FZ4YZzK20xUYQH4YkfehY1e6QSICrJquM6xXZNcrw== - dependencies: - "@protobufjs/aspromise" "^1.1.2" - "@protobufjs/base64" "^1.1.2" - "@protobufjs/codegen" "^2.0.4" - "@protobufjs/eventemitter" "^1.1.0" - "@protobufjs/fetch" "^1.1.0" - "@protobufjs/float" "^1.0.2" - "@protobufjs/inquire" "^1.1.0" - "@protobufjs/path" "^1.1.2" - "@protobufjs/pool" "^1.1.0" - "@protobufjs/utf8" "^1.1.0" - "@types/long" "^4.0.1" - "@types/node" ">=13.7.0" - long "^4.0.0" - -punycode@^2.1.0: - version "2.3.1" - resolved "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz" - integrity sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg== - -queue-microtask@^1.2.2: - version "1.2.3" - resolved "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz" - integrity sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A== - -randombytes@^2.1.0: - version "2.1.0" - resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" - integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== - dependencies: - safe-buffer "^5.1.0" - -react-is@^16.13.1, react-is@^16.7.0: - version "16.13.1" - resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" - integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== - -readable-stream@^3.6.0: - version "3.6.2" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz" - integrity sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA== - dependencies: - inherits "^2.0.3" - string_decoder "^1.1.1" - util-deprecate "^1.0.1" - -readable-stream@~1.0.31: - version "1.0.34" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-1.0.34.tgz" - integrity sha512-ok1qVCJuRkNmvebYikljxJA/UEsKwLl2nI1OmaqAu4/UE+h0wKCHok4XkL/gvi39OacXvw59RJUOFUkDib2rHg== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.1" - isarray "0.0.1" - string_decoder "~0.10.x" - -readable-stream@~2.3.6: - version "2.3.8" - resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz" - integrity sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA== - dependencies: - core-util-is "~1.0.0" - inherits "~2.0.3" - isarray "~1.0.0" - process-nextick-args "~2.0.0" - safe-buffer "~5.1.1" - string_decoder "~1.1.1" - util-deprecate "~1.0.1" - -readdirp@~3.6.0: - version "3.6.0" - resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" - integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== - dependencies: - picomatch "^2.2.1" - -readonly-date@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/readonly-date/-/readonly-date-1.0.0.tgz" - integrity sha512-tMKIV7hlk0h4mO3JTmmVuIlJVXjKk3Sep9Bf5OH0O+758ruuVkUy2J9SttDLm91IEX/WHlXPSpxMGjPj4beMIQ== - -rechoir@^0.6.2: - version "0.6.2" - resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" - integrity sha512-HFM8rkZ+i3zrV+4LQjwQ0W+ez98pApMGM3HUrN04j3CqzPOzl9nmP15Y8YXNm8QHGv/eacOVEjqhmWpkRV0NAw== - dependencies: - resolve "^1.1.6" - -regenerator-runtime@^0.13.11: - version "0.13.11" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz" - integrity sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg== - -regenerator-runtime@^0.14.0: - version "0.14.1" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz" - integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== - -regexp.prototype.flags@^1.5.1: - version "1.5.1" - resolved "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.1.tgz" - integrity sha512-sy6TXMN+hnP/wMy+ISxg3krXx7BAtWVO4UouuCN/ziM9UEne0euamVNafDfvC83bRNr95y0V5iijeDQFUNpvrg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - set-function-name "^2.0.0" - -rehackt@0.0.4: - version "0.0.4" - resolved "https://registry.npmjs.org/rehackt/-/rehackt-0.0.4.tgz" - integrity sha512-xFroSGCbMEK/cTJVhq+c8l/AzIeMeojVyLqtZmr2jmIAFvePjapkCSGg9MnrcNk68HPaMxGf+Ndqozotu78ITw== - -require-directory@^2.1.1: - version "2.1.1" - resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" - integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== - -resolve-from@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" - integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== - -resolve-pkg-maps@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz" - integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== - -resolve@^1.1.6, resolve@^1.22.2, resolve@^1.22.4: - version "1.22.8" - resolved "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz" - integrity sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw== - dependencies: - is-core-module "^2.13.0" - path-parse "^1.0.7" - supports-preserve-symlinks-flag "^1.0.0" - -response-iterator@^0.2.6: - version "0.2.6" - resolved "https://registry.npmjs.org/response-iterator/-/response-iterator-0.2.6.tgz" - integrity sha512-pVzEEzrsg23Sh053rmDUvLSkGXluZio0qu8VT6ukrYuvtjVfCbDZH9d6PGXb8HZfzdNZt8feXv/jvUzlhRgLnw== - -reusify@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" - integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== - -rimraf@^3.0.0, rimraf@^3.0.2: - version "3.0.2" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" - integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== - dependencies: - glob "^7.1.3" - -ripemd160-min@0.0.6: - version "0.0.6" - resolved "https://registry.npmjs.org/ripemd160-min/-/ripemd160-min-0.0.6.tgz" - integrity sha512-+GcJgQivhs6S9qvLogusiTcS9kQUfgR75whKuy5jIhuiOfQuJ8fjqxV6EGD5duH1Y/FawFUMtMhyeq3Fbnib8A== - -ripemd160@^2.0.0, ripemd160@^2.0.1: - version "2.0.2" - resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" - integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== - dependencies: - hash-base "^3.0.0" - inherits "^2.0.1" - -rlp@^2.2.3, rlp@^2.2.4: - version "2.2.7" - resolved "https://registry.npmjs.org/rlp/-/rlp-2.2.7.tgz" - integrity sha512-d5gdPmgQ0Z+AklL2NVXr/IoSjNZFfTVvQWzL/AM2AOcSzYP2xjlb0AC8YyCLc41MSNf6P6QVtjgPdmVtzb+4lQ== - dependencies: - bn.js "^5.2.0" - -rpc-websockets@^7.5.1: - version "7.9.0" - resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.9.0.tgz" - integrity sha512-DwKewQz1IUA5wfLvgM8wDpPRcr+nWSxuFxx5CbrI2z/MyyZ4nXLM86TvIA+cI1ZAdqC8JIBR1mZR55dzaLU+Hw== - dependencies: - "@babel/runtime" "^7.17.2" - eventemitter3 "^4.0.7" - uuid "^8.3.2" - ws "^8.5.0" - optionalDependencies: - bufferutil "^4.0.1" - utf-8-validate "^5.0.2" - -run-parallel@^1.1.9: - version "1.2.0" - resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz" - integrity sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA== - dependencies: - queue-microtask "^1.2.2" - -rxjs@^7.4.0, rxjs@^7.5.6, rxjs@^7.8.0: - version "7.8.1" - resolved "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz" - integrity sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg== - dependencies: - tslib "^2.1.0" - -safe-array-concat@^1.0.1: - version "1.1.0" - resolved "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.0.tgz" - integrity sha512-ZdQ0Jeb9Ofti4hbt5lX3T2JcAamT9hfzYU1MNB+z/jaEbB6wfFfPIR/zEORmZqobkCCJhSjodobH6WHNmJ97dg== - dependencies: - call-bind "^1.0.5" - get-intrinsic "^1.2.2" - has-symbols "^1.0.3" - isarray "^2.0.5" - -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@~5.2.0: - version "5.2.1" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: - version "5.1.2" - resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-regex-test@^1.0.0: - version "1.0.3" - resolved "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz" - integrity sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-regex "^1.1.4" - -scrypt-js@^3.0.0, scrypt-js@3.0.1: - version "3.0.1" - resolved "https://registry.npmjs.org/scrypt-js/-/scrypt-js-3.0.1.tgz" - integrity sha512-cdwTTnqPu0Hyvf5in5asVdZocVDTNRmR7XEcJuIzMjJeSHybHl7vpB66AzwTaIg6CLSbtjcxc8fqcySfnTkccA== - -secp256k1@^4.0.1, secp256k1@^4.0.2, secp256k1@^4.0.3: - version "4.0.3" - resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-4.0.3.tgz" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -secp256k1@3.7.1: - version "3.7.1" - resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-3.7.1.tgz" - integrity sha512-1cf8sbnRreXrQFdH6qsg2H71Xw91fCCS9Yp021GnUNJzWJS/py96fS4lHbnTnouLp08Xj6jBoBB6V78Tdbdu5g== - dependencies: - bindings "^1.5.0" - bip66 "^1.1.5" - bn.js "^4.11.8" - create-hash "^1.2.0" - drbg.js "^1.0.1" - elliptic "^6.4.1" - nan "^2.14.0" - safe-buffer "^5.1.2" - -secp256k1@5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/secp256k1/-/secp256k1-5.0.0.tgz" - integrity sha512-TKWX8xvoGHrxVdqbYeZM9w+izTF4b9z3NhSaDkdn81btvuh+ivbIMGT/zQvDtTFWhRlThpoz6LEYTr7n8A5GcA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^5.0.0" - node-gyp-build "^4.2.0" - -semver@^6.3.1: - version "6.3.1" - resolved "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz" - integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== - -semver@^7.0.0, semver@^7.5.3, semver@^7.5.4: - version "7.6.0" - resolved "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" - -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.0.tgz" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== - dependencies: - randombytes "^2.1.0" - -set-function-length@^1.2.0: - version "1.2.1" - resolved "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.1.tgz" - integrity sha512-j4t6ccc+VsKwYHso+kElc5neZpjtq9EnRICFZtWyBsLojhmeF/ZBd/elqm22WJh/BziDe/SBiOeAt0m2mfLD0g== - dependencies: - define-data-property "^1.1.2" - es-errors "^1.3.0" - function-bind "^1.1.2" - get-intrinsic "^1.2.3" - gopd "^1.0.1" - has-property-descriptors "^1.0.1" - -set-function-name@^2.0.0: - version "2.0.1" - resolved "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.1.tgz" - integrity sha512-tMNCiqYVkXIZgc2Hnoy2IvC/f8ezc5koaRFkCjrpWzGpCd3qbZXPzVy9MAZzK1ch/X0jvSkojys3oqJN0qCmdA== - dependencies: - define-data-property "^1.0.1" - functions-have-names "^1.2.3" - has-property-descriptors "^1.0.0" - -setimmediate@^1.0.5: - version "1.0.5" - resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" - integrity sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA== - -setprototypeof@1.2.0: - version "1.2.0" - resolved "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz" - integrity sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw== - -sha.js@^2.4.0, sha.js@^2.4.8: - version "2.4.11" - resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" - integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== - dependencies: - inherits "^2.0.1" - safe-buffer "^5.0.1" - -sha3@^2.1.1, sha3@^2.1.4: - version "2.1.4" - resolved "https://registry.npmjs.org/sha3/-/sha3-2.1.4.tgz" - integrity sha512-S8cNxbyb0UGUM2VhRD4Poe5N58gJnJsLJ5vC7FYWGUmGhcsj4++WaIOBFVDxlG0W3To6xBuiRh+i0Qp2oNCOtg== - dependencies: - buffer "6.0.3" - -shebang-command@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" - integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== - dependencies: - shebang-regex "^3.0.0" - -shebang-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" - integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== - -shelljs@^0.8.5: - version "0.8.5" - resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz" - integrity sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow== - dependencies: - glob "^7.0.0" - interpret "^1.0.0" - rechoir "^0.6.2" - -shx@^0.3.2: - version "0.3.4" - resolved "https://registry.npmjs.org/shx/-/shx-0.3.4.tgz" - integrity sha512-N6A9MLVqjxZYcVn8hLmtneQWIJtp8IKzMP4eMnx+nqkvXoqinUPCbUFLp2UcWTEIUONhlk0ewxr/jaVGlc+J+g== - dependencies: - minimist "^1.2.3" - shelljs "^0.8.5" - -side-channel@^1.0.4: - version "1.0.5" - resolved "https://registry.npmjs.org/side-channel/-/side-channel-1.0.5.tgz" - integrity sha512-QcgiIWV4WV7qWExbN5llt6frQB/lBven9pqliLXfGPB+K9ZYXxDozp0wLkHS24kWCm+6YXH/f0HhnObZnZOBnQ== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - get-intrinsic "^1.2.4" - object-inspect "^1.13.1" - -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - -snake-case@^3.0.4: - version "3.0.4" - resolved "https://registry.npmjs.org/snake-case/-/snake-case-3.0.4.tgz" - integrity sha512-LAOh4z89bGQvl9pFfNF8V146i7o7/CqFPbqzYgP+yYzDIDeS9HaNFtXABamRW+AQzEVODcvE79ljJ+8a9YSdMg== - dependencies: - dot-case "^3.0.4" - tslib "^2.0.3" - -snakecase-keys@^5.1.2, snakecase-keys@^5.4.1: - version "5.5.0" - resolved "https://registry.npmjs.org/snakecase-keys/-/snakecase-keys-5.5.0.tgz" - integrity sha512-r3kRtnoPu3FxGJ3fny6PKNnU3pteb29o6qAa0ugzhSseKNWRkw1dw8nIjXMyyKaU9vQxxVIE62Mb3bKbdrgpiw== - dependencies: - map-obj "^4.1.0" - snake-case "^3.0.4" - type-fest "^3.12.0" - -source-map-support@^0.5.6: - version "0.5.21" - resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - -"statuses@>= 1.5.0 < 2": - version "1.5.0" - resolved "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz" - integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA== - -store2@^2.12.0: - version "2.14.2" - resolved "https://registry.npmjs.org/store2/-/store2-2.14.2.tgz" - integrity sha512-siT1RiqlfQnGqgT/YzXVUNsom9S0H1OX+dpdGN1xkyYATo4I6sep5NmsRD/40s3IIOvlCq6akxkqG82urIZW1w== - -string_decoder@^1.1.1: - version "1.3.0" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz" - integrity sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA== - dependencies: - safe-buffer "~5.2.0" - -string_decoder@~0.10.x: - version "0.10.31" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz" - integrity sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ== - -string_decoder@~1.1.1: - version "1.1.1" - resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" - integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== - dependencies: - safe-buffer "~5.1.0" - -string-width@^4.1.0, string-width@^4.2.0: - version "4.2.3" - resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz" - integrity sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g== - dependencies: - emoji-regex "^8.0.0" - is-fullwidth-code-point "^3.0.0" - strip-ansi "^6.0.1" - -string.prototype.trim@^1.2.8: - version "1.2.8" - resolved "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.8.tgz" - integrity sha512-lfjY4HcixfQXOfaqCvcBuOIapyaroTXhbkfJN3gcB1OtyupngWK4sEET9Knd0cXd28kTUqu/kHoV4HKSJdnjiQ== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimend@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.7.tgz" - integrity sha512-Ni79DqeB72ZFq1uH/L6zJ+DKZTkOtPIHovb3YZHQViE+HDouuU4mBrLOLDn5Dde3RF8qw5qVETEjhu9locMLvA== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -string.prototype.trimstart@^1.0.7: - version "1.0.7" - resolved "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.7.tgz" - integrity sha512-NGhtDFu3jCEm7B4Fy0DpLewdJQOZcQ0rGbwQ/+stjnrp2i+rlKeCvos9hOIeCmqwratM47OBxY7uFZzjxHXmrg== - dependencies: - call-bind "^1.0.2" - define-properties "^1.2.0" - es-abstract "^1.22.1" - -strip-ansi@^6.0.0, strip-ansi@^6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz" - integrity sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A== - dependencies: - ansi-regex "^5.0.1" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz" - integrity sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA== - -strip-hex-prefix@1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/strip-hex-prefix/-/strip-hex-prefix-1.0.0.tgz" - integrity sha512-q8d4ue7JGEiVcypji1bALTos+0pWtyGlivAWyPuTkHzuTCJqrK9sWxYQZUq6Nq3cuyv3bm734IhHvHtGGURU6A== - dependencies: - is-hex-prefixed "1.0.0" - -strip-json-comments@^3.1.1, strip-json-comments@3.1.1: - version "3.1.1" - resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz" - integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== - -superstruct@^0.14.2: - version "0.14.2" - resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.14.2.tgz" - integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== - -superstruct@^0.15.4: - version "0.15.5" - resolved "https://registry.npmjs.org/superstruct/-/superstruct-0.15.5.tgz" - integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== - -superstruct@^1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/superstruct/-/superstruct-1.0.3.tgz" - integrity sha512-8iTn3oSS8nRGn+C2pgXSKPI3jmpm6FExNazNpjvqS6ZUJQCej3PUXEKM8NjHBOs54ExM+LPW/FBRhymrdcCiSg== - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -supports-color@^7.1.0: - version "7.2.0" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz" - integrity sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw== - dependencies: - has-flag "^4.0.0" - -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" - -supports-preserve-symlinks-flag@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz" - integrity sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w== - -symbol-observable@^2.0.3: - version "2.0.3" - resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-2.0.3.tgz" - integrity sha512-sQV7phh2WCYAn81oAkakC5qjq2Ml0g8ozqz03wOGnx9dDlG1de6yrF+0RAzSJD8fPUow3PTSMf2SAbOGxb93BA== - -symbol-observable@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz" - integrity sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ== - -text-encoding-utf-8@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz" - integrity sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg== - -text-table@^0.2.0: - version "0.2.0" - resolved "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz" - integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== - -"through@>=2.2.7 <3": - version "2.3.8" - resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" - integrity sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg== - -through2@^2.0.1: - version "2.0.5" - resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" - integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== - dependencies: - readable-stream "~2.3.6" - xtend "~4.0.1" - -tiny-secp256k1@^1.1.3: - version "1.1.6" - resolved "https://registry.npmjs.org/tiny-secp256k1/-/tiny-secp256k1-1.1.6.tgz" - integrity sha512-FmqJZGduTyvsr2cF3375fqGHUovSwDi/QytexX1Se4BPuPZpTE5Ftp5fg+EFSuEf3lhZqgCRjEG3ydUQ/aNiwA== - dependencies: - bindings "^1.3.0" - bn.js "^4.11.8" - create-hmac "^1.1.7" - elliptic "^6.4.0" - nan "^2.13.2" - -tmp@^0.2.1: - version "0.2.1" - resolved "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz" - integrity sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ== - dependencies: - rimraf "^3.0.0" - -to-regex-range@^5.0.1: - version "5.0.1" - resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" - integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== - dependencies: - is-number "^7.0.0" - -toidentifier@1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz" - integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== - -toml@^3.0.0: - version "3.0.0" - resolved "https://registry.npmjs.org/toml/-/toml-3.0.0.tgz" - integrity sha512-y/mWCZinnvxjTKYhJ+pYxwD0mRLVvOtdS2Awbgxln6iEnt4rk0yBxeSBHkGJcPucRiG0e55mwWp+g/05rsrd6w== - -tr46@~0.0.3: - version "0.0.3" - resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" - integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== - -ts-api-utils@^1.0.1: - version "1.2.1" - resolved "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.2.1.tgz" - integrity sha512-RIYA36cJn2WiH9Hy77hdF9r7oEwxAtB/TS9/S4Qd90Ap4z5FSiin5zEiTL44OII1Y3IIlEvxwxFUVgrHSZ/UpA== - -ts-invariant@^0.10.3: - version "0.10.3" - resolved "https://registry.npmjs.org/ts-invariant/-/ts-invariant-0.10.3.tgz" - integrity sha512-uivwYcQaxAucv1CzRp2n/QdYPo4ILf9VXgH19zEIjFx2EJufV16P0JtJVpYHy89DItG6Kwj2oIUjrcK5au+4tQ== - dependencies: - tslib "^2.1.0" - -ts-mocha@^10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/ts-mocha/-/ts-mocha-10.0.0.tgz" - integrity sha512-VRfgDO+iiuJFlNB18tzOfypJ21xn2xbuZyDvJvqpTbWgkAgD17ONGr8t+Tl8rcBtOBdjXp5e/Rk+d39f7XBHRw== - dependencies: - ts-node "7.0.1" - optionalDependencies: - tsconfig-paths "^3.5.0" - -ts-node@7.0.1: - version "7.0.1" - resolved "https://registry.npmjs.org/ts-node/-/ts-node-7.0.1.tgz" - integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== - dependencies: - arrify "^1.0.0" - buffer-from "^1.1.0" - diff "^3.1.0" - make-error "^1.1.1" - minimist "^1.2.0" - mkdirp "^0.5.1" - source-map-support "^0.5.6" - yn "^2.0.0" - -tsconfig-paths@^3.15.0, tsconfig-paths@^3.5.0: - version "3.15.0" - resolved "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz" - integrity sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.2" - minimist "^1.2.6" - strip-bom "^3.0.0" - -tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0: - version "2.6.2" - resolved "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz" - integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q== - -tweetnacl-util@^0.15.1: - version "0.15.1" - resolved "https://registry.npmjs.org/tweetnacl-util/-/tweetnacl-util-0.15.1.tgz" - integrity sha512-RKJBIj8lySrShN4w6i/BonWp2Z/uxwC3h4y7xsRrpP59ZboCd0GpEVsOnMDYLMmKBpYhb5TgHzZXy7wTfYFBRw== - -tweetnacl@^1.0.1, tweetnacl@^1.0.3, tweetnacl@1.0.3: - version "1.0.3" - resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== - -type-check@^0.4.0, type-check@~0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz" - integrity sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew== - dependencies: - prelude-ls "^1.2.1" - -type-detect@^4.0.0, type-detect@^4.0.8: - version "4.0.8" - resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== - -type-fest@^0.20.2: - version "0.20.2" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" - integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== - -type-fest@^3.12.0: - version "3.13.1" - resolved "https://registry.npmjs.org/type-fest/-/type-fest-3.13.1.tgz" - integrity sha512-tLq3bSNx+xSpwvAJnzrK0Ep5CLNWjvFTOp71URMaAEWBfRb9nnJiBoUe0tF8bI4ZFO3omgBR6NvnbzVUT3Ly4g== - -typed-array-buffer@^1.0.0: - version "1.0.1" - resolved "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.1.tgz" - integrity sha512-RSqu1UEuSlrBhHTWC8O9FnPjOduNs4M7rJ4pRKoEjtx1zUNOPN2sSXHLDX+Y2WPbHIxbvg4JFo2DNAEfPIKWoQ== - dependencies: - call-bind "^1.0.6" - es-errors "^1.3.0" - is-typed-array "^1.1.13" - -typed-array-byte-length@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.0.tgz" - integrity sha512-Or/+kvLxNpeQ9DtSydonMxCx+9ZXOswtwJn17SNLvhptaXYDJvkFFP5zbfU/uLmvnBJlI4yrnXRxpdWH/M5tNA== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-byte-offset@^1.0.0: - version "1.0.0" - resolved "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.0.tgz" - integrity sha512-RD97prjEt9EL8YgAgpOkf3O4IF9lhJFr9g0htQkm0rchFp/Vx7LW5Q8fSXXub7BXAODyUQohRMyOc3faCPd0hg== - dependencies: - available-typed-arrays "^1.0.5" - call-bind "^1.0.2" - for-each "^0.3.3" - has-proto "^1.0.1" - is-typed-array "^1.1.10" - -typed-array-length@^1.0.4: - version "1.0.4" - resolved "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.4.tgz" - integrity sha512-KjZypGq+I/H7HI5HlOoGHkWUUGq+Q0TPhQurLbyrVrvnKTBgzLhIJ7j6J/XTQOi0d1RjyZ0wdas8bKs2p0x3Ng== - dependencies: - call-bind "^1.0.2" - for-each "^0.3.3" - is-typed-array "^1.1.9" - -typeforce@^1.11.5: - version "1.18.0" - resolved "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz" - integrity sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g== - -typescript@*, typescript@^4.9.5, typescript@>=4.2.0: - version "4.9.5" - resolved "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz" - integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g== - -u3@^0.1.1: - version "0.1.1" - resolved "https://registry.npmjs.org/u3/-/u3-0.1.1.tgz" - integrity sha512-+J5D5ir763y+Am/QY6hXNRlwljIeRMZMGs0cT6qqZVVzzT3X3nFPXVyPOFRMOR4kupB0T8JnCdpWdp6Q/iXn3w== - -unbox-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz" - integrity sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw== - dependencies: - call-bind "^1.0.2" - has-bigints "^1.0.2" - has-symbols "^1.0.3" - which-boxed-primitive "^1.0.2" - -undici-types@~5.26.4: - version "5.26.5" - resolved "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz" - integrity sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA== - -untildify@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz" - integrity sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw== - -uri-js@^4.2.2: - version "4.4.1" - resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz" - integrity sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg== - dependencies: - punycode "^2.1.0" - -utf-8-validate@^5.0.2, utf-8-validate@^5.0.5, utf-8-validate@>=5.0.2: - version "5.0.10" - resolved "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz" - integrity sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ== - dependencies: - node-gyp-build "^4.3.0" - -util-deprecate@^1.0.1, util-deprecate@~1.0.1: - version "1.0.2" - resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" - integrity sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw== - -uuid@^8.3.2: - version "8.3.2" - resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" - integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== - -vlq@^2.0.4: - version "2.0.4" - resolved "https://registry.npmjs.org/vlq/-/vlq-2.0.4.tgz" - integrity sha512-aodjPa2wPQFkra1G8CzJBTHXhgk3EVSwxSWXNPr1fgdFLUb8kvLV1iEb6rFgasIsjP82HWI6dsb5Io26DDnasA== - -webidl-conversions@^3.0.0: - version "3.0.1" - resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz" - integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ== - -whatwg-url@^5.0.0: - version "5.0.0" - resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz" - integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw== - dependencies: - tr46 "~0.0.3" - webidl-conversions "^3.0.0" - -which-boxed-primitive@^1.0.2: - version "1.0.2" - resolved "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz" - integrity sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg== - dependencies: - is-bigint "^1.0.1" - is-boolean-object "^1.1.0" - is-number-object "^1.0.4" - is-string "^1.0.5" - is-symbol "^1.0.3" - -which-typed-array@^1.1.13, which-typed-array@^1.1.14: - version "1.1.14" - resolved "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.14.tgz" - integrity sha512-VnXFiIW8yNn9kIHN88xvZ4yOWchftKDsRJ8fEPacX/wl1lOvBrhsJ/OeJCXq7B0AaijRuqgzSKalJoPk+D8MPg== - dependencies: - available-typed-arrays "^1.0.6" - call-bind "^1.0.5" - for-each "^0.3.3" - gopd "^1.0.1" - has-tostringtag "^1.0.1" - -which@^2.0.1, which@2.0.2: - version "2.0.2" - resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -wif@^2.0.6: - version "2.0.6" - resolved "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz" - integrity sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ== - dependencies: - bs58check "<3.0.0" - -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.npmjs.org/workerpool/-/workerpool-6.2.0.tgz" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== - -wrap-ansi@^7.0.0: - version "7.0.0" - resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" - integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== - dependencies: - ansi-styles "^4.0.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" - integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== - -ws@*, ws@^7, ws@^7.4.5, ws@^7.5.8, ws@^7.5.9: - version "7.5.9" - resolved "https://registry.npmjs.org/ws/-/ws-7.5.9.tgz" - integrity sha512-F+P9Jil7UiSKSkppIiD94dN07AwvFixvLIj1Og1Rl9GGMuNipJnV9JzjD6XuqmAeiswGvUmNLjr5cFuXwNS77Q== - -ws@^8.5.0: - version "8.16.0" - resolved "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz" - integrity sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ== - -ws@7.4.6: - version "7.4.6" - resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" - integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== - -xstream@^11.14.0: - version "11.14.0" - resolved "https://registry.npmjs.org/xstream/-/xstream-11.14.0.tgz" - integrity sha512-1bLb+kKKtKPbgTK6i/BaoAn03g47PpFstlbe1BA+y3pNS/LfvcaghS5BFf9+EE1J+KwSQsEpfJvFN5GqFtiNmw== - dependencies: - globalthis "^1.0.1" - symbol-observable "^2.0.3" - -xtend@~4.0.1: - version "4.0.2" - resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" - integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== - -y18n@^5.0.5: - version "5.0.8" - resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" - integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== - -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - -yargs-parser@^20.2.2: - version "20.2.9" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.9.tgz" - integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== - -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-unparser@2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/yargs-unparser/-/yargs-unparser-2.0.0.tgz" - integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== - dependencies: - camelcase "^6.0.0" - decamelize "^4.0.0" - flat "^5.0.2" - is-plain-obj "^2.1.0" - -yargs@^16.1.0, yargs@16.2.0: - version "16.2.0" - resolved "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - -yn@^2.0.0: - version "2.0.0" - resolved "https://registry.npmjs.org/yn/-/yn-2.0.0.tgz" - integrity sha512-uTv8J/wiWTgUTg+9vLTi//leUl5vDQS6uii/emeTb2ssY7vl6QWf2fFbIIGjnhjvbdKlU0ed7QPgY1htTC86jQ== - -yocto-queue@^0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz" - integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zen-observable-ts@^1.2.5: - version "1.2.5" - resolved "https://registry.npmjs.org/zen-observable-ts/-/zen-observable-ts-1.2.5.tgz" - integrity sha512-QZWQekv6iB72Naeake9hS1KxHlotfRpe+WGNbNx5/ta+R3DNjVO2bswf63gXlWDcs+EMd7XY8HfVQyP1X6T4Zg== - dependencies: - zen-observable "0.8.15" - -zen-observable@0.8.15: - version "0.8.15" - resolved "https://registry.npmjs.org/zen-observable/-/zen-observable-0.8.15.tgz" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ== From 6a6d5c10bd620fb7a8fc4f08a3e8f003d00d3262 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 10:53:29 -0500 Subject: [PATCH 79/90] solana: relax trait bounds --- .../src/endpoints/wormhole/messages.rs | 2 +- .../src/messages.rs | 62 +++++-------------- 2 files changed, 16 insertions(+), 48 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs index f06b45dfd..d387a3fd3 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs @@ -1,6 +1,6 @@ use crate::messages::Endpoint; -#[derive(PartialEq, Eq)] +#[derive(PartialEq, Eq, Clone, Debug)] pub struct WormholeEndpoint {} impl Endpoint for WormholeEndpoint { diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index 21645e6ed..e21d6af0b 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -172,22 +172,20 @@ impl ValidatedEndpointMe } #[derive(Debug, PartialEq, Eq, InitSpace, Clone, AnchorSerialize, AnchorDeserialize)] -pub struct EndpointMessageData { +pub struct EndpointMessageData { pub source_manager: [u8; 32], pub manager_payload: ManagerMessage, } -#[derive(Eq, PartialEq)] -pub struct EndpointMessage { +#[derive(Eq, PartialEq, Clone, Debug)] +pub struct EndpointMessage { _phantom: PhantomData, // TODO: check sibling registration at the manager level pub message_data: EndpointMessageData, pub endpoint_payload: Vec, } -impl std::ops::Deref - for EndpointMessage -{ +impl std::ops::Deref for EndpointMessage { type Target = EndpointMessageData; fn deref(&self) -> &Self::Target { @@ -195,29 +193,15 @@ impl std::o } } -impl std::ops::DerefMut - for EndpointMessage -{ +impl std::ops::DerefMut for EndpointMessage { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.message_data } } -impl fmt::Debug for EndpointMessage -where - E: Endpoint, - A: AnchorDeserialize + AnchorSerialize + Space + Clone, -{ - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - f.debug_struct("EndpointMessage") - .field("manager_payload", &self.manager_payload) - .finish() - } -} - impl AnchorDeserialize for EndpointMessage where - A: AnchorDeserialize + AnchorSerialize + Space, + A: Space, { fn deserialize_reader(reader: &mut R) -> io::Result { Readable::read(reader) @@ -226,33 +210,16 @@ where impl AnchorSerialize for EndpointMessage where - A: AnchorDeserialize + AnchorSerialize + Space, + A: Space, { fn serialize(&self, writer: &mut W) -> io::Result<()> { Writeable::write(self, writer) } } -impl Clone for EndpointMessage -where - E: Endpoint, - A: AnchorDeserialize + AnchorSerialize + Space, -{ - fn clone(&self) -> Self { - Self { - _phantom: PhantomData, - message_data: EndpointMessageData { - source_manager: self.source_manager, - manager_payload: self.manager_payload.clone(), - }, - endpoint_payload: self.endpoint_payload.clone(), - } - } -} - impl EndpointMessage where - A: AnchorDeserialize + AnchorSerialize + Space + Clone, + A: Space, { pub fn new( source_manager: [u8; 32], @@ -270,16 +237,17 @@ where } } -impl TypePrefixedPayload for EndpointMessage +impl TypePrefixedPayload + for EndpointMessage where - A: AnchorDeserialize + AnchorSerialize + Space, + A: Space + Clone, { const TYPE: Option = None; } -impl Readable for EndpointMessage +impl Readable for EndpointMessage where - A: AnchorDeserialize + AnchorSerialize + Space, + A: Space, { const SIZE: Option = None; @@ -313,9 +281,9 @@ where } } -impl Writeable for EndpointMessage +impl Writeable for EndpointMessage where - A: AnchorDeserialize + AnchorSerialize + Space, + A: Space, { fn written_size(&self) -> usize { 4 // prefix From 07a0d8480d7eebc0c4bd55f025e02e6d5483760c Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 10:57:33 -0500 Subject: [PATCH 80/90] solana/Makefile: node_modules depends on package-lock.json --- solana/Makefile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/solana/Makefile b/solana/Makefile index 5f9baca20..0f9403181 100644 --- a/solana/Makefile +++ b/solana/Makefile @@ -15,10 +15,10 @@ _anchor-build: anchor-test: node_modules build target/idl/example_native_token_transfers.json anchor test --skip-build -node_modules: +node_modules: package-lock.json npm ci .PHONY: clean clean: anchor clean - rm -rf .anchor node_modules \ No newline at end of file + rm -rf .anchor node_modules From 4ff93043e936762bf89a350d7751bd37d0f199d1 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 11:18:29 -0500 Subject: [PATCH 81/90] solana: remove done TODO --- .../example-native-token-transfers/src/instructions/redeem.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index d36e3b981..2be507391 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -113,7 +113,6 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { // idempotent accs.inbox_item.votes.set(accs.endpoint.id, true); - // TODO: if endpoints can be disabled, this should only cound enabled endpoints if accs .inbox_item .votes From 58364089c35b25eaaa15ebbe8395f282e96b130f Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Thu, 22 Feb 2024 11:02:31 -0500 Subject: [PATCH 82/90] solana: reduce timestamp calls --- .../src/instructions/redeem.rs | 7 +++--- .../src/instructions/transfer.rs | 7 +++--- .../src/queue/rate_limit.rs | 22 ++++++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 2be507391..5b61dac23 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -3,7 +3,6 @@ use anchor_spl::token_interface; use crate::{ bitmap::Bitmap, - clock::current_timestamp, config::*, error::NTTError, messages::{ManagerMessage, NativeTokenTransfer, ValidatedEndpointMessage}, @@ -123,11 +122,11 @@ pub fn redeem(ctx: Context, _args: RedeemArgs) -> Result<()> { } let release_timestamp = match accs.inbox_rate_limit.rate_limit.consume_or_delay(amount) { - RateLimitResult::Consumed => { + RateLimitResult::Consumed(now) => { // When receiving a transfer, we refill the outbound rate limit with // the same amount (we call this "backflow") - accs.outbox_rate_limit.rate_limit.refill(amount); - current_timestamp() + accs.outbox_rate_limit.rate_limit.refill(now, amount); + now } RateLimitResult::Delayed(release_timestamp) => release_timestamp, }; diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 8482cdf47..085d84414 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -4,7 +4,6 @@ use anchor_spl::token_interface; use crate::{ bitmap::Bitmap, chain_id::ChainId, - clock::current_timestamp, config::*, error::NTTError, normalized_amount::NormalizedAmount, @@ -216,11 +215,11 @@ fn insert_into_outbox( ) -> Result<()> { // consume the rate limit, or delay the transfer if it's outside the limit let release_timestamp = match common.outbox_rate_limit.rate_limit.consume_or_delay(amount) { - RateLimitResult::Consumed => { + RateLimitResult::Consumed(now) => { // When sending a transfer, we refill the inbound rate limit for // that chain the same amount (we call this "backflow") - inbox_rate_limit.rate_limit.refill(amount); - current_timestamp() + inbox_rate_limit.rate_limit.refill(now, amount); + now } RateLimitResult::Delayed(release_timestamp) => { if !should_queue { diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index a7493f382..8cda07f08 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -22,7 +22,7 @@ pub struct RateLimitState { pub enum RateLimitResult { /// If the rate limit is not exceeded, the transfer is immediate, /// and the capacity is reduced. - Consumed, + Consumed(UnixTimestamp), /// If the rate limit is exceeded, the transfer is delayed until the /// given timestamp. Delayed(UnixTimestamp), @@ -81,11 +81,11 @@ impl RateLimitState { /// returned. pub fn consume_or_delay(&mut self, amount: u64) -> RateLimitResult { let now = current_timestamp(); - let capacity = self.capacity(); + let capacity = self.capacity_at(now); if capacity >= amount { self.capacity_at_last_tx = capacity - amount; self.last_tx_timestamp = now; - RateLimitResult::Consumed + RateLimitResult::Consumed(now) } else { RateLimitResult::Delayed(now + Self::RATE_LIMIT_DURATION) } @@ -93,9 +93,9 @@ impl RateLimitState { /// Refills the capacity by the given amount. /// This is used to replenish the capacity via backflows. - pub fn refill(&mut self, amount: u64) { + pub fn refill(&mut self, now: UnixTimestamp, amount: u64) { self.capacity_at_last_tx = self.capacity().saturating_add(amount).min(self.limit); - self.last_tx_timestamp = current_timestamp(); + self.last_tx_timestamp = now; } pub fn set_limit(&mut self, limit: u64) { @@ -127,22 +127,24 @@ mod tests { #[test] fn test_rate_limit() { + let now = current_timestamp(); let mut rate_limit_state = RateLimitState { limit: 100_000, capacity_at_last_tx: 100_000, - last_tx_timestamp: current_timestamp(), + last_tx_timestamp: now, }; // consume 30k. should be immediate let immediately = rate_limit_state.consume_or_delay(30_000); - assert_eq!(immediately, RateLimitResult::Consumed); + assert_eq!(immediately, RateLimitResult::Consumed(now)); assert_eq!(rate_limit_state.capacity(), 70_000); assert_eq!(rate_limit_state.limit, 100_000); // unchanged assert_eq!(rate_limit_state.last_tx_timestamp, current_timestamp()); // replenish 1/4 of the limit, i.e. 25k set_test_timestamp(current_timestamp() + RateLimitState::RATE_LIMIT_DURATION / 4); + let now = current_timestamp(); assert_eq!(rate_limit_state.capacity(), 70_000 + 25_000); @@ -150,7 +152,7 @@ mod tests { let tomorrow = rate_limit_state.consume_or_delay(150_000); assert_eq!( tomorrow, - RateLimitResult::Delayed(current_timestamp() + RateLimitState::RATE_LIMIT_DURATION) + RateLimitResult::Delayed(now + RateLimitState::RATE_LIMIT_DURATION) ); // the limit is not changed, since the tx was delayed @@ -168,11 +170,11 @@ mod tests { assert_eq!(rate_limit_state.capacity(), 95_000); // now refill 2k - rate_limit_state.refill(2_000); + rate_limit_state.refill(now, 2_000); assert_eq!(rate_limit_state.capacity(), 97_000); // now refill 50k - rate_limit_state.refill(50_000); + rate_limit_state.refill(now, 50_000); assert_eq!(rate_limit_state.capacity(), 100_000); } } From 1536c981ec7286b6c09760a822dc52350aa9edb6 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 13:55:16 -0500 Subject: [PATCH 83/90] solana: allow cancelling ownership transfer --- .../src/instructions/admin.rs | 23 +++++++++++++------ .../tests/sdk/accounts.rs | 2 +- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 1099bb73d..3d7eaceab 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -15,6 +15,13 @@ use crate::{ // * Transfer ownership +/// Transferring the ownership is a 2-step process. The first step is to set the +/// new owner, and the second step is for the new owner to claim the ownership. +/// This is to prevent a situation where the ownership is transferred to an +/// address that is not able to claim the ownership (by mistake). +/// +/// The transfer can be cancelled by the existing owner invoking the [`claim_ownership`] +/// instruction. #[derive(Accounts)] pub struct TransferOwnership<'info> { #[account( @@ -28,9 +35,8 @@ pub struct TransferOwnership<'info> { /// CHECK: This account will be the signer in the [claim_ownership] instruction. new_owner: AccountInfo<'info>, - /// CHECK: Seeds must be \["upgrade-lock"\]. #[account( - seeds = [b"upgrade-lock"], + seeds = [b"upgrade_lock"], bump, )] upgrade_lock: AccountInfo<'info>, @@ -49,6 +55,7 @@ pub struct TransferOwnership<'info> { pub fn transfer_ownership(ctx: Context) -> Result<()> { ctx.accounts.config.pending_owner = Some(ctx.accounts.new_owner.key()); + // TODO: only transfer authority when the authority is not already the upgrade lock bpf_loader_upgradeable::set_upgrade_authority_checked( CpiContext::new_with_signer( ctx.accounts @@ -59,7 +66,7 @@ pub fn transfer_ownership(ctx: Context) -> Result<()> { current_authority: ctx.accounts.owner.to_account_info(), new_authority: ctx.accounts.upgrade_lock.to_account_info(), }, - &[&[b"upgrade-lock", &[ctx.bumps.upgrade_lock]]], + &[&[b"upgrade_lock", &[ctx.bumps.upgrade_lock]]], ), &crate::ID, ) @@ -71,13 +78,15 @@ pub fn transfer_ownership(ctx: Context) -> Result<()> { pub struct ClaimOwnership<'info> { #[account( mut, - constraint = config.pending_owner == Some(new_owner.key()) @ NTTError::InvalidPendingOwner + constraint = ( + config.pending_owner == Some(new_owner.key()) + || config.owner == new_owner.key() + ) @ NTTError::InvalidPendingOwner )] pub config: Account<'info, Config>, - /// CHECK: Seeds must be \["upgrade-lock"\]. #[account( - seeds = [b"upgrade-lock"], + seeds = [b"upgrade_lock"], bump, )] upgrade_lock: AccountInfo<'info>, @@ -109,7 +118,7 @@ pub fn claim_ownership(ctx: Context) -> Result<()> { current_authority: ctx.accounts.upgrade_lock.to_account_info(), new_authority: ctx.accounts.new_owner.to_account_info(), }, - &[&[b"upgrade-lock", &[ctx.bumps.upgrade_lock]]], + &[&[b"upgrade_lock", &[ctx.bumps.upgrade_lock]]], ), &crate::ID, ) diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 20c6190a3..0c9a7ff49 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -185,7 +185,7 @@ impl NTT { } pub fn upgrade_lock(&self) -> Pubkey { - let (addr, _) = Pubkey::find_program_address(&[b"upgrade-lock"], &self.program); + let (addr, _) = Pubkey::find_program_address(&[b"upgrade_lock"], &self.program); addr } } From 4922504da1a639e0aab33d962ba2293fcaeb668e Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Thu, 22 Feb 2024 14:13:32 -0500 Subject: [PATCH 84/90] solana: fix program IDs; fix .gitignore; arch sbf --- .gitignore | 7 +++++++ solana/.gitignore | 3 --- solana/Anchor.toml | 4 ++-- solana/Makefile | 2 +- solana/programs/example-native-token-transfers/src/lib.rs | 2 +- solana/programs/wormhole-governance/src/lib.rs | 2 +- 6 files changed, 12 insertions(+), 8 deletions(-) diff --git a/.gitignore b/.gitignore index 0c8a4d204..ded2d1d47 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ # Compiler files cache/ out/ +target/ # Ignores development broadcast logs !/broadcast @@ -15,3 +16,9 @@ docs/ # macOS stuff .DS_Store + +# VSCode +.vscode + +# Misc +.private \ No newline at end of file diff --git a/solana/.gitignore b/solana/.gitignore index d243ecc13..cb6711175 100644 --- a/solana/.gitignore +++ b/solana/.gitignore @@ -1,7 +1,4 @@ - .anchor -.DS_Store -target **/*.rs.bk node_modules test-ledger diff --git a/solana/Anchor.toml b/solana/Anchor.toml index 72dd44a42..ab4b49e8f 100644 --- a/solana/Anchor.toml +++ b/solana/Anchor.toml @@ -7,8 +7,8 @@ seeds = false skip-lint = false [programs.localnet] -example_native_token_transfers = "F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV" -wormhole_governance = "7kK9JyavhgE5G8oErMziHeBzZiAu3J64oLMbNf8FpG4S" +example_native_token_transfers = "nttiK1SepaQt6sZ4WGW5whvc9tEnGXGxuKeptcQPCcS" +wormhole_governance = "wgvEiKVzX9yyEoh41jZAdC6JqGUTS4CFXbFGBV5TKdZ" [registry] url = "https://api.apr.dev" diff --git a/solana/Makefile b/solana/Makefile index 0f9403181..2e1451b83 100644 --- a/solana/Makefile +++ b/solana/Makefile @@ -10,7 +10,7 @@ target/idl/example_native_token_transfers.json: .PHONY: anchor-build _anchor-build: - @anchor build + @anchor build --arch sbf anchor-test: node_modules build target/idl/example_native_token_transfers.json anchor test --skip-build diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index d34d8dbeb..3c97bf329 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -18,7 +18,7 @@ use endpoints::wormhole::instructions::*; use instructions::*; -declare_id!("F2DDaJgSfJTVYVjVkxmsFYy771QgXfqCjanF7nRQt4HV"); +declare_id!("nttiK1SepaQt6sZ4WGW5whvc9tEnGXGxuKeptcQPCcS"); const TOKEN_AUTHORITY_SEED: &[u8] = b"token_authority"; diff --git a/solana/programs/wormhole-governance/src/lib.rs b/solana/programs/wormhole-governance/src/lib.rs index c470a0bf7..5c85fce9e 100644 --- a/solana/programs/wormhole-governance/src/lib.rs +++ b/solana/programs/wormhole-governance/src/lib.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; -declare_id!("7kK9JyavhgE5G8oErMziHeBzZiAu3J64oLMbNf8FpG4S"); +declare_id!("wgvEiKVzX9yyEoh41jZAdC6JqGUTS4CFXbFGBV5TKdZ"); pub mod error; pub mod instructions; From a39026c5f479813961e1218ed410e5fc02657e65 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 14:45:18 -0500 Subject: [PATCH 85/90] solana: move release_outbound to wormhole endpoint ixs --- .../src/endpoints/wormhole/instructions/mod.rs | 2 ++ .../wormhole}/instructions/release_outbound.rs | 0 .../src/instructions/mod.rs | 2 -- .../example-native-token-transfers/src/lib.rs | 14 +++++++------- .../sdk/endpoints/wormhole/instructions/mod.rs | 1 + .../wormhole}/instructions/release_outbound.rs | 4 ++-- .../tests/sdk/instructions/mod.rs | 1 - .../tests/transfer.rs | 18 +++++++++--------- solana/ts/sdk/index.ts | 2 +- 9 files changed, 22 insertions(+), 22 deletions(-) rename solana/programs/example-native-token-transfers/src/{ => endpoints/wormhole}/instructions/release_outbound.rs (100%) rename solana/programs/example-native-token-transfers/tests/sdk/{ => endpoints/wormhole}/instructions/release_outbound.rs (92%) diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs index 6964147fb..1d6ab915f 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/mod.rs @@ -1,5 +1,7 @@ pub mod admin; pub mod receive_message; +pub mod release_outbound; pub use admin::*; pub use receive_message::*; +pub use release_outbound::*; diff --git a/solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs similarity index 100% rename from solana/programs/example-native-token-transfers/src/instructions/release_outbound.rs rename to solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs diff --git a/solana/programs/example-native-token-transfers/src/instructions/mod.rs b/solana/programs/example-native-token-transfers/src/instructions/mod.rs index 84c453533..a716c567e 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/mod.rs @@ -2,12 +2,10 @@ pub mod admin; pub mod initialize; pub mod redeem; pub mod release_inbound; -pub mod release_outbound; pub mod transfer; pub use admin::*; pub use initialize::*; pub use redeem::*; pub use release_inbound::*; -pub use release_outbound::*; pub use transfer::*; diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index 3c97bf329..d28b3bb1f 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -39,13 +39,6 @@ pub mod example_native_token_transfers { instructions::transfer_lock(ctx, args) } - pub fn release_outbound( - ctx: Context, - args: ReleaseOutboundArgs, - ) -> Result<()> { - instructions::release_outbound(ctx, args) - } - pub fn redeem(ctx: Context, args: RedeemArgs) -> Result<()> { instructions::redeem(ctx, args) } @@ -110,4 +103,11 @@ pub mod example_native_token_transfers { pub fn receive_wormhole_message(ctx: Context) -> Result<()> { endpoints::wormhole::instructions::receive_message(ctx) } + + pub fn release_wormhole_outbound( + ctx: Context, + args: ReleaseOutboundArgs, + ) -> Result<()> { + endpoints::wormhole::instructions::release_outbound(ctx, args) + } } diff --git a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs index 571d4fd22..9922536c3 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/mod.rs @@ -1,2 +1,3 @@ pub mod admin; pub mod receive_message; +pub mod release_outbound; diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/release_outbound.rs similarity index 92% rename from solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs rename to solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/release_outbound.rs index 964bc90b6..948c5574b 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/endpoints/wormhole/instructions/release_outbound.rs @@ -1,6 +1,6 @@ use anchor_lang::{prelude::*, InstructionData}; use example_native_token_transfers::{ - accounts::NotPausedConfig, instructions::ReleaseOutboundArgs, + accounts::NotPausedConfig, endpoints::wormhole::ReleaseOutboundArgs, }; use solana_sdk::{instruction::Instruction, sysvar::SysvarId}; @@ -16,7 +16,7 @@ pub fn release_outbound( release_outbound: ReleaseOutbound, args: ReleaseOutboundArgs, ) -> Instruction { - let data = example_native_token_transfers::instruction::ReleaseOutbound { args }; + let data = example_native_token_transfers::instruction::ReleaseWormholeOutbound { args }; let accounts = example_native_token_transfers::accounts::ReleaseOutbound { payer: release_outbound.payer, config: NotPausedConfig { diff --git a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs index 732856782..b97075c76 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/instructions/mod.rs @@ -2,5 +2,4 @@ pub mod admin; pub mod initialize; pub mod post_vaa; pub mod redeem; -pub mod release_outbound; pub mod transfer; diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 1ee45d236..1dff3178f 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -7,9 +7,9 @@ use example_native_token_transfers::{ bitmap::Bitmap, chain_id::ChainId, config::Mode, - endpoints::wormhole::messages::WormholeEndpoint, + endpoints::wormhole::{messages::WormholeEndpoint, ReleaseOutboundArgs}, error::NTTError, - instructions::{ReleaseOutboundArgs, TransferArgs}, + instructions::TransferArgs, messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, normalized_amount::NormalizedAmount, queue::outbox::{OutboxItem, OutboxRateLimit}, @@ -24,17 +24,17 @@ use wormhole_anchor_sdk::wormhole::PostedVaa; use crate::{ common::submit::Submittable, - sdk::instructions::{ - admin::{set_paused, SetPaused}, - transfer::{approve_token_authority, transfer}, + sdk::{ + endpoints::wormhole::instructions::release_outbound::{release_outbound, ReleaseOutbound}, + instructions::{ + admin::{set_paused, SetPaused}, + transfer::{approve_token_authority, transfer}, + }, }, }; use crate::{ common::{query::GetAccountDataAnchor, setup::OUTBOUND_LIMIT}, - sdk::instructions::{ - release_outbound::{release_outbound, ReleaseOutbound}, - transfer::Transfer, - }, + sdk::instructions::transfer::Transfer, }; pub mod common; diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 343399865..17b167354 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -352,7 +352,7 @@ export class NTT { const whAccs = getWormholeDerivedAccounts(this.program.programId, this.wormholeId) return await this.program.methods - .releaseOutbound({ + .releaseWormholeOutbound({ revertOnDelay: args.revertOnDelay }) .accounts({ From f28c39345ab4d5ee6a8d71be93952e5f4b7fbc21 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Thu, 22 Feb 2024 15:42:03 -0500 Subject: [PATCH 86/90] solana: add testnet setup; refactor ts program instance --- solana/package-lock.json | 15 ++++- solana/package.json | 2 + solana/tests/example-native-token-transfer.ts | 25 +++---- solana/ts/scripts/setUpTestnet.ts | 32 +++++++++ solana/ts/sdk/index.ts | 65 +++++++++++-------- solana/tsconfig.json | 21 +++--- 6 files changed, 110 insertions(+), 50 deletions(-) create mode 100644 solana/ts/scripts/setUpTestnet.ts diff --git a/solana/package-lock.json b/solana/package-lock.json index 83078ccba..da1e5845f 100644 --- a/solana/package-lock.json +++ b/solana/package-lock.json @@ -1,5 +1,5 @@ { - "name": "solana-multi-endpoint", + "name": "solana", "lockfileVersion": 3, "requires": true, "packages": { @@ -9,6 +9,8 @@ "@certusone/wormhole-sdk": "^0.10.10", "@coral-xyz/anchor": "^0.29.0", "@solana/spl-token": "^0.4.0", + "@solana/web3.js": "^1.90.0", + "dotenv": "^16.4.5", "sha3": "^2.1.4" }, "devDependencies": { @@ -3998,6 +4000,17 @@ "tslib": "^2.0.3" } }, + "node_modules/dotenv": { + "version": "16.4.5", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.4.5.tgz", + "integrity": "sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/drbg.js": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/drbg.js/-/drbg.js-1.0.1.tgz", diff --git a/solana/package.json b/solana/package.json index de9169d7c..8ac8941f1 100644 --- a/solana/package.json +++ b/solana/package.json @@ -8,6 +8,8 @@ "@certusone/wormhole-sdk": "^0.10.10", "@coral-xyz/anchor": "^0.29.0", "@solana/spl-token": "^0.4.0", + "@solana/web3.js": "^1.90.0", + "dotenv": "^16.4.5", "sha3": "^2.1.4" }, "devDependencies": { diff --git a/solana/tests/example-native-token-transfer.ts b/solana/tests/example-native-token-transfer.ts index ceb05843b..cffdf027b 100644 --- a/solana/tests/example-native-token-transfer.ts +++ b/solana/tests/example-native-token-transfer.ts @@ -14,15 +14,16 @@ export const GUARDIAN_KEY = 'cfb12303a19cde580bb4dd771639b0d26bc68353645571a8cff describe('example-native-token-transfers', () => { // Configure the client to use the local cluster. - anchor.setProvider(anchor.AnchorProvider.env()) + //anchor.setProvider(anchor.AnchorProvider.env()) const payerSecretKey = Uint8Array.from(JSON.parse(fs.readFileSync(`${__dirname}/../keys/test.json`, { encoding: "utf-8" }))); const payer = anchor.web3.Keypair.fromSecretKey(payerSecretKey); - const program = anchor.workspace.ExampleNativeTokenTransfers as Program + //const program = anchor.workspace.ExampleNativeTokenTransfers as Program const owner = anchor.web3.Keypair.generate() - const ntt = new NTT({ - program, + const connection = new anchor.web3.Connection('http://localhost:8899', 'confirmed'); + const ntt = new NTT(connection, { + nttId: 'nttiK1SepaQt6sZ4WGW5whvc9tEnGXGxuKeptcQPCcS', wormholeId: 'worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth' }) const user = anchor.web3.Keypair.generate() @@ -34,21 +35,21 @@ describe('example-native-token-transfers', () => { before(async () => { // airdrop some tokens to payer mint = await spl.createMint( - program.provider.connection, + connection, payer, owner.publicKey, null, 9 ) - tokenAccount = await spl.createAssociatedTokenAccount(program.provider.connection, payer, mint, user.publicKey) - await spl.mintTo(program.provider.connection, payer, mint, tokenAccount, owner, BigInt(10000000)) + tokenAccount = await spl.createAssociatedTokenAccount(connection, payer, mint, user.publicKey) + await spl.mintTo(connection, payer, mint, tokenAccount, owner, BigInt(10000000)) }); describe('Locking', () => { before(async () => { await spl.setAuthority( - program.provider.connection, + connection, payer, mint, owner, @@ -107,7 +108,7 @@ describe('example-native-token-transfers', () => { const wormholeMessage = ntt.wormholeMessageAccountAddress(outboxItem) - const wormholeMessageAccount = await program.provider.connection.getAccountInfo(wormholeMessage) + const wormholeMessageAccount = await connection.getAccountInfo(wormholeMessage) if (wormholeMessageAccount === null) { throw new Error('wormhole message account not found') } @@ -121,11 +122,11 @@ describe('example-native-token-transfers', () => { // assert theat amount is what we expect expect(endpointMessage.managerPayload.payload.normalizedAmount).to.deep.equal(new NormalizedAmount(BigInt(10000), 8)) // get from balance - const balance = await program.provider.connection.getTokenAccountBalance(tokenAccount) + const balance = await connection.getTokenAccountBalance(tokenAccount) expect(balance.value.amount).to.equal('9900000') // grab logs - // await program.provider.connection.confirmTransaction(redeemTx, 'confirmed'); + // await connection.confirmTransaction(redeemTx, 'confirmed'); // const tx = await anchor.getProvider().connection.getParsedTransaction(redeemTx, { // commitment: "confirmed", // }); @@ -174,7 +175,7 @@ describe('example-native-token-transfers', () => { const vaaBuf = guardians.addSignatures(published, [0]) - await postVaa(program.provider.connection, payer, vaaBuf, ntt.wormholeId) + await postVaa(connection, payer, vaaBuf, ntt.wormholeId) const released = await ntt.redeem({ payer, diff --git a/solana/ts/scripts/setUpTestnet.ts b/solana/ts/scripts/setUpTestnet.ts new file mode 100644 index 000000000..0539c835f --- /dev/null +++ b/solana/ts/scripts/setUpTestnet.ts @@ -0,0 +1,32 @@ +import { Connection, Keypair, PublicKey } from "@solana/web3.js"; +import "dotenv/config"; +import { NTT } from "../sdk"; +import { BN } from "@coral-xyz/anchor"; + +main(); + +async function main() { + if (process.env.SOLANA_PRIVATE_KEY === undefined) { + throw new Error("SOLANA_PRIVATE_KEY is not set"); + } + + if (process.env.MINT === undefined) { + throw new Error("MINT is not set"); + } + + const connection = new Connection("https://api.devnet.solana.com", "confirmed"); + const ntt = new NTT(connection, { nttId: "nttiK1SepaQt6sZ4WGW5whvc9tEnGXGxuKeptcQPCcS", wormholeId: "3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5"}); + + const payer = Keypair.fromSecretKey(Buffer.from(process.env.SOLANA_PRIVATE_KEY, "base64")); + const owner = payer; + const mint = new PublicKey(process.env.MINT); + + await ntt.initialize({ + payer, + owner, + chain: "solana", + mint, + outboundLimit: new BN(100), + mode: "locking" + }) +} \ No newline at end of file diff --git a/solana/ts/sdk/index.ts b/solana/ts/sdk/index.ts index 17b167354..5dcadacbd 100644 --- a/solana/ts/sdk/index.ts +++ b/solana/ts/sdk/index.ts @@ -1,6 +1,6 @@ import { type ChainName, toChainId, coalesceChainId, type ChainId, SignedVaa, parseVaa } from '@certusone/wormhole-sdk' import { derivePostedVaaKey, getWormholeDerivedAccounts } from '@certusone/wormhole-sdk/lib/cjs/solana/wormhole' -import { BN, translateError, type IdlAccounts, type Program } from '@coral-xyz/anchor' +import { BN, translateError, type IdlAccounts, Program } from '@coral-xyz/anchor' import { associatedAddress } from '@coral-xyz/anchor/dist/cjs/utils/token' import { getAssociatedTokenAddressSync } from '@solana/spl-token' import { @@ -9,15 +9,17 @@ import { type TransactionInstruction, Transaction, sendAndConfirmTransaction, - type TransactionSignature + type TransactionSignature, + Connection } from '@solana/web3.js' import { Keccak } from 'sha3' -import { type ExampleNativeTokenTransfers as Idl } from '../../target/types/example_native_token_transfers' +import { type ExampleNativeTokenTransfers as RawExampleNativeTokenTransfers } from '../../target/types/example_native_token_transfers' import { ManagerMessage } from './payloads/common' import { NativeTokenTransfer } from './payloads/transfers' import { WormholeEndpointMessage } from './payloads/wormhole' import { BPF_LOADER_UPGRADEABLE_PROGRAM_ID, programDataAddress } from './utils' import * as splToken from '@solana/spl-token'; +import IDL from '../../target/idl/example_native_token_transfers.json'; export { NormalizedAmount } from './normalized_amount' export { EndpointMessage, ManagerMessage } from './payloads/common' @@ -36,20 +38,33 @@ type OmitGenerics = { : T[P]; }; -export type ExampleNativeTokenTransfers = OmitGenerics +export type ExampleNativeTokenTransfers = OmitGenerics export type Config = IdlAccounts['config'] export type InboxItem = IdlAccounts['inboxItem'] + +export const NTT_PROGRAM_IDS = [ + "nttiK1SepaQt6sZ4WGW5whvc9tEnGXGxuKeptcQPCcS", +] as const; + +export const WORMHOLE_PROGRAM_IDS = [ + "worm2ZoG2kUd4vFXhvjh93UUH596ayRfgQ2MgjNMTth", // mainnet + "3u8hJUVTA4jH1wYAyUur7FFZVQ8H635K3tSHHF4ssjQ5", // testnet +] as const; + +export type NttProgramId = (typeof NTT_PROGRAM_IDS)[number]; +export type WormholeProgramId = (typeof WORMHOLE_PROGRAM_IDS)[number]; + export class NTT { readonly program: Program readonly wormholeId: PublicKey // mapping from error code to error message. Used for prettifying error messages private readonly errors: Map - constructor(args: { program: Program, wormholeId: PublicKeyInitData }) { + constructor(connection: Connection, args: { nttId: NttProgramId, wormholeId: WormholeProgramId }) { // TODO: initialise a new Program here with a passed in Connection - this.program = args.program + this.program = new Program(IDL as any, new PublicKey(args.nttId), { connection }); this.wormholeId = new PublicKey(args.wormholeId) this.errors = this.processErrors() } @@ -149,7 +164,7 @@ export class NTT { mint: PublicKey outboundLimit: BN mode: 'burning' | 'locking' - }): Promise { + }) { const mode = args.mode === 'burning' ? { burning: {} } @@ -160,7 +175,7 @@ export class NTT { throw new Error("Couldn't determine token program. Mint account is null.") } const tokenProgram = mintInfo.owner - await this.program.methods + const ix = await this.program.methods .initialize({ chainId, limit: args.outboundLimit, mode }) .accounts({ payer: args.payer.publicKey, @@ -174,9 +189,8 @@ export class NTT { tokenAuthority: this.tokenAuthorityAddress(), custody: await this.custodyAccountAddress(args.mint), bpfLoaderUpgradeableProgram: BPF_LOADER_UPGRADEABLE_PROGRAM_ID, - }) - .signers([args.payer, args.owner]) - .rpc() + }).instruction(); + return sendAndConfirmTransaction(this.program.provider.connection, new Transaction().add(ix), [args.payer, args.owner]); } async transfer(args: { @@ -375,7 +389,7 @@ export class NTT { outboxItem: PublicKey revertOnDelay: boolean config?: Config - }): Promise { + }) { if (await this.isPaused()) { throw new Error('Contract is paused') } @@ -389,7 +403,7 @@ export class NTT { tx.add(await this.createReleaseOutboundInstruction(txArgs)) const signers = [args.payer] - await sendAndConfirmTransaction(this.program.provider.connection, tx, signers) + return await sendAndConfirmTransaction(this.program.provider.connection, tx, signers) } // TODO: document that if recipient is provided, then the instruction can be @@ -520,8 +534,8 @@ export class NTT { address: ArrayLike limit: BN config?: Config - }): Promise { - await this.program.methods.setSibling({ + }) { + const ix = await this.program.methods.setSibling({ chainId: { id: toChainId(args.chain) }, address: Array.from(args.address), limit: args.limit @@ -532,9 +546,8 @@ export class NTT { config: this.configAccountAddress(), sibling: this.siblingAccountAddress(args.chain), inboxRateLimit: this.inboxRateLimitAccountAddress(args.chain), - }) - .signers([args.payer, args.owner]) - .rpc() + }).instruction(); + return sendAndConfirmTransaction(this.program.provider.connection, new Transaction().add(ix), [args.payer, args.owner]); } @@ -545,7 +558,7 @@ export class NTT { address: ArrayLike config?: Config }) { - await this.program.methods.setWormholeSibling({ + const ix = await this.program.methods.setWormholeSibling({ chainId: { id: toChainId(args.chain) }, address: Array.from(args.address) }) @@ -554,26 +567,24 @@ export class NTT { owner: args.owner.publicKey, config: this.configAccountAddress(), sibling: this.endpointSiblingAccountAddress(args.chain), - }) - .signers([args.payer, args.owner]) - .rpc() + }).instruction(); + return sendAndConfirmTransaction(this.program.provider.connection, new Transaction().add(ix), [args.payer, args.owner]); } async registerEndpoint(args: { payer: Keypair owner: Keypair endpoint: PublicKey - }): Promise { - await this.program.methods.registerEndpoint() + }) { + const ix = await this.program.methods.registerEndpoint() .accounts({ payer: args.payer.publicKey, owner: args.owner.publicKey, config: this.configAccountAddress(), endpoint: args.endpoint, registeredEndpoint: this.registeredEndpointAddress(args.endpoint), - }) - .signers([args.payer, args.owner]) - .rpc() + }).instruction(); + return sendAndConfirmTransaction(this.program.provider.connection, new Transaction().add(ix), [args.payer, args.owner]); } async createReceiveWormholeMessageInstruction(args: { diff --git a/solana/tsconfig.json b/solana/tsconfig.json index f9914254d..09e942222 100644 --- a/solana/tsconfig.json +++ b/solana/tsconfig.json @@ -1,11 +1,12 @@ { - "compilerOptions": { - "types": ["mocha", "chai"], - "typeRoots": ["./node_modules/@types"], - "lib": ["es2015"], - "module": "commonjs", - "target": "es6", - "esModuleInterop": true, - "strictNullChecks": true - } - } + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true, + "resolveJsonModule": true, + "strictNullChecks": true + } +} From 3d341f4cfa64fea4dc3dcd793db6483b83300562 Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 16:21:47 -0500 Subject: [PATCH 87/90] solana: split out structs to a separate crate --- solana/Cargo.lock | 11 + solana/Cargo.toml | 3 +- solana/modules/ntt-messages/Cargo.toml | 19 + .../ntt-messages}/src/chain_id.rs | 5 +- solana/modules/ntt-messages/src/endpoint.rs | 226 +++++++++++ .../modules/ntt-messages/src/endpoints/mod.rs | 2 + .../ntt-messages/src/endpoints/wormhole.rs} | 2 +- solana/modules/ntt-messages/src/lib.rs | 7 + solana/modules/ntt-messages/src/manager.rs | 85 ++++ .../ntt-messages}/src/normalized_amount.rs | 8 +- solana/modules/ntt-messages/src/ntt.rs | 90 +++++ .../ntt-messages/src/utils/maybe_space.rs | 12 + solana/modules/ntt-messages/src/utils/mod.rs | 1 + .../example-native-token-transfers/Cargo.toml | 1 + .../src/config.rs | 3 +- .../endpoints/wormhole/instructions/admin.rs | 3 +- .../wormhole/instructions/receive_message.rs | 15 +- .../wormhole/instructions/release_outbound.rs | 13 +- .../src/endpoints/wormhole/mod.rs | 1 - .../src/instructions/admin.rs | 2 +- .../src/instructions/initialize.rs | 2 +- .../src/instructions/redeem.rs | 3 +- .../src/instructions/transfer.rs | 3 +- .../example-native-token-transfers/src/lib.rs | 2 - .../src/messages.rs | 366 +----------------- .../src/queue/outbox.rs | 6 +- .../tests/cancel_flow.rs | 8 +- .../tests/common/setup.rs | 2 +- .../tests/sdk/accounts.rs | 2 +- .../tests/transfer.rs | 9 +- 30 files changed, 505 insertions(+), 407 deletions(-) create mode 100644 solana/modules/ntt-messages/Cargo.toml rename solana/{programs/example-native-token-transfers => modules/ntt-messages}/src/chain_id.rs (80%) create mode 100644 solana/modules/ntt-messages/src/endpoint.rs create mode 100644 solana/modules/ntt-messages/src/endpoints/mod.rs rename solana/{programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs => modules/ntt-messages/src/endpoints/wormhole.rs} (84%) create mode 100644 solana/modules/ntt-messages/src/lib.rs create mode 100644 solana/modules/ntt-messages/src/manager.rs rename solana/{programs/example-native-token-transfers => modules/ntt-messages}/src/normalized_amount.rs (95%) create mode 100644 solana/modules/ntt-messages/src/ntt.rs create mode 100644 solana/modules/ntt-messages/src/utils/maybe_space.rs create mode 100644 solana/modules/ntt-messages/src/utils/mod.rs diff --git a/solana/Cargo.lock b/solana/Cargo.lock index fcd066406..6c6d890d8 100644 --- a/solana/Cargo.lock +++ b/solana/Cargo.lock @@ -1493,6 +1493,7 @@ dependencies = [ "bitmaps 3.2.1", "hex", "libsecp256k1", + "ntt-messages", "serde", "serde_json", "serde_wormhole", @@ -2342,6 +2343,16 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "ntt-messages" +version = "0.1.0" +dependencies = [ + "anchor-lang", + "hex", + "solana-program", + "wormhole-io", +] + [[package]] name = "num" version = "0.2.1" diff --git a/solana/Cargo.toml b/solana/Cargo.toml index fbf1730be..4620aa5be 100644 --- a/solana/Cargo.toml +++ b/solana/Cargo.toml @@ -1,6 +1,7 @@ [workspace] members = [ - "programs/*" + "programs/*", + "modules/*" ] resolver = "2" diff --git a/solana/modules/ntt-messages/Cargo.toml b/solana/modules/ntt-messages/Cargo.toml new file mode 100644 index 000000000..665c7dba9 --- /dev/null +++ b/solana/modules/ntt-messages/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "ntt-messages" +version = "0.1.0" +edition = "2021" + +[features] +default = [ "wormhole" ] +wormhole = [] +hash = [ "solana-program" ] +anchor = [ "anchor-lang" ] + +[dependencies] +anchor-lang = { workspace = true, optional = true } +wormhole-io.workspace = true +solana-program = { workspace = true, optional = true } + +[dev-dependencies] + +hex.workspace = true diff --git a/solana/programs/example-native-token-transfers/src/chain_id.rs b/solana/modules/ntt-messages/src/chain_id.rs similarity index 80% rename from solana/programs/example-native-token-transfers/src/chain_id.rs rename to solana/modules/ntt-messages/src/chain_id.rs index 56d54ce21..f7049940d 100644 --- a/solana/programs/example-native-token-transfers/src/chain_id.rs +++ b/solana/modules/ntt-messages/src/chain_id.rs @@ -1,9 +1,12 @@ use std::io; +#[cfg(feature = "anchor")] use anchor_lang::prelude::*; + use wormhole_io::{Readable, Writeable}; -#[derive(AnchorSerialize, AnchorDeserialize, InitSpace, Clone, Debug, PartialEq, Eq, Copy)] +#[derive(Clone, Debug, PartialEq, Eq, Copy)] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize, InitSpace))] pub struct ChainId { pub id: u16, } diff --git a/solana/modules/ntt-messages/src/endpoint.rs b/solana/modules/ntt-messages/src/endpoint.rs new file mode 100644 index 000000000..26f627c52 --- /dev/null +++ b/solana/modules/ntt-messages/src/endpoint.rs @@ -0,0 +1,226 @@ +use core::fmt; +use std::{io, marker::PhantomData}; + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::*; + +use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; + +use crate::{manager::ManagerMessage, utils::maybe_space::MaybeSpace}; + +pub trait Endpoint { + const PREFIX: [u8; 4]; +} + +#[derive(Debug, PartialEq, Eq, Clone)] +#[cfg_attr( + feature = "anchor", + derive(AnchorSerialize, AnchorDeserialize, InitSpace) +)] +pub struct EndpointMessageData { + pub source_manager: [u8; 32], + pub manager_payload: ManagerMessage, +} + +#[derive(Eq, PartialEq, Clone, Debug)] +pub struct EndpointMessage { + _phantom: PhantomData, + // TODO: check sibling registration at the manager level + pub message_data: EndpointMessageData, + pub endpoint_payload: Vec, +} + +impl std::ops::Deref for EndpointMessage { + type Target = EndpointMessageData; + + fn deref(&self) -> &Self::Target { + &self.message_data + } +} + +impl std::ops::DerefMut for EndpointMessage { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.message_data + } +} + +#[cfg(feature = "anchor")] +impl AnchorDeserialize for EndpointMessage +where + A: MaybeSpace, +{ + fn deserialize_reader(reader: &mut R) -> io::Result { + Readable::read(reader) + } +} + +#[cfg(feature = "anchor")] +impl AnchorSerialize for EndpointMessage +where + A: MaybeSpace, +{ + fn serialize(&self, writer: &mut W) -> io::Result<()> { + Writeable::write(self, writer) + } +} + +impl EndpointMessage +where + A: MaybeSpace, +{ + pub fn new( + source_manager: [u8; 32], + manager_payload: ManagerMessage, + endpoint_payload: Vec, + ) -> Self { + Self { + _phantom: PhantomData, + message_data: EndpointMessageData { + source_manager, + manager_payload, + }, + endpoint_payload, + } + } +} + +impl TypePrefixedPayload + for EndpointMessage +where + A: MaybeSpace + Clone, +{ + const TYPE: Option = None; +} + +impl Readable for EndpointMessage +where + A: MaybeSpace, +{ + const SIZE: Option = None; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let prefix: [u8; 4] = Readable::read(reader)?; + if prefix != E::PREFIX { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid prefix for EndpointMessage", + )); + } + + let source_manager = Readable::read(reader)?; + // TODO: we need a way to easily check that decoding the payload + // consumes the expected amount of bytes + let _manager_payload_len: u16 = Readable::read(reader)?; + let manager_payload = ManagerMessage::read(reader)?; + let endpoint_payload_len: u16 = Readable::read(reader)?; + let mut endpoint_payload = vec![0; endpoint_payload_len as usize]; + reader.read_exact(&mut endpoint_payload)?; + + Ok(EndpointMessage::new( + source_manager, + manager_payload, + endpoint_payload, + )) + } +} + +impl Writeable for EndpointMessage +where + A: MaybeSpace, +{ + fn written_size(&self) -> usize { + 4 // prefix + + self.source_manager.len() + + u16::SIZE.unwrap() // length prefix + + self.manager_payload.written_size() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let EndpointMessage { + _phantom, + message_data: + EndpointMessageData { + source_manager, + manager_payload, + }, + endpoint_payload, + } = self; + + E::PREFIX.write(writer)?; + source_manager.write(writer)?; + let len: u16 = u16::try_from(manager_payload.written_size()).expect("u16 overflow"); + len.write(writer)?; + // TODO: review this in wormhole-io. The written_size logic is error prone. Instead, + // a better API would be + // foo.write_with_prefix_be::(writer) + // which writes the length as a big endian u16. + manager_payload.write(writer)?; + let len: u16 = u16::try_from(endpoint_payload.len()).expect("u16 overflow"); + len.write(writer)?; + writer.write_all(endpoint_payload)?; + Ok(()) + } +} + +#[cfg(test)] +mod test { + use crate::{ + chain_id::ChainId, endpoints::wormhole::WormholeEndpoint, + normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, + }; + + use super::*; + // + #[test] + fn test_deserialize_endpoint_message() { + let data = hex::decode("9945ff10042942fafabe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe0000000000000000000000000000000000000000000000000000000000110000").unwrap(); + let mut vec = &data[..]; + let message: EndpointMessage = + TypePrefixedPayload::read_payload(&mut vec).unwrap(); + + let expected = EndpointMessage { + _phantom: PhantomData::, + message_data: EndpointMessageData { + source_manager: [ + 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + manager_payload: ManagerMessage { + sequence: 233968345345, + sender: [ + 0x46, 0x67, 0x92, 0x13, 0x41, 0x23, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + payload: NativeTokenTransfer { + amount: NormalizedAmount { + amount: 1234567, + decimals: 7, + }, + source_token: [ + 0xBE, 0xEF, 0xFA, 0xCE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + to_chain: ChainId { id: 17 }, + to: [ + 0xFE, 0xEB, 0xCA, 0xFE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + ], + }, + }, + }, + endpoint_payload: vec![], + }; + assert_eq!(message, expected); + assert_eq!(vec.len(), 0); + + let encoded = TypePrefixedPayload::to_vec_payload(&expected); + assert_eq!(encoded, data); + } +} diff --git a/solana/modules/ntt-messages/src/endpoints/mod.rs b/solana/modules/ntt-messages/src/endpoints/mod.rs new file mode 100644 index 000000000..a639b60a4 --- /dev/null +++ b/solana/modules/ntt-messages/src/endpoints/mod.rs @@ -0,0 +1,2 @@ +#[cfg(feature = "wormhole")] +pub mod wormhole; diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs b/solana/modules/ntt-messages/src/endpoints/wormhole.rs similarity index 84% rename from solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs rename to solana/modules/ntt-messages/src/endpoints/wormhole.rs index d387a3fd3..92119a7b3 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/messages.rs +++ b/solana/modules/ntt-messages/src/endpoints/wormhole.rs @@ -1,4 +1,4 @@ -use crate::messages::Endpoint; +use crate::endpoint::Endpoint; #[derive(PartialEq, Eq, Clone, Debug)] pub struct WormholeEndpoint {} diff --git a/solana/modules/ntt-messages/src/lib.rs b/solana/modules/ntt-messages/src/lib.rs new file mode 100644 index 000000000..d4450d4d8 --- /dev/null +++ b/solana/modules/ntt-messages/src/lib.rs @@ -0,0 +1,7 @@ +pub mod chain_id; +pub mod endpoint; +pub mod endpoints; +pub mod manager; +pub mod normalized_amount; +pub mod ntt; +pub mod utils; diff --git a/solana/modules/ntt-messages/src/manager.rs b/solana/modules/ntt-messages/src/manager.rs new file mode 100644 index 000000000..c4a8f850c --- /dev/null +++ b/solana/modules/ntt-messages/src/manager.rs @@ -0,0 +1,85 @@ +use std::io; + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::*; + +use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; + +use crate::utils::maybe_space::MaybeSpace; + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + feature = "anchor", + derive(AnchorSerialize, AnchorDeserialize, InitSpace) +)] +pub struct ManagerMessage { + pub sequence: u64, + pub sender: [u8; 32], + pub payload: A, +} + +#[cfg(feature = "hash")] +impl ManagerMessage +where + ManagerMessage: TypePrefixedPayload, +{ + pub fn keccak256(&self, chain_id: crate::chain_id::ChainId) -> solana_program::keccak::Hash { + let mut bytes: Vec = Vec::new(); + bytes.extend_from_slice(&chain_id.id.to_be_bytes()); + bytes.extend_from_slice(&TypePrefixedPayload::to_vec_payload(self)); + solana_program::keccak::hash(&bytes) + } +} + +impl TypePrefixedPayload for ManagerMessage { + const TYPE: Option = None; +} + +impl Readable for ManagerMessage { + const SIZE: Option = None; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let sequence = Readable::read(reader)?; + let sender = Readable::read(reader)?; + // TODO: same as below for manager payload + let _payload_len: u16 = Readable::read(reader)?; + let payload = A::read_payload(reader)?; + + Ok(Self { + sequence, + sender, + payload, + }) + } +} + +impl Writeable for ManagerMessage { + fn written_size(&self) -> usize { + u64::SIZE.unwrap() + + self.sender.len() + + u16::SIZE.unwrap() // payload length + + self.payload.written_size() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let ManagerMessage { + sequence, + sender, + payload, + } = self; + + sequence.write(writer)?; + writer.write_all(sender)?; + let len: u16 = u16::try_from(payload.written_size()).expect("u16 overflow"); + len.write(writer)?; + // TODO: same as above + A::write_payload(payload, writer) + } +} diff --git a/solana/programs/example-native-token-transfers/src/normalized_amount.rs b/solana/modules/ntt-messages/src/normalized_amount.rs similarity index 95% rename from solana/programs/example-native-token-transfers/src/normalized_amount.rs rename to solana/modules/ntt-messages/src/normalized_amount.rs index 5f46069ba..f4647c614 100644 --- a/solana/programs/example-native-token-transfers/src/normalized_amount.rs +++ b/solana/modules/ntt-messages/src/normalized_amount.rs @@ -9,12 +9,18 @@ use std::io; +#[cfg(feature = "anchor")] use anchor_lang::prelude::*; + use wormhole_io::{Readable, Writeable}; pub const NORMALIZED_DECIMALS: u8 = 8; -#[derive(Debug, Clone, Copy, AnchorSerialize, AnchorDeserialize, InitSpace)] +#[derive(Debug, Clone, Copy)] +#[cfg_attr( + feature = "anchor", + derive(AnchorSerialize, AnchorDeserialize, InitSpace) +)] pub struct NormalizedAmount { pub amount: u64, pub decimals: u8, diff --git a/solana/modules/ntt-messages/src/ntt.rs b/solana/modules/ntt-messages/src/ntt.rs new file mode 100644 index 000000000..9fbce8a70 --- /dev/null +++ b/solana/modules/ntt-messages/src/ntt.rs @@ -0,0 +1,90 @@ +#[cfg(feature = "anchor")] +use anchor_lang::prelude::*; + +use std::io; + +use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; + +use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; + +#[derive(Debug, Clone, PartialEq, Eq)] +#[cfg_attr( + feature = "anchor", + derive(AnchorSerialize, AnchorDeserialize, InitSpace) +)] +pub struct NativeTokenTransfer { + pub amount: NormalizedAmount, + // TODO: is this needed? + pub source_token: [u8; 32], + // TODO: shouldn't we put this in the outer message? + pub to_chain: ChainId, + pub to: [u8; 32], +} + +impl NativeTokenTransfer { + const PREFIX: [u8; 4] = [0x99, 0x4E, 0x54, 0x54]; +} + +impl TypePrefixedPayload for NativeTokenTransfer { + const TYPE: Option = None; +} + +impl Readable for NativeTokenTransfer { + const SIZE: Option = None; + + fn read(reader: &mut R) -> io::Result + where + Self: Sized, + R: io::Read, + { + let prefix: [u8; 4] = Readable::read(reader)?; + if prefix != Self::PREFIX { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "Invalid prefix for NativeTokenTransfer", + )); + } + + let amount = Readable::read(reader)?; + let source_token = Readable::read(reader)?; + let to = Readable::read(reader)?; + let to_chain = Readable::read(reader)?; + + Ok(Self { + amount, + source_token, + to, + to_chain, + }) + } +} + +impl Writeable for NativeTokenTransfer { + fn written_size(&self) -> usize { + Self::PREFIX.len() + + NormalizedAmount::SIZE.unwrap() + + self.source_token.len() + + self.to.len() + + ChainId::SIZE.unwrap() + } + + fn write(&self, writer: &mut W) -> io::Result<()> + where + W: io::Write, + { + let NativeTokenTransfer { + amount, + source_token, + to, + to_chain, + } = self; + + Self::PREFIX.write(writer)?; + amount.write(writer)?; + source_token.write(writer)?; + to.write(writer)?; + to_chain.write(writer)?; + + Ok(()) + } +} diff --git a/solana/modules/ntt-messages/src/utils/maybe_space.rs b/solana/modules/ntt-messages/src/utils/maybe_space.rs new file mode 100644 index 000000000..67b62b513 --- /dev/null +++ b/solana/modules/ntt-messages/src/utils/maybe_space.rs @@ -0,0 +1,12 @@ +#[cfg(feature = "anchor")] +use anchor_lang::prelude::*; + +#[cfg(feature = "anchor")] +pub trait MaybeSpace: Space {} +#[cfg(feature = "anchor")] +impl MaybeSpace for A {} + +#[cfg(not(feature = "anchor"))] +pub trait MaybeSpace {} +#[cfg(not(feature = "anchor"))] +impl MaybeSpace for A {} diff --git a/solana/modules/ntt-messages/src/utils/mod.rs b/solana/modules/ntt-messages/src/utils/mod.rs new file mode 100644 index 000000000..7e1dfa8e0 --- /dev/null +++ b/solana/modules/ntt-messages/src/utils/mod.rs @@ -0,0 +1 @@ +pub mod maybe_space; diff --git a/solana/programs/example-native-token-transfers/Cargo.toml b/solana/programs/example-native-token-transfers/Cargo.toml index 1ea7d58b9..1cf9942cf 100644 --- a/solana/programs/example-native-token-transfers/Cargo.toml +++ b/solana/programs/example-native-token-transfers/Cargo.toml @@ -22,6 +22,7 @@ idl-build = [ [dependencies] ahash = "=0.8.5" +ntt-messages = { path = "../../modules/ntt-messages", features = ["anchor", "hash"] } anchor-lang = { workspace = true, features = ["init-if-needed"] } anchor-spl.workspace = true bitmaps = "3.2.1" diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 6e84d239d..7d04ece31 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -1,8 +1,9 @@ use std::ops::{Deref, DerefMut}; use anchor_lang::prelude::*; +use ntt_messages::chain_id::ChainId; -use crate::{bitmap::Bitmap, chain_id::ChainId}; +use crate::bitmap::Bitmap; #[account] #[derive(InitSpace)] diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs index 3a9d1ed32..0cbaf4106 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/admin.rs @@ -1,6 +1,7 @@ use anchor_lang::prelude::*; +use ntt_messages::chain_id::ChainId; -use crate::{chain_id::ChainId, config::Config, endpoints::accounts::sibling::EndpointSibling}; +use crate::{config::Config, endpoints::accounts::sibling::EndpointSibling}; #[derive(Accounts)] #[instruction(args: SetEndpointSiblingArgs)] diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs index 2d3a876d8..bc85b00e1 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs @@ -1,15 +1,16 @@ use anchor_lang::prelude::*; +use ntt_messages::{ + chain_id::ChainId, + endpoint::{EndpointMessage, EndpointMessageData}, + endpoints::wormhole::WormholeEndpoint, + ntt::NativeTokenTransfer, +}; use wormhole_anchor_sdk::wormhole::PostedVaa; use crate::{ - chain_id::ChainId, - config::*, - endpoints::{accounts::sibling::EndpointSibling, wormhole::messages::WormholeEndpoint}, - error::NTTError, - messages::{ - EndpointMessage, EndpointMessageData, NativeTokenTransfer, ValidatedEndpointMessage, - }, + config::*, endpoints::accounts::sibling::EndpointSibling, error::NTTError, + messages::ValidatedEndpointMessage, }; #[derive(Accounts)] diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs index f62e374f6..77b1f383c 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/release_outbound.rs @@ -1,16 +1,13 @@ use anchor_lang::prelude::*; +use ntt_messages::{ + endpoint::EndpointMessage, endpoints::wormhole::WormholeEndpoint, manager::ManagerMessage, + ntt::NativeTokenTransfer, +}; use wormhole_anchor_sdk::wormhole; use wormhole_io::TypePrefixedPayload; -use crate::{ - config::*, - endpoints::wormhole::messages::WormholeEndpoint, - error::NTTError, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, - queue::outbox::OutboxItem, - registered_endpoint::*, -}; +use crate::{config::*, error::NTTError, queue::outbox::OutboxItem, registered_endpoint::*}; #[derive(Accounts)] pub struct ReleaseOutbound<'info> { diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs index 17544562a..0784027bb 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/mod.rs @@ -1,4 +1,3 @@ pub mod instructions; -pub mod messages; pub use instructions::*; diff --git a/solana/programs/example-native-token-transfers/src/instructions/admin.rs b/solana/programs/example-native-token-transfers/src/instructions/admin.rs index 3d7eaceab..bf6e07dd4 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/admin.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/admin.rs @@ -1,11 +1,11 @@ use anchor_lang::prelude::*; +use ntt_messages::chain_id::ChainId; use wormhole_solana_utils::cpi::bpf_loader_upgradeable::{self, BpfLoaderUpgradeable}; #[cfg(feature = "idl-build")] use crate::messages::Hack; use crate::{ - chain_id::ChainId, config::Config, error::NTTError, queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit, rate_limit::RateLimitState}, diff --git a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs index 2796bb9bf..525da4d49 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/initialize.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/initialize.rs @@ -1,5 +1,6 @@ use anchor_lang::prelude::*; use anchor_spl::{associated_token::AssociatedToken, token_interface}; +use ntt_messages::chain_id::ChainId; use wormhole_solana_utils::cpi::bpf_loader_upgradeable::BpfLoaderUpgradeable; #[cfg(feature = "idl-build")] @@ -7,7 +8,6 @@ use crate::messages::Hack; use crate::{ bitmap::Bitmap, - chain_id::ChainId, error::NTTError, queue::{outbox::OutboxRateLimit, rate_limit::RateLimitState}, sequence::Sequence, diff --git a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs index 5b61dac23..62b0889af 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/redeem.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/redeem.rs @@ -1,11 +1,12 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; +use ntt_messages::{manager::ManagerMessage, ntt::NativeTokenTransfer}; use crate::{ bitmap::Bitmap, config::*, error::NTTError, - messages::{ManagerMessage, NativeTokenTransfer, ValidatedEndpointMessage}, + messages::ValidatedEndpointMessage, queue::{ inbox::{InboxItem, InboxRateLimit, ReleaseStatus}, outbox::OutboxRateLimit, diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 085d84414..5c586e1d8 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -1,12 +1,11 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface; +use ntt_messages::{chain_id::ChainId, normalized_amount::NormalizedAmount}; use crate::{ bitmap::Bitmap, - chain_id::ChainId, config::*, error::NTTError, - normalized_amount::NormalizedAmount, queue::{ inbox::InboxRateLimit, outbox::{OutboxItem, OutboxRateLimit}, diff --git a/solana/programs/example-native-token-transfers/src/lib.rs b/solana/programs/example-native-token-transfers/src/lib.rs index d28b3bb1f..e122a2a96 100644 --- a/solana/programs/example-native-token-transfers/src/lib.rs +++ b/solana/programs/example-native-token-transfers/src/lib.rs @@ -1,14 +1,12 @@ use anchor_lang::prelude::*; pub mod bitmap; -pub mod chain_id; pub mod clock; pub mod config; pub mod endpoints; pub mod error; pub mod instructions; pub mod messages; -pub mod normalized_amount; pub mod queue; pub mod registered_endpoint; pub mod sequence; diff --git a/solana/programs/example-native-token-transfers/src/messages.rs b/solana/programs/example-native-token-transfers/src/messages.rs index e21d6af0b..99c598322 100644 --- a/solana/programs/example-native-token-transfers/src/messages.rs +++ b/solana/programs/example-native-token-transfers/src/messages.rs @@ -1,164 +1,6 @@ use anchor_lang::prelude::*; -use core::fmt; -use solana_program::keccak::Hash; -use std::{collections::HashMap, io, marker::PhantomData}; - -use wormhole_io::{Readable, TypePrefixedPayload, Writeable}; - -use crate::{chain_id::ChainId, normalized_amount::NormalizedAmount}; - -// TODO: might make sense to break this up into multiple files - -#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize, InitSpace)] -pub struct ManagerMessage { - pub sequence: u64, - pub sender: [u8; 32], - pub payload: A, -} - -impl ManagerMessage { - pub fn keccak256(&self, chain_id: ChainId) -> Hash { - let mut bytes: Vec = Vec::new(); - bytes.extend_from_slice(&chain_id.id.to_be_bytes()); - bytes.extend_from_slice(&TypePrefixedPayload::to_vec_payload(self)); - solana_program::keccak::hash(&bytes) - } -} - -impl TypePrefixedPayload for ManagerMessage { - const TYPE: Option = None; -} - -impl Readable for ManagerMessage { - const SIZE: Option = None; - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read, - { - let sequence = Readable::read(reader)?; - let sender = Readable::read(reader)?; - // TODO: same as below for manager payload - let _payload_len: u16 = Readable::read(reader)?; - let payload = A::read_payload(reader)?; - - Ok(Self { - sequence, - sender, - payload, - }) - } -} - -impl Writeable for ManagerMessage { - fn written_size(&self) -> usize { - u64::SIZE.unwrap() - + self.sender.len() - + u16::SIZE.unwrap() // payload length - + self.payload.written_size() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - let ManagerMessage { - sequence, - sender, - payload, - } = self; - - sequence.write(writer)?; - writer.write_all(sender)?; - let len: u16 = u16::try_from(payload.written_size()).expect("u16 overflow"); - len.write(writer)?; - // TODO: same as above - A::write_payload(payload, writer) - } -} - -#[derive(Debug, Clone, PartialEq, Eq, AnchorSerialize, AnchorDeserialize, InitSpace)] -pub struct NativeTokenTransfer { - pub amount: NormalizedAmount, - // TODO: is this needed? - pub source_token: [u8; 32], - // TODO: shouldn't we put this in the outer message? - pub to_chain: ChainId, - pub to: [u8; 32], -} - -impl NativeTokenTransfer { - const PREFIX: [u8; 4] = [0x99, 0x4E, 0x54, 0x54]; -} - -impl TypePrefixedPayload for NativeTokenTransfer { - const TYPE: Option = None; -} - -impl Readable for NativeTokenTransfer { - const SIZE: Option = None; - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read, - { - let prefix: [u8; 4] = Readable::read(reader)?; - if prefix != Self::PREFIX { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Invalid prefix for NativeTokenTransfer", - )); - } - - let amount = Readable::read(reader)?; - let source_token = Readable::read(reader)?; - let to = Readable::read(reader)?; - let to_chain = Readable::read(reader)?; - - Ok(Self { - amount, - source_token, - to, - to_chain, - }) - } -} - -impl Writeable for NativeTokenTransfer { - fn written_size(&self) -> usize { - Self::PREFIX.len() - + NormalizedAmount::SIZE.unwrap() - + self.source_token.len() - + self.to.len() - + ChainId::SIZE.unwrap() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - let NativeTokenTransfer { - amount, - source_token, - to, - to_chain, - } = self; - - Self::PREFIX.write(writer)?; - amount.write(writer)?; - source_token.write(writer)?; - to.write(writer)?; - to_chain.write(writer)?; - - Ok(()) - } -} - -pub trait Endpoint { - const PREFIX: [u8; 4]; -} +use ntt_messages::{chain_id::ChainId, endpoint::EndpointMessageData}; +use std::{collections::HashMap, marker::PhantomData}; #[account] #[derive(InitSpace)] @@ -171,157 +13,6 @@ impl ValidatedEndpointMe pub const SEED_PREFIX: &'static [u8] = b"endpoint_message"; } -#[derive(Debug, PartialEq, Eq, InitSpace, Clone, AnchorSerialize, AnchorDeserialize)] -pub struct EndpointMessageData { - pub source_manager: [u8; 32], - pub manager_payload: ManagerMessage, -} - -#[derive(Eq, PartialEq, Clone, Debug)] -pub struct EndpointMessage { - _phantom: PhantomData, - // TODO: check sibling registration at the manager level - pub message_data: EndpointMessageData, - pub endpoint_payload: Vec, -} - -impl std::ops::Deref for EndpointMessage { - type Target = EndpointMessageData; - - fn deref(&self) -> &Self::Target { - &self.message_data - } -} - -impl std::ops::DerefMut for EndpointMessage { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.message_data - } -} - -impl AnchorDeserialize for EndpointMessage -where - A: Space, -{ - fn deserialize_reader(reader: &mut R) -> io::Result { - Readable::read(reader) - } -} - -impl AnchorSerialize for EndpointMessage -where - A: Space, -{ - fn serialize(&self, writer: &mut W) -> io::Result<()> { - Writeable::write(self, writer) - } -} - -impl EndpointMessage -where - A: Space, -{ - pub fn new( - source_manager: [u8; 32], - manager_payload: ManagerMessage, - endpoint_payload: Vec, - ) -> Self { - Self { - _phantom: PhantomData, - message_data: EndpointMessageData { - source_manager, - manager_payload, - }, - endpoint_payload, - } - } -} - -impl TypePrefixedPayload - for EndpointMessage -where - A: Space + Clone, -{ - const TYPE: Option = None; -} - -impl Readable for EndpointMessage -where - A: Space, -{ - const SIZE: Option = None; - - fn read(reader: &mut R) -> io::Result - where - Self: Sized, - R: io::Read, - { - let prefix: [u8; 4] = Readable::read(reader)?; - if prefix != E::PREFIX { - return Err(io::Error::new( - io::ErrorKind::InvalidData, - "Invalid prefix for EndpointMessage", - )); - } - - let source_manager = Readable::read(reader)?; - // TODO: we need a way to easily check that decoding the payload - // consumes the expected amount of bytes - let _manager_payload_len: u16 = Readable::read(reader)?; - let manager_payload = ManagerMessage::read(reader)?; - let endpoint_payload_len: u16 = Readable::read(reader)?; - let mut endpoint_payload = vec![0; endpoint_payload_len as usize]; - reader.read_exact(&mut endpoint_payload)?; - - Ok(EndpointMessage::new( - source_manager, - manager_payload, - endpoint_payload, - )) - } -} - -impl Writeable for EndpointMessage -where - A: Space, -{ - fn written_size(&self) -> usize { - 4 // prefix - + self.source_manager.len() - + u16::SIZE.unwrap() // length prefix - + self.manager_payload.written_size() - } - - fn write(&self, writer: &mut W) -> io::Result<()> - where - W: io::Write, - { - let EndpointMessage { - _phantom, - message_data: - EndpointMessageData { - source_manager, - manager_payload, - }, - endpoint_payload, - } = self; - - E::PREFIX.write(writer)?; - source_manager.write(writer)?; - let len: u16 = u16::try_from(manager_payload.written_size()).expect("u16 overflow"); - len.write(writer)?; - // TODO: review this in wormhole-io. The written_size logic is error prone. Instead, - // a better API would be - // foo.write_with_prefix_be::(writer) - // which writes the length as a big endian u16. - manager_payload.write(writer)?; - let len: u16 = u16::try_from(endpoint_payload.len()).expect("u16 overflow"); - len.write(writer)?; - writer.write_all(endpoint_payload)?; - Ok(()) - } -} - // This is a hack to get around the fact that the IDL generator doesn't support // PhantomData. The generator uses the following functions, so we just mix them onto PhantomData. // @@ -354,56 +45,3 @@ impl Hack for ProgramData { None } } - -#[cfg(test)] -mod test { - use crate::endpoints::wormhole::messages::WormholeEndpoint; - - use super::*; - // - #[test] - fn test_deserialize_endpoint_message() { - let data = hex::decode("9945ff10042942fafabe00000000000000000000000000000000000000000000000000000079000000367999a1014667921341234300000000000000000000000000000000000000000000000000004f994e545407000000000012d687beefface00000000000000000000000000000000000000000000000000000000feebcafe0000000000000000000000000000000000000000000000000000000000110000").unwrap(); - let mut vec = &data[..]; - let message: EndpointMessage = - TypePrefixedPayload::read_payload(&mut vec).unwrap(); - - let expected = EndpointMessage { - _phantom: PhantomData::, - message_data: EndpointMessageData { - source_manager: [ - 0x04, 0x29, 0x42, 0xFA, 0xFA, 0xBE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - manager_payload: ManagerMessage { - sequence: 233968345345, - sender: [ - 0x46, 0x67, 0x92, 0x13, 0x41, 0x23, 0x43, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - payload: NativeTokenTransfer { - amount: NormalizedAmount { - amount: 1234567, - decimals: 7, - }, - source_token: [ - 0xBE, 0xEF, 0xFA, 0xCE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - to_chain: ChainId { id: 17 }, - to: [ - 0xFE, 0xEB, 0xCA, 0xFE, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - ], - }, - }, - }, - endpoint_payload: vec![], - }; - assert_eq!(message, expected); - assert_eq!(vec.len(), 0); - - let encoded = TypePrefixedPayload::to_vec_payload(&expected); - assert_eq!(encoded, data); - } -} diff --git a/solana/programs/example-native-token-transfers/src/queue/outbox.rs b/solana/programs/example-native-token-transfers/src/queue/outbox.rs index 43706b884..c1c6d534c 100644 --- a/solana/programs/example-native-token-transfers/src/queue/outbox.rs +++ b/solana/programs/example-native-token-transfers/src/queue/outbox.rs @@ -1,11 +1,9 @@ use std::ops::{Deref, DerefMut}; use anchor_lang::prelude::*; +use ntt_messages::{chain_id::ChainId, normalized_amount::NormalizedAmount}; -use crate::{ - bitmap::*, chain_id::ChainId, clock::current_timestamp, error::NTTError, - normalized_amount::NormalizedAmount, -}; +use crate::{bitmap::*, clock::current_timestamp, error::NTTError}; use super::rate_limit::RateLimitState; diff --git a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs index 123c8b48e..a5fe6899c 100644 --- a/solana/programs/example-native-token-transfers/tests/cancel_flow.rs +++ b/solana/programs/example-native-token-transfers/tests/cancel_flow.rs @@ -3,14 +3,14 @@ use anchor_lang::prelude::*; use common::setup::{TestData, OTHER_CHAIN, OTHER_ENDPOINT, OTHER_MANAGER, THIS_CHAIN}; use example_native_token_transfers::{ - chain_id::ChainId, config::Mode, - endpoints::wormhole::messages::WormholeEndpoint, instructions::{RedeemArgs, TransferArgs}, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, - normalized_amount::NormalizedAmount, queue::{inbox::InboxRateLimit, outbox::OutboxRateLimit}, }; +use ntt_messages::{ + chain_id::ChainId, endpoint::EndpointMessage, endpoints::wormhole::WormholeEndpoint, + manager::ManagerMessage, normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, +}; use sdk::endpoints::wormhole::instructions::receive_message::ReceiveMessage; use solana_program_test::*; use solana_sdk::{signature::Keypair, signer::Signer}; diff --git a/solana/programs/example-native-token-transfers/tests/common/setup.rs b/solana/programs/example-native-token-transfers/tests/common/setup.rs index 57e969b5c..eae479c24 100644 --- a/solana/programs/example-native-token-transfers/tests/common/setup.rs +++ b/solana/programs/example-native-token-transfers/tests/common/setup.rs @@ -3,11 +3,11 @@ use std::path::PathBuf; use anchor_lang::prelude::{Error, Id, Pubkey}; use anchor_spl::token::{Mint, Token}; use example_native_token_transfers::{ - chain_id::ChainId, config::Mode, endpoints::wormhole::SetEndpointSiblingArgs, instructions::{InitializeArgs, SetSiblingArgs}, }; +use ntt_messages::chain_id::ChainId; use solana_program::{bpf_loader_upgradeable::UpgradeableLoaderState, rent::Rent}; use solana_program_runtime::{ invoke_context::ProcessInstructionWithContext, diff --git a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs index 0c9a7ff49..d13c73ebf 100644 --- a/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs +++ b/solana/programs/example-native-token-transfers/tests/sdk/accounts.rs @@ -1,7 +1,6 @@ use anchor_lang::prelude::Pubkey; use example_native_token_transfers::{ config::Config, - messages::{ManagerMessage, NativeTokenTransfer}, queue::{ inbox::{InboxItem, InboxRateLimit}, outbox::OutboxRateLimit, @@ -9,6 +8,7 @@ use example_native_token_transfers::{ registered_endpoint::RegisteredEndpoint, sequence::Sequence, }; +use ntt_messages::{manager::ManagerMessage, ntt::NativeTokenTransfer}; use sha3::{Digest, Keccak256}; use wormhole_anchor_sdk::wormhole; use wormhole_io::TypePrefixedPayload; diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 1dff3178f..6a55dcaf8 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -5,16 +5,17 @@ use anchor_spl::token::{Mint, TokenAccount}; use common::setup::TestData; use example_native_token_transfers::{ bitmap::Bitmap, - chain_id::ChainId, config::Mode, - endpoints::wormhole::{messages::WormholeEndpoint, ReleaseOutboundArgs}, + endpoints::wormhole::ReleaseOutboundArgs, error::NTTError, instructions::TransferArgs, - messages::{EndpointMessage, ManagerMessage, NativeTokenTransfer}, - normalized_amount::NormalizedAmount, queue::outbox::{OutboxItem, OutboxRateLimit}, sequence::Sequence, }; +use ntt_messages::{ + chain_id::ChainId, endpoint::EndpointMessage, manager::ManagerMessage, + normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, endpoints::wormhole::WormholeEndpoint, +}; use solana_program_test::*; use solana_sdk::{ instruction::InstructionError, signature::Keypair, signer::Signer, From 389de519a0b5dfd5517c6a6a8fa024ac823b1a5e Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 17:35:35 -0500 Subject: [PATCH 88/90] solana: some clean up --- solana/migrations/deploy.ts | 12 ------------ .../src/endpoints/accounts/sibling.rs | 1 - .../wormhole/instructions/receive_message.rs | 3 +++ .../src/endpoints/wormhole/instructions/redeem.rs | 0 4 files changed, 3 insertions(+), 13 deletions(-) delete mode 100644 solana/migrations/deploy.ts delete mode 100644 solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/redeem.rs diff --git a/solana/migrations/deploy.ts b/solana/migrations/deploy.ts deleted file mode 100644 index 82fb175fa..000000000 --- a/solana/migrations/deploy.ts +++ /dev/null @@ -1,12 +0,0 @@ -// Migrations are an early feature. Currently, they're nothing more than this -// single deploy script that's invoked from the CLI, injecting a provider -// configured from the workspace's Anchor.toml. - -const anchor = require("@coral-xyz/anchor"); - -module.exports = async function (provider) { - // Configure client to use the provider. - anchor.setProvider(provider); - - // Add your deploy script here. -}; diff --git a/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs b/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs index cbc45579a..84c941e3b 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/accounts/sibling.rs @@ -5,7 +5,6 @@ use anchor_lang::prelude::*; /// A sibling on another chain. Stored in a PDA seeded by the chain id. pub struct EndpointSibling { pub bump: u8, - // TODO: variable address length? pub address: [u8; 32], } diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs index bc85b00e1..cb3f75568 100644 --- a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs +++ b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/receive_message.rs @@ -28,6 +28,9 @@ pub struct ReceiveMessage<'info> { )] pub sibling: Account<'info, EndpointSibling>, + // TODO: Consider using VaaAccount from wormhole-solana-vaa crate. Using a zero-copy reader + // will allow this instruction to be generic (instead of strictly specifying NativeTokenTransfer + // as the message type). #[account( // check that the messages is targeted to this chain constraint = vaa.message().manager_payload.payload.to_chain == config.chain_id @ NTTError::InvalidChainId, diff --git a/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/redeem.rs b/solana/programs/example-native-token-transfers/src/endpoints/wormhole/instructions/redeem.rs deleted file mode 100644 index e69de29bb..000000000 From 5e444b36b1c93013a8d6e635e89368e29595c533 Mon Sep 17 00:00:00 2001 From: A5 Pickle Date: Thu, 22 Feb 2024 16:34:29 -0500 Subject: [PATCH 89/90] solana: fail on wrong mode earlier; one less timestamp call --- .../src/config.rs | 9 ++ .../src/instructions/transfer.rs | 82 ++++++++++--------- .../src/queue/rate_limit.rs | 7 +- 3 files changed, 57 insertions(+), 41 deletions(-) diff --git a/solana/programs/example-native-token-transfers/src/config.rs b/solana/programs/example-native-token-transfers/src/config.rs index 7d04ece31..6a1668017 100644 --- a/solana/programs/example-native-token-transfers/src/config.rs +++ b/solana/programs/example-native-token-transfers/src/config.rs @@ -68,3 +68,12 @@ pub enum Mode { Burning, Locking, } + +impl std::fmt::Display for Mode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Mode::Burning => write!(f, "Burning"), + Mode::Locking => write!(f, "Locking"), + } + } +} diff --git a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs index 5c586e1d8..abb10058a 100644 --- a/solana/programs/example-native-token-transfers/src/instructions/transfer.rs +++ b/solana/programs/example-native-token-transfers/src/instructions/transfer.rs @@ -95,6 +95,12 @@ pub struct TransferBurn<'info> { // TODO: fees for relaying? pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<()> { + require_eq!( + ctx.accounts.common.config.mode, + Mode::Burning, + NTTError::InvalidMode + ); + let accs = ctx.accounts; let TransferArgs { amount, @@ -106,24 +112,21 @@ pub fn transfer_burn(ctx: Context, args: TransferArgs) -> Result<( // TODO: should we revert if we have dust? let amount = NormalizedAmount::remove_dust(amount, accs.common.mint.decimals); - match accs.common.config.mode { - Mode::Burning => token_interface::burn( - CpiContext::new_with_signer( - accs.common.token_program.to_account_info(), - token_interface::Burn { - mint: accs.common.mint.to_account_info(), - from: accs.common.from.to_account_info(), - authority: accs.common.token_authority.to_account_info(), - }, - &[&[ - crate::TOKEN_AUTHORITY_SEED, - &[ctx.bumps.common.token_authority], - ]], - ), - amount, - )?, - Mode::Locking => return Err(NTTError::InvalidMode.into()), - } + token_interface::burn( + CpiContext::new_with_signer( + accs.common.token_program.to_account_info(), + token_interface::Burn { + mint: accs.common.mint.to_account_info(), + from: accs.common.from.to_account_info(), + authority: accs.common.token_authority.to_account_info(), + }, + &[&[ + crate::TOKEN_AUTHORITY_SEED, + &[ctx.bumps.common.token_authority], + ]], + ), + amount, + )?; insert_into_outbox( &mut accs.common, @@ -162,6 +165,12 @@ pub struct TransferLock<'info> { // TODO: fees for relaying? // TODO: factor out common bits pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<()> { + require_eq!( + ctx.accounts.common.config.mode, + Mode::Locking, + NTTError::InvalidMode + ); + let accs = ctx.accounts; let TransferArgs { amount, @@ -173,26 +182,23 @@ pub fn transfer_lock(ctx: Context, args: TransferArgs) -> Result<( // TODO: should we revert if we have dust? let amount = NormalizedAmount::remove_dust(amount, accs.common.mint.decimals); - match accs.common.config.mode { - Mode::Burning => return Err(NTTError::InvalidMode.into()), - Mode::Locking => token_interface::transfer_checked( - CpiContext::new_with_signer( - accs.common.token_program.to_account_info(), - token_interface::TransferChecked { - from: accs.common.from.to_account_info(), - to: accs.custody.to_account_info(), - authority: accs.common.token_authority.to_account_info(), - mint: accs.common.mint.to_account_info(), - }, - &[&[ - crate::TOKEN_AUTHORITY_SEED, - &[ctx.bumps.common.token_authority], - ]], - ), - amount, - accs.common.mint.decimals, - )?, - } + token_interface::transfer_checked( + CpiContext::new_with_signer( + accs.common.token_program.to_account_info(), + token_interface::TransferChecked { + from: accs.common.from.to_account_info(), + to: accs.custody.to_account_info(), + authority: accs.common.token_authority.to_account_info(), + mint: accs.common.mint.to_account_info(), + }, + &[&[ + crate::TOKEN_AUTHORITY_SEED, + &[ctx.bumps.common.token_authority], + ]], + ), + amount, + accs.common.mint.decimals, + )?; insert_into_outbox( &mut accs.common, diff --git a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs index 8cda07f08..a0b36ea83 100644 --- a/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs +++ b/solana/programs/example-native-token-transfers/src/queue/rate_limit.rs @@ -94,13 +94,14 @@ impl RateLimitState { /// Refills the capacity by the given amount. /// This is used to replenish the capacity via backflows. pub fn refill(&mut self, now: UnixTimestamp, amount: u64) { - self.capacity_at_last_tx = self.capacity().saturating_add(amount).min(self.limit); + self.capacity_at_last_tx = self.capacity_at(now).saturating_add(amount).min(self.limit); self.last_tx_timestamp = now; } pub fn set_limit(&mut self, limit: u64) { let old_limit = self.limit; - let current_capacity = self.capacity(); + let now = current_timestamp(); + let current_capacity = self.capacity_at(now); self.limit = limit; @@ -115,7 +116,7 @@ impl RateLimitState { }; self.capacity_at_last_tx = new_capacity.min(limit); - self.last_tx_timestamp = current_timestamp(); + self.last_tx_timestamp = now; } } From 59fdd271c4f6a726a114b09728fcfacf0b92a17c Mon Sep 17 00:00:00 2001 From: Csongor Kiss Date: Thu, 22 Feb 2024 17:42:58 -0500 Subject: [PATCH 90/90] cargo fmt --- solana/modules/ntt-messages/src/chain_id.rs | 5 ++++- .../example-native-token-transfers/tests/transfer.rs | 4 ++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/solana/modules/ntt-messages/src/chain_id.rs b/solana/modules/ntt-messages/src/chain_id.rs index f7049940d..910455e0a 100644 --- a/solana/modules/ntt-messages/src/chain_id.rs +++ b/solana/modules/ntt-messages/src/chain_id.rs @@ -6,7 +6,10 @@ use anchor_lang::prelude::*; use wormhole_io::{Readable, Writeable}; #[derive(Clone, Debug, PartialEq, Eq, Copy)] -#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize, InitSpace))] +#[cfg_attr( + feature = "anchor", + derive(AnchorSerialize, AnchorDeserialize, InitSpace) +)] pub struct ChainId { pub id: u16, } diff --git a/solana/programs/example-native-token-transfers/tests/transfer.rs b/solana/programs/example-native-token-transfers/tests/transfer.rs index 6a55dcaf8..627e045e6 100644 --- a/solana/programs/example-native-token-transfers/tests/transfer.rs +++ b/solana/programs/example-native-token-transfers/tests/transfer.rs @@ -13,8 +13,8 @@ use example_native_token_transfers::{ sequence::Sequence, }; use ntt_messages::{ - chain_id::ChainId, endpoint::EndpointMessage, manager::ManagerMessage, - normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, endpoints::wormhole::WormholeEndpoint, + chain_id::ChainId, endpoint::EndpointMessage, endpoints::wormhole::WormholeEndpoint, + manager::ManagerMessage, normalized_amount::NormalizedAmount, ntt::NativeTokenTransfer, }; use solana_program_test::*; use solana_sdk::{