From cb04f7fa696c5f97def38d551650ae016549763a Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sat, 18 May 2024 10:14:50 +0400 Subject: [PATCH 01/11] add token-voter program, upgrade anchor to 0.30.0, add tests --- Anchor.toml | 7 +- Cargo.lock | 4367 +++++++++++------ Cargo.toml | 4 + package.json | 6 +- programs/gateway/Cargo.toml | 27 +- .../src/instructions/configure_registrar.rs | 4 +- .../tests/program_test/gateway_voter_test.rs | 8 +- .../tests/program_test/program_test_bench.rs | 2 +- programs/nft-voter/Cargo.toml | 27 +- .../src/instructions/configure_collection.rs | 4 +- .../nft-voter/src/tools/token_metadata.rs | 9 +- .../tests/program_test/token_metadata_test.rs | 146 +- programs/realm-voter/Cargo.toml | 17 +- .../configure_governance_program.rs | 10 +- .../instructions/configure_voter_weights.rs | 4 +- .../src/state/max_voter_weight_record.rs | 1 - programs/realm-voter/src/state/registrar.rs | 5 +- .../tests/program_test/program_test_bench.rs | 14 +- programs/token-voter/Cargo.toml | 42 + programs/token-voter/Xargo.toml | 2 + programs/token-voter/src/error.rs | 190 + programs/token-voter/src/governance.rs | 217 + .../src/instructions/close_voter.rs | 79 + .../src/instructions/configure_mint_config.rs | 111 + .../create_max_voter_weight_record.rs | 60 + .../src/instructions/create_registrar.rs | 81 + .../create_voter_weight_record.rs | 80 + .../token-voter/src/instructions/deposit.rs | 170 + programs/token-voter/src/instructions/mod.rs | 20 + .../token-voter/src/instructions/withdraw.rs | 154 + programs/token-voter/src/lib.rs | 70 + .../token-voter/src/state/deposit_entry.rs | 43 + programs/token-voter/src/state/mod.rs | 11 + programs/token-voter/src/state/registrar.rs | 156 + programs/token-voter/src/state/voter.rs | 107 + .../src/state/voting_mint_config.rs | 43 + programs/token-voter/src/tools/mod.rs | 1 + programs/token-voter/src/tools/spl_token.rs | 683 +++ .../tests/configure_voter_weights.rs | 200 + .../tests/create_max_voter_weight_record.rs | 103 + .../token-voter/tests/create_registrar.rs | 200 + programs/token-voter/tests/deposit.rs | 647 +++ .../tests/fixtures/spl_governance.so | Bin 0 -> 673864 bytes .../tests/fixtures/spl_governance_2022.so | Bin 0 -> 739288 bytes .../tests/program_test/governance_test.rs | 530 ++ .../token-voter/tests/program_test/mod.rs | 39 + .../tests/program_test/program_test_bench.rs | 819 ++++ .../tests/program_test/token_voter_test.rs | 662 +++ .../token-voter/tests/program_test/tools.rs | 80 + programs/token-voter/tests/withdraw.rs | 699 +++ rust-toolchain.toml | 2 +- src/gateway/client.ts | 16 +- src/gateway/gateway.json | 510 ++ src/gateway/gateway.ts | 827 ++-- src/index.ts | 2 + src/nftVoter/client.ts | 17 +- src/nftVoter/nft_voter.json | 822 ++++ src/nftVoter/nft_voter.ts | 1437 +++--- src/realmVoter/client.ts | 16 +- src/realmVoter/realm_voter.json | 747 +++ src/realmVoter/realm_voter.ts | 1100 ++--- src/tokenVoter/client.ts | 17 + src/tokenVoter/token_voter.json | 941 ++++ src/tokenVoter/token_voter.ts | 947 ++++ tsconfig.json | 1 + yarn.lock | 495 +- 66 files changed, 14942 insertions(+), 3916 deletions(-) create mode 100644 programs/token-voter/Cargo.toml create mode 100644 programs/token-voter/Xargo.toml create mode 100644 programs/token-voter/src/error.rs create mode 100644 programs/token-voter/src/governance.rs create mode 100644 programs/token-voter/src/instructions/close_voter.rs create mode 100644 programs/token-voter/src/instructions/configure_mint_config.rs create mode 100644 programs/token-voter/src/instructions/create_max_voter_weight_record.rs create mode 100644 programs/token-voter/src/instructions/create_registrar.rs create mode 100644 programs/token-voter/src/instructions/create_voter_weight_record.rs create mode 100644 programs/token-voter/src/instructions/deposit.rs create mode 100644 programs/token-voter/src/instructions/mod.rs create mode 100644 programs/token-voter/src/instructions/withdraw.rs create mode 100644 programs/token-voter/src/lib.rs create mode 100644 programs/token-voter/src/state/deposit_entry.rs create mode 100644 programs/token-voter/src/state/mod.rs create mode 100644 programs/token-voter/src/state/registrar.rs create mode 100644 programs/token-voter/src/state/voter.rs create mode 100644 programs/token-voter/src/state/voting_mint_config.rs create mode 100644 programs/token-voter/src/tools/mod.rs create mode 100644 programs/token-voter/src/tools/spl_token.rs create mode 100644 programs/token-voter/tests/configure_voter_weights.rs create mode 100644 programs/token-voter/tests/create_max_voter_weight_record.rs create mode 100644 programs/token-voter/tests/create_registrar.rs create mode 100644 programs/token-voter/tests/deposit.rs create mode 100755 programs/token-voter/tests/fixtures/spl_governance.so create mode 100755 programs/token-voter/tests/fixtures/spl_governance_2022.so create mode 100644 programs/token-voter/tests/program_test/governance_test.rs create mode 100644 programs/token-voter/tests/program_test/mod.rs create mode 100644 programs/token-voter/tests/program_test/program_test_bench.rs create mode 100644 programs/token-voter/tests/program_test/token_voter_test.rs create mode 100644 programs/token-voter/tests/program_test/tools.rs create mode 100644 programs/token-voter/tests/withdraw.rs create mode 100644 src/gateway/gateway.json create mode 100644 src/nftVoter/nft_voter.json create mode 100644 src/realmVoter/realm_voter.json create mode 100644 src/tokenVoter/client.ts create mode 100644 src/tokenVoter/token_voter.json create mode 100644 src/tokenVoter/token_voter.ts diff --git a/Anchor.toml b/Anchor.toml index 95d18c01..61c3ebf2 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -1,9 +1,12 @@ -anchor_version = "0.26.0" -solana_version = "1.14.16" +anchor_version = "0.30.0" +solana_version = "1.18.12" [features] seeds = false +[toolchain] +anchor_version = "0.30.0" + [programs.localnet] nft_voter = "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw" gateway = "GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk" diff --git a/Cargo.lock b/Cargo.lock index 78e5a9d5..b871571a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,15 @@ dependencies = [ "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" @@ -34,7 +43,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" dependencies = [ "cfg-if", - "cipher 0.3.0", + "cipher", "cpufeatures", "opaque-debug", ] @@ -47,7 +56,7 @@ checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" dependencies = [ "aead", "aes", - "cipher 0.3.0", + "cipher", "ctr", "polyval", "subtle", @@ -56,20 +65,33 @@ dependencies = [ [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" +dependencies = [ + "getrandom 0.2.15", + "once_cell", + "version_check", +] + +[[package]] +name = "ahash" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "77c3a9648d43b9cd48db467b3f87fdd6e146bcc88ab0180006cef2179fe11d01" dependencies = [ - "getrandom 0.2.5", + "cfg-if", + "getrandom 0.2.15", "once_cell", "version_check", + "zerocopy", ] [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] @@ -97,177 +119,203 @@ dependencies = [ [[package]] name = "anchor-attribute-access-control" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" +checksum = "dd7368e171b3a317885dc08ec0f74eed9d0ad6c726cc819593aed81440dca926" dependencies = [ "anchor-syn", - "anyhow", - "proc-macro2 1.0.59", - "quote 1.0.28", - "regex", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-account" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bcd731f21048a032be27c7791701120e44f3f6371358fc4261a7f716283d29" +checksum = "f527df85a8cba3f2bea04e46ed71b66e525ea378c7fec538aa205f4520b73e31" dependencies = [ "anchor-syn", - "anyhow", - "bs58 0.4.0", - "proc-macro2 1.0.59", - "quote 1.0.28", - "rustversion", + "bs58 0.5.1", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-constant" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" +checksum = "3eb1dc1845cf8636c2e046a274ca074dabd3884ac8ed11cc4ed64b7e8ef5a318" dependencies = [ "anchor-syn", - "proc-macro2 1.0.59", + "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-error" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" +checksum = "7f382e41514c59a77ffa7bb1a47df9a0359564a749b6934485c742c11962e540" dependencies = [ "anchor-syn", - "proc-macro2 1.0.59", - "quote 1.0.28", + "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-event" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" +checksum = "473a122aeed3f6b666438236338d2ef7833ee5fdc5688e1baa80185d61088a53" dependencies = [ "anchor-syn", - "anyhow", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] -name = "anchor-attribute-interface" -version = "0.26.0" +name = "anchor-attribute-program" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6700a6f5c888a9c33fe8afc0c64fd8575fa28d05446037306d0f96102ae4480" +checksum = "7f88c7ffe2eb40aeac43ffd0d74a6671581158aedfaa0552330a2ef92fa5c889" dependencies = [ + "anchor-lang-idl", "anchor-syn", "anyhow", + "bs58 0.5.1", "heck 0.3.3", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", + "serde_json", "syn 1.0.109", ] [[package]] -name = "anchor-attribute-program" -version = "0.26.0" +name = "anchor-derive-accounts" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" +checksum = "ed9b97c99dcec135aae0ff908c14bcfcd3e78cfc16a0c6f245135038f0e6d390" dependencies = [ "anchor-syn", - "anyhow", - "proc-macro2 1.0.59", - "quote 1.0.28", + "quote", "syn 1.0.109", ] [[package]] -name = "anchor-attribute-state" -version = "0.26.0" +name = "anchor-derive-serde" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" +checksum = "bbece98f6ad9c37070edc0841326c9623a249346cd74f433e7cef69b14f7f31d" dependencies = [ "anchor-syn", - "anyhow", - "proc-macro2 1.0.59", - "quote 1.0.28", + "borsh-derive-internal 0.10.3", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] -name = "anchor-derive-accounts" -version = "0.26.0" +name = "anchor-derive-space" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" +checksum = "8badbe2648bc99a85ee05a7a5f9512e5e2af8ffac71476a69350cb278057ac53" dependencies = [ - "anchor-syn", - "anyhow", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "anchor-lang" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662ceafe667448ee4199a4be2ee83b6bb76da28566eee5cea05f96ab38255af8" +checksum = "e41feb9c1cd9f4b0fad1c004fc8f289183f3ce27e9db38fa6e434470c716fb1e" dependencies = [ "anchor-attribute-access-control", "anchor-attribute-account", "anchor-attribute-constant", "anchor-attribute-error", "anchor-attribute-event", - "anchor-attribute-interface", "anchor-attribute-program", - "anchor-attribute-state", "anchor-derive-accounts", + "anchor-derive-serde", + "anchor-derive-space", + "anchor-lang-idl", "arrayref", - "base64 0.13.0", + "base64 0.21.7", "bincode", - "borsh", + "borsh 0.10.3", "bytemuck", + "getrandom 0.2.15", "solana-program", "thiserror", ] +[[package]] +name = "anchor-lang-idl" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b29da81eae478b1bb846749b06b8a2cb9c6f9ed26ca793b0c916793fdf36adab" +dependencies = [ + "anchor-syn", + "anyhow", + "regex", + "serde", + "serde_json", +] + [[package]] name = "anchor-spl" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f32390ce8356f54c0f0245ea156f8190717e37285b8bf4f406a613dc4b954cde" +checksum = "0dcee54a30b27ea8317ca647759b5d9701a8c7caaaa0c922c6d3c306a7278a7a" dependencies = [ "anchor-lang", - "solana-program", - "spl-associated-token-account", - "spl-token", + "spl-associated-token-account 3.0.2", + "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 4.0.0", + "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-group-interface 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-metadata-interface 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "anchor-syn" -version = "0.26.0" +version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0418bcb5daac3b8cb1b60d8fdb1d468ca36f5509f31fb51179326fae1028fdcc" +checksum = "ac53f2378bc08e89e20c2b893c01986ffd34cfbc69a17e35bd6f754753e9fdad" dependencies = [ "anyhow", - "bs58 0.3.1", + "bs58 0.5.1", + "cargo_toml", "heck 0.3.3", - "proc-macro2 1.0.59", - "proc-macro2-diagnostics", - "quote 1.0.28", + "proc-macro2", + "quote", "serde", "serde_json", - "sha2 0.9.9", + "sha2 0.10.8", "syn 1.0.109", "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" @@ -279,9 +327,140 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" + +[[package]] +name = "aquamarine" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da02abba9f9063d786eab1509833ebb2fac0f966862ca59439c76b9c566760" +dependencies = [ + "include_dir", + "itertools", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[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 0.4.5", + "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 0.4.5", + "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 = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint 0.4.5", +] + +[[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 = "arrayref" @@ -291,9 +470,9 @@ checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "ascii" @@ -314,7 +493,7 @@ dependencies = [ "num-traits", "rusticata-macros", "thiserror", - "time 0.3.21", + "time", ] [[package]] @@ -323,8 +502,8 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", "synstructure", ] @@ -335,8 +514,8 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] @@ -346,11 +525,22 @@ 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.3.15" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942c7cd7ae39e91bde4820d74132e9862e62c2f386c3aa90ccf55949f5bad63a" +checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" dependencies = [ "brotli", "flate2", @@ -371,13 +561,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.68" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9ccdd8f2a161be9bd5c023df56f1b2a0bd1d83872ae53b71a84a12c9bf6e842" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 2.0.18", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] @@ -393,9 +583,24 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" + +[[package]] +name = "backtrace" +version = "0.3.71" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +dependencies = [ + "addr2line", + "cc", + "cfg-if", + "libc", + "miniz_oxide", + "object", + "rustc-demangle", +] [[package]] name = "base64" @@ -405,15 +610,15 @@ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "base64" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.2" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" @@ -436,6 +641,15 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +dependencies = [ + "serde", +] + [[package]] name = "bitmaps" version = "2.1.0" @@ -447,9 +661,9 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", @@ -471,9 +685,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -490,31 +704,89 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" dependencies = [ - "borsh-derive", + "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" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbe5b10e214954177fb1dc9fbd20a1a2608fe99e6c832033bdc7cea287a20d77" +dependencies = [ + "borsh-derive 1.5.0", + "cfg_aliases", +] + [[package]] name = "borsh-derive" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", "proc-macro-crate 0.1.5", - "proc-macro2 1.0.59", + "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" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7a8646f94ab393e43e8b35a2558b1624bed28b97ee09c5d15456e3c9463f46d" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.62", + "syn_derive", +] + [[package]] name = "borsh-derive-internal" version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "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", ] @@ -524,16 +796,27 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "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 = "brotli" -version = "3.3.4" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1a0b1dbcc8ae29329621f8d4f0d835787c1c38bb1401979b49d13b0b305ff68" +checksum = "74f7971dbd9326d58187408ab83117d8ac1bb9c17b085fdacd1cf2f598719b6b" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -542,9 +825,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.3.4" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6561fd3f895a11e8f72af2cb7d22e08366bebc2b6b57f7744c4bda27034744" +checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -552,21 +835,24 @@ dependencies = [ [[package]] name = "bs58" -version = "0.3.1" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" +checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" [[package]] name = "bs58" -version = "0.4.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] [[package]] name = "bumpalo" -version = "3.9.1" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a45a46ab1f2412e53d3a0ade76ffad2025804294569aae387231a0cd6e0899" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bv" @@ -580,35 +866,35 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.13.1" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17febce684fd15d89027105661fec94afb475cb995fbc59d2865198446ba2eea" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.4.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdde5c9cd29ebd706ce1b35600920a33550e402fc998a2e53ad3b42c3c47a192" +checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 2.0.18", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.1.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4872d67bab6358e59559027aa3b9157c53d9358c51423c17554809a8858e0f8" +checksum = "514de17de45fdb8dc022b1a7975556c53c86f9f0aa5f534b98977b171857c2c9" [[package]] name = "bzip2" @@ -641,13 +927,25 @@ dependencies = [ "thiserror", ] +[[package]] +name = "cargo_toml" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" +dependencies = [ + "serde", + "toml 0.8.12", +] + [[package]] name = "cc" -version = "1.0.73" +version = "1.0.97" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" dependencies = [ "jobserver", + "libc", + "once_cell", ] [[package]] @@ -656,25 +954,32 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" -version = "0.4.19" +version = "0.4.38" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401" dependencies = [ - "libc", - "num-integer", + "android-tzdata", + "iana-time-zone", + "js-sys", "num-traits", "serde", - "time 0.1.43", - "winapi", + "wasm-bindgen", + "windows-targets 0.52.5", ] [[package]] name = "chrono-humanize" -version = "0.2.1" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eddc119501d583fd930cb92144e605f44e0252c38dd89d9247fffa1993375cb" +checksum = "799627e6b4d27827a814e837b9d8a504832086081806d45b1afa34dc982b023b" dependencies = [ "chrono", ] @@ -688,16 +993,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "cipher" -version = "0.4.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d1873270f8f7942c191139cb8a40fd228da6c3fd2fc376d7e92d47aa14aeb59e" -dependencies = [ - "crypto-common", - "inout", -] - [[package]] name = "clap" version = "2.34.0" @@ -706,7 +1001,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim 0.8.0", "textwrap 0.11.0", "unicode-width", @@ -720,13 +1015,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" dependencies = [ "atty", - "bitflags", + "bitflags 1.3.2", "clap_lex", - "indexmap", + "indexmap 1.9.3", "once_cell", "strsim 0.10.0", "termcolor", - "textwrap 0.16.0", + "textwrap 0.16.1", ] [[package]] @@ -752,16 +1047,25 @@ dependencies = [ ] [[package]] -name = "console" -version = "0.15.7" +name = "concurrent-queue" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ - "encode_unicode", - "lazy_static", - "libc", + "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.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -776,9 +1080,9 @@ dependencies = [ [[package]] name = "console_log" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" dependencies = [ "log", "web-sys", @@ -792,15 +1096,15 @@ checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "core-foundation" -version = "0.9.3" +version = "0.9.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "194a7a9e6de53fa55116934067c844d9d749312f75c6f6d0980e8c252f8c2146" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" dependencies = [ "core-foundation-sys", "libc", @@ -808,71 +1112,61 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.4" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e496a50fda8aacccc86d7529e2c1e0892dbd0f898a6b5645b5561b89c3210efa" +checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if", "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.1" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6455c0ca19f0d2fbf751b908d5c55c1f5cbc65e03c4225427254b46890bdde1e" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "cfg-if", "crossbeam-utils", - "lazy_static", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" -dependencies = [ - "cfg-if", - "lazy_static", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -882,9 +1176,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -906,7 +1200,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" dependencies = [ - "cipher 0.3.0", + "cipher", ] [[package]] @@ -923,22 +1217,60 @@ dependencies = [ "zeroize", ] +[[package]] +name = "darling" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim 0.10.0", + "syn 2.0.62", +] + +[[package]] +name = "darling_macro" +version = "0.20.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.62", +] + [[package]] name = "dashmap" -version = "4.0.2" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "num_cpus", + "hashbrown 0.14.5", + "lock_api", + "once_cell", + "parking_lot_core", "rayon", ] [[package]] name = "data-encoding" -version = "2.4.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2e66c9d817f1720209181c316d28635c050fa304f9c79e47a520882661b7308" +checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" [[package]] name = "der" @@ -958,17 +1290,37 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.3", + "num-bigint 0.4.5", "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" @@ -981,6 +1333,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" version = "0.9.0" @@ -996,16 +1354,16 @@ version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.4", "crypto-common", "subtle", ] [[package]] name = "dir-diff" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2860407d7d7e2e004bb2128510ad9e8d669e76fa005ccf567977b5d71b8b4a0b" +checksum = "a7ad16bf5f84253b50d6557681c58c3ab67c47c77d39fed9aeb56e947290bd10" dependencies = [ "walkdir", ] @@ -1037,34 +1395,40 @@ version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 2.0.18", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] -name = "dlopen" -version = "0.1.8" +name = "dlopen2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e80ad39f814a9abe68583cd50a2d45c8a67561c3361ab8da240587dda80937" +checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" dependencies = [ - "dlopen_derive", - "lazy_static", + "dlopen2_derive", "libc", + "once_cell", "winapi", ] [[package]] -name = "dlopen_derive" -version = "0.1.4" +name = "dlopen2_derive" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f236d9e1b1fbd81cea0f9cbdc8dcc7e8ebcd80e6659cd7cb2ad5f6c05946c581" +checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ - "libc", - "quote 0.6.13", - "syn 0.15.44", + "proc-macro2", + "quote", + "syn 2.0.62", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + [[package]] name = "eager" version = "0.1.0" @@ -1073,9 +1437,9 @@ checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" [[package]] name = "ed25519" -version = "1.4.0" +version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eed12bbf7b5312f8da1c2722bc06d8c6b12c2d86a7fb35a194c7f3e6fc2bbe39" +checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ "signature", ] @@ -1103,26 +1467,26 @@ dependencies = [ "derivation-path", "ed25519-dalek", "hmac 0.12.1", - "sha2 0.10.6", + "sha2 0.10.8", ] [[package]] name = "educe" -version = "0.4.19" +version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c07b7cc9cd8c08d10db74fca3b20949b9b6199725c04a0cce6d543496098fcac" +checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" dependencies = [ "enum-ordinalize", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "either" -version = "1.8.1" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcaabb2fef8c910e7f4c7ce9f67a1283a1715879a7c230ca9d6d1ae31f16d91" +checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" [[package]] name = "encode_unicode" @@ -1132,64 +1496,63 @@ checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" [[package]] name = "encoding_rs" -version = "0.8.30" +version = "0.8.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dc8abb250ffdda33912550faa54c88ec8b998dec0b2c55ab224921ce11df" +checksum = "b45de904aa0b010bce2ab45264d0631681847fa7b6f2eaa7dab7619943bc4f59" dependencies = [ "cfg-if", ] [[package]] name = "enum-iterator" -version = "0.8.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2953d1df47ac0eb70086ccabf0275aa8da8591a28bd358ee2b52bd9f9e3ff9e9" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "0.8.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8958699f9359f0b04e691a13850d48b7de329138023876d07cbd024c2c820598" +checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "enum-ordinalize" -version = "3.1.11" +version = "3.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2170fc0efee383079a8bdd05d6ea2a184d2a0f07a1c1dcabdb2fd5e9f24bc36c" +checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" dependencies = [ - "num-bigint 0.4.3", + "num-bigint 0.4.5", "num-traits", - "proc-macro2 1.0.59", - "quote 1.0.28", - "rustc_version", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "enum_dispatch" -version = "0.3.8" +version = "0.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0eb359f1476bf611266ac1f5355bc14aeca37b299d0ebccc038ee7058891c9cb" +checksum = "aa18ce2bc66555b3218614519ac839ddb759a7d6720732f979ef8d13be147ecd" dependencies = [ "once_cell", - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "env_logger" -version = "0.9.0" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b2cf0344971ee6c64c31be0d530793fba457d322dfec2810c453d0ef228f9c3" +checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7" dependencies = [ "atty", "humantime", @@ -1199,24 +1562,19 @@ dependencies = [ ] [[package]] -name = "errno" -version = "0.3.1" +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bcfec3a70f97c962c307b2d2c56e358cf1d00b558d74262b5f929ee8cc7e73a" -dependencies = [ - "errno-dragonfly", - "libc", - "windows-sys 0.48.0", -] +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] -name = "errno-dragonfly" -version = "0.1.2" +name = "errno" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa68f1b12764fab894d2755d2518754e71b4fd80ecfb822714a1206c2aab39bf" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" dependencies = [ - "cc", "libc", + "windows-sys 0.52.0", ] [[package]] @@ -1227,12 +1585,9 @@ checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] name = "fastrand" -version = "1.7.0" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3fcf0cee53519c866c09b5de1f6c56ff9d647101f81c1964fa632e148896cdf" -dependencies = [ - "instant", -] +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" [[package]] name = "feature-probe" @@ -1242,26 +1597,35 @@ checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" [[package]] name = "filetime" -version = "0.2.15" +version = "0.2.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "975ccf83d8d9d0d84682850a38c8169027be83368805971cc4f238c2b245bc98" +checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.11", - "winapi", + "redox_syscall 0.4.1", + "windows-sys 0.52.0", ] [[package]] name = "flate2" -version = "1.0.26" +version = "1.0.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b9429470923de8e8cbd4d2dc513535400b4b3fef0319fb5c4e1f520a7bef743" +checksum = "5f54427cfd1c7829e2a139fcefea601bf088ebca651d2bf53ebc600eac295dae" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" @@ -1270,19 +1634,24 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.0.1" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fc25a87fa4fd2094bffb06925852034d90a17f0d1e05197d4956d3555752191" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ - "matches", "percent-encoding", ] +[[package]] +name = "fragile" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c2141d6d6c8512188a7891b4b01590a45f6dac67afb4f255c4124dbb86d4eaa" + [[package]] name = "futures" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f73fe65f54d1e12b726f517d3e2135ca3125a437b6d998caf1962961f7172d9e" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1295,9 +1664,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3083ce4b914124575708913bca19bfe887522d6e2e6d0952943f5eac4a74010" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1305,15 +1674,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0c09fd04b7e4073ac7156a9539b57a484a8ea920f79c7c675d05d289ab6110d3" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9420b90cfa29e327d0429f19be13e7ddb68fa1cccb09d65e5706b8c7a749b8a6" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1322,38 +1691,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc4045962a5a5e935ee2fdedaa4e08284547402885ab326734432bed5d12966b" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c1e13800337f4d4d7a316bf45a567dbcb6ffe087f16424852d97e97a91f512" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "futures-sink" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21163e139fa306126e6eedaf49ecdb4588f939600f0b1e770f4205ee4b7fa868" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57c66a976bf5909d801bbef33416c41372779507e7a6b3a5e25e4749c58f776a" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.21" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8b7abd5d659d9b90c8cba917f6ec750a74e2dc23902ef9cd4cc8c8b22e6036a" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1367,20 +1736,11 @@ dependencies = [ "slab", ] -[[package]] -name = "fxhash" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c31b6d751ae2c7f11320402d34e41349dd1016f8d5d45e48c4312bc8625af50c" -dependencies = [ - "byteorder", -] - [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "serde", "typenum", @@ -1412,17 +1772,23 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", "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" @@ -1436,46 +1802,44 @@ dependencies = [ [[package]] name = "gpl-civic-gateway" -version = "0.1.1" +version = "0.2.0" dependencies = [ "anchor-lang", "anchor-spl", "arrayref", - "borsh", + "borsh 0.10.3", "enum_dispatch", "itertools", - "num 0.4.0", - "num-derive", + "num 0.4.3", + "num-derive 0.3.3", "num-traits", "solana-gateway", "solana-program", "solana-program-test", "solana-sdk", - "spl-governance", - "spl-governance-addin-api", + "spl-governance 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "spl-governance-addin-mock", - "spl-governance-tools", - "spl-token", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 4.0.0", ] [[package]] name = "gpl-nft-voter" -version = "0.2.2" +version = "0.3.0" dependencies = [ "anchor-lang", "anchor-spl", "arrayref", - "borsh", + "borsh 0.10.3", "itertools", "mpl-token-metadata", "solana-program", "solana-program-test", "solana-sdk", - "spl-governance", - "spl-governance-tools", - "spl-token", - "toml_datetime", - "winnow", + "spl-governance 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 4.0.0", ] [[package]] @@ -1485,20 +1849,20 @@ dependencies = [ "anchor-lang", "anchor-spl", "arrayref", - "borsh", + "borsh 0.10.3", "solana-program", "solana-program-test", "solana-sdk", - "spl-governance", - "spl-governance-tools", - "spl-token", + "spl-governance 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 4.0.0", ] [[package]] name = "h2" -version = "0.3.12" +version = "0.3.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62eeb471aa3e3c9197aa4bfeabfe02982f6dc96f750486c0bb0009ac58b26d2b" +checksum = "81fe527a889e1532da5c525686d96d4c2e74cdd345badf8dfef9f6b39dd5f5e8" dependencies = [ "bytes", "fnv", @@ -1506,10 +1870,10 @@ dependencies = [ "futures-sink", "futures-util", "http", - "indexmap", + "indexmap 2.2.6", "slab", "tokio", - "tokio-util 0.6.9", + "tokio-util 0.7.11", "tracing", ] @@ -1528,7 +1892,7 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] @@ -1537,9 +1901,24 @@ version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash", + "ahash 0.7.8", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash 0.8.7", ] +[[package]] +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + [[package]] name = "heck" version = "0.3.3" @@ -1566,9 +1945,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.1" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fed44880c466736ef9a5c5b5facefb5ed0785676d0c02d612db14e54f0d84286" +checksum = "d231dfb89cfffdbc30e7fc41579ed6066ad03abda9e567ccafae602b97ec5024" [[package]] name = "histogram" @@ -1608,9 +1987,9 @@ dependencies = [ [[package]] name = "http" -version = "0.2.6" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31f4c6746584866f0feabcc69893c5b51beef3831656a968ed7ae254cdc4fd03" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", @@ -1619,9 +1998,9 @@ dependencies = [ [[package]] name = "http-body" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ff4f84919677303da5f147645dbea6b1881f368d03ac84e1dc09031ebd7b2c6" +checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" dependencies = [ "bytes", "http", @@ -1636,9 +2015,9 @@ checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" [[package]] name = "httpdate" -version = "1.0.2" +version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4a1e36c821dbe04574f602848a19f742f4fb3c98d40449f11bcad18d6b17421" +checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" @@ -1648,9 +2027,9 @@ checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" [[package]] name = "hyper" -version = "0.14.22" +version = "0.14.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abfba89e19b959ca163c7752ba59d737c1ceea53a5d31a149c805446fc958064" +checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" dependencies = [ "bytes", "futures-channel", @@ -1672,10 +2051,11 @@ dependencies = [ [[package]] name = "hyper-rustls" -version = "0.23.0" +version = "0.24.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d87c48c02e0dc5e3b849a2041db3029fd066650f8f717c07bf8ed78ccb895cac" +checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" dependencies = [ + "futures-util", "http", "hyper", "rustls", @@ -1683,13 +2063,41 @@ dependencies = [ "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.2.3" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "418a0a6fab821475f634efe3ccc45c013f742efe03d853e8d3355d5cb850ecf8" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ - "matches", "unicode-bidi", "unicode-normalization", ] @@ -1701,7 +2109,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" dependencies = [ "bitmaps", - "rand_core 0.6.3", + "rand_core 0.6.4", "rand_xoshiro", "rayon", "serde", @@ -1710,11 +2118,30 @@ dependencies = [ "version_check", ] +[[package]] +name = "include_dir" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18762faeff7122e89e0857b02f7ce6fcc0d101d5e9ad2ad7846cc01d61b7f19e" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b139284b5cf57ecfa712bcc66950bb635b31aff41c188e8a4cfc758eca374a3f" +dependencies = [ + "proc-macro2", + "quote", +] + [[package]] name = "index_list" -version = "0.2.7" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a9d968042a4902e08810946fc7cd5851eb75e80301342305af755ca06cb82ce" +checksum = "70891286cb8e844fdfcf1178b47569699f9e20b5ecc4b45a6240a64771444638" [[package]] name = "indexmap" @@ -1727,24 +2154,26 @@ dependencies = [ ] [[package]] -name = "indicatif" -version = "0.16.2" +name = "indexmap" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d207dc617c7a380ab07ff572a6e52fa202a2a8f355860ac9c38e23f8196be1b" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ - "console", - "lazy_static", - "number_prefix", - "regex", + "equivalent", + "hashbrown 0.14.5", ] [[package]] -name = "inout" -version = "0.1.3" +name = "indicatif" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0c10553d664a4d0bcff9f4215d0aac67a639cc68ef660840afe309b807bc9f5" +checksum = "763a5a8f45087d6bcea4222e7b72c291a054edf80e4ef6efd2a4979878c7bea3" dependencies = [ - "generic-array", + "console", + "instant", + "number_prefix", + "portable-atomic", + "unicode-width", ] [[package]] @@ -1756,52 +2185,41 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "io-lifetimes" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eae7b9aee968036d54dce06cebaefd919e4472e753296daccd6d344e3e2df0c2" -dependencies = [ - "hermit-abi 0.3.1", - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "ipnet" -version = "2.4.0" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35e70ee094dc02fd9c13fdad4940090f22dbd6ac7c9e7094a46cf0232a50bc7c" +checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" [[package]] name = "jobserver" -version = "0.1.24" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af25a77299a7f711a01975c35a6a424eb6862092cc2d6c72c4ed6cbc56dfc1fa" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" dependencies = [ "libc", ] [[package]] name = "js-sys" -version = "0.3.63" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f37a4a5928311ac501dee68b3c7613a1037d0edb30c8e5427bd832d55d1b790" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -1823,9 +2241,12 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.0" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] [[package]] name = "lazy_static" @@ -1835,18 +2256,18 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.144" +version = "0.2.154" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b00cc1c228a6782d0f076e7b232802e0c5689d41bb5df366f2a6b6621cfdfe1" +checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" [[package]] -name = "libloading" -version = "0.7.3" +name = "libredox" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efbc0f03f9a775e9f6aed295c6a1ba2253c5757a9e03d55c6caa46a681abcddd" +checksum = "c0ff37bd590ca25063e35af745c343cb7a0271906fb7b37e4813e8f79f00268d" dependencies = [ - "cfg-if", - "winapi", + "bitflags 2.5.0", + "libc", ] [[package]] @@ -1898,31 +2319,38 @@ dependencies = [ ] [[package]] -name = "linked-hash-map" -version = "0.5.6" +name = "light-poseidon" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint 0.4.5", + "thiserror", +] [[package]] name = "linux-raw-sys" -version = "0.3.8" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef53942eb7bf7ff43a617b3e2c1c4a5ecf5944a7c1bc12d7ee39bbb15e5c1519" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" [[package]] name = "lock_api" -version = "0.4.6" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88943dd7ef4a2e5a4bfa2753aaab3013e34ce2533d1996fb18ef591e315e2b3b" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ + "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.18" +version = "0.4.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "518ef76f2f87365916b142844c16d8fefd85039bc5699050210a7778ee1cd1de" +checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" [[package]] name = "lru" @@ -1953,32 +2381,35 @@ dependencies = [ "libc", ] -[[package]] -name = "matches" -version = "0.1.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e378b66a060d48947b590737b30a1be76706c8dd7b8ba0f2fe3989c68a853f" - [[package]] name = "memchr" -version = "2.4.1" +version = "2.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d" [[package]] name = "memmap2" -version = "0.5.3" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] [[package]] name = "memoffset" -version = "0.6.5" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +dependencies = [ + "autocfg", +] + +[[package]] +name = "memoffset" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aa361d4faea93603064a027415f07bd8e1d5c88c9fbf68bf56a285428fd79ce" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -1991,15 +2422,15 @@ checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" dependencies = [ "byteorder", "keccak", - "rand_core 0.6.3", + "rand_core 0.6.4", "zeroize", ] [[package]] name = "mime" -version = "0.3.16" +version = "0.3.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a60c7ce501c71e03a9c9c0d35b861413ae925bd979cc7a4e30d060069aaac8d" +checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" [[package]] name = "minimal-lexical" @@ -2009,33 +2440,49 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" dependencies = [ "adler", ] [[package]] name = "mio" -version = "0.7.14" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc" +checksum = "a4a650543ca06a924e8b371db273b2756685faae30f8487da1b56505a8f78b0c" dependencies = [ "libc", - "log", - "miow", - "ntapi", - "winapi", + "wasi 0.11.0+wasi-snapshot-preview1", + "windows-sys 0.48.0", ] [[package]] -name = "miow" -version = "0.3.7" +name = "mockall" +version = "0.11.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9f1c5b025cda876f66ef43a113f91ebc9f4ccef34843000e0adf6ebbab84e21" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" dependencies = [ - "winapi", + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -2054,81 +2501,35 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a7d5f7076603ebc68de2dc6a650ec331a062a13abaa346975be747bbfa4b789" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] -[[package]] -name = "mpl-token-auth-rules" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24dcb2b0ec0e9246f6f035e0336ba3359c21f6928dfd90281999e2c8e8ab53eb" -dependencies = [ - "borsh", - "mpl-token-metadata-context-derive", - "num-derive", - "num-traits", - "rmp-serde", - "serde", - "shank", - "solana-program", - "solana-zk-token-sdk", - "thiserror", -] - [[package]] name = "mpl-token-metadata" -version = "1.12.0" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f661ff8c1d64c48cf207c0d259783d411a4249058c1b861fabd8bb6ce30ae4d8" +checksum = "caf0f61b553e424a6234af1268456972ee66c2222e1da89079242251fa7479e5" dependencies = [ - "arrayref", - "borsh", - "mpl-token-auth-rules", - "mpl-token-metadata-context-derive", - "mpl-utils", - "num-derive", + "borsh 0.10.3", + "num-derive 0.3.3", "num-traits", - "shank", "solana-program", - "spl-associated-token-account", - "spl-token", "thiserror", ] -[[package]] -name = "mpl-token-metadata-context-derive" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12989bc45715b0ee91944855130131479f9c772e198a910c3eb0ea327d5bffc3" -dependencies = [ - "quote 1.0.28", - "syn 1.0.109", -] - -[[package]] -name = "mpl-utils" -version = "0.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "822133b6cba8f9a43e5e0e189813be63dd795858f54155c729833be472ffdb51" -dependencies = [ - "arrayref", - "borsh", - "solana-program", - "spl-token", -] - [[package]] name = "nix" -version = "0.24.3" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa52e972a9a719cecb6864fb88568781eb706bac2cd1d4f04a648542dbf78069" +checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" dependencies = [ - "bitflags", + "bitflags 1.3.2", "cfg-if", "libc", - "memoffset", + "memoffset 0.7.1", + "pin-utils", ] [[package]] @@ -2142,13 +2543,10 @@ dependencies = [ ] [[package]] -name = "ntapi" -version = "0.3.7" +name = "normalize-line-endings" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c28774a7fd2fbb4f0babd8237ce554b73af68021b5f695a3cebd6c59bac0980f" -dependencies = [ - "winapi", -] +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" [[package]] name = "num" @@ -2166,15 +2564,15 @@ dependencies = [ [[package]] name = "num" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43db66d1170d347f9a065114077f7dccb00c1b9478c89384490a3425279a4606" +checksum = "35bd024e8b2ff75562e5f34e7f4905839deb4b22955ef5e73d2fea1b9813cb23" dependencies = [ - "num-bigint 0.4.3", - "num-complex 0.4.1", + "num-bigint 0.4.5", + "num-complex 0.4.6", "num-integer", "num-iter", - "num-rational 0.4.0", + "num-rational 0.4.2", "num-traits", ] @@ -2191,11 +2589,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f93ab6289c7b344a8a9f60f88d80aa20032336fe78da341afc91c8a2341fc75f" +checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -2212,39 +2609,55 @@ dependencies = [ [[package]] name = "num-complex" -version = "0.4.1" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "97fbc387afefefd5e9e39493299f3069e14a140dd34dc19b4c1c1a8fddb6a790" +checksum = "73f88a1307638156682bada9d7604135552957b7818057dcef22705b4d509495" dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.62", +] + [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -2265,32 +2678,31 @@ dependencies = [ [[package]] name = "num-rational" -version = "0.4.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d41702bd167c2df5520b384281bc111a4b5efcf7fbc4c9c222c815b07e0a6a6a" +checksum = "f83d14da390562dca69fc84082e73e548e1ad308d24accdedd2720017cb37824" dependencies = [ - "autocfg", - "num-bigint 0.4.3", + "num-bigint 0.4.5", "num-integer", "num-traits", ] [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.13.1" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19e64526ebdee182341572e50e9ad03965aa510cd94427a4549448f285e957a1" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi 0.3.9", "libc", ] @@ -2300,7 +2712,25 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1f646caf906c20226733ed5b1374287eb97e3c2a5c227ce668c1f2ce20ae57c9" dependencies = [ - "num_enum_derive", + "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" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +dependencies = [ + "num_enum_derive 0.7.2", ] [[package]] @@ -2309,18 +2739,51 @@ version = "0.5.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dcbff9bc912032c62bf65ef1d5aea88983b420f4f839db1e9b0c281a25c9c799" dependencies = [ - "proc-macro-crate 1.1.3", - "proc-macro2 1.0.59", - "quote 1.0.28", + "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.62", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" +dependencies = [ + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.62", +] + [[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" @@ -2332,15 +2795,15 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.17.2" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9670a07f94779e00908f3e686eab508878ebb390ba6e604d3a284c00e8d0487b" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl-probe" @@ -2369,9 +2832,9 @@ dependencies = [ [[package]] name = "os_str_bytes" -version = "6.5.0" +version = "6.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ceedf44fb00f2d1984b0bc98102627ce622e083e49a5bacdb3e514fa4238e267" +checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" [[package]] name = "ouroboros" @@ -2391,64 +2854,39 @@ checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" dependencies = [ "Inflector", "proc-macro-error", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "parking_lot" -version = "0.11.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d17b78036a60663b797adeaee46f5c9dfebb86948d1255007a1d6be0271ff99" -dependencies = [ - "instant", - "lock_api", - "parking_lot_core 0.8.5", -] - -[[package]] -name = "parking_lot" -version = "0.12.0" +version = "0.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f5ec2493a61ac0506c0f4199f99070cbe83857b0337006a30f3e6719b8ef58" +checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" dependencies = [ "lock_api", - "parking_lot_core 0.9.1", -] - -[[package]] -name = "parking_lot_core" -version = "0.8.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76e8e1493bcac0d2766c42737f34458f1c8c50c0d23bcb24ea953affb273216" -dependencies = [ - "cfg-if", - "instant", - "libc", - "redox_syscall 0.2.11", - "smallvec", - "winapi", + "parking_lot_core", ] [[package]] name = "parking_lot_core" -version = "0.9.1" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28141e0cc4143da2443301914478dc976a61ffdb3f043058310c70df2fed8954" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", - "redox_syscall 0.2.11", + "redox_syscall 0.5.1", "smallvec", - "windows-sys 0.32.0", + "windows-targets 0.52.5", ] [[package]] name = "paste" -version = "1.0.12" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f746c4065a8fa3fe23974dd82f15431cc8d40779821001404d10d2e79ca7d79" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pbkdf2" @@ -2474,14 +2912,14 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" dependencies = [ - "base64 0.13.0", + "base64 0.13.1", ] [[package]] name = "percent-encoding" -version = "2.1.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4fd5641d01c8f18a23da7b6fe29298ff4b55afcccdf78973b24cf3175fee32e" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "percentage" @@ -2494,29 +2932,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.0.10" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58ad3879ad3baf4e44784bc6a718a8698867bb991f8ce24d1bcbe2cfb4c3a75e" +checksum = "b6bf43b791c5b9e34c3d182969b4abb522f9343702850a2e57f460d00d09b4b3" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.0.10" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744b6f092ba29c3650faf274db506afd39944f48420f6c86b17cfe0ee1cb36bb" +checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "pin-project-lite" -version = "0.2.8" +version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e280fbe77cc62c91527259e9442153f4688736748d24660126286329742b4c6c" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" [[package]] name = "pin-utils" @@ -2537,9 +2975,9 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.24" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58893f751c9b0412871a09abd62ecd2a00298c6c83befa223ef98c52aef40cbe" +checksum = "d231b230927b5e4ad203db57bbcbee2802f6bce620b1e4a9024a07d94e2907ec" [[package]] name = "plain" @@ -2559,11 +2997,59 @@ 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.16" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "predicates" +version = "2.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools", + "normalize-line-endings", + "predicates-core", + "regex", +] + +[[package]] +name = "predicates-core" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b794032607612e7abeb4db69adb4e33590fa6cf1149e95fd7cb00e634b92f174" + +[[package]] +name = "predicates-tree" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "368ba315fb8c5052ab692e68a0eefec6ec57b23a36959c14496f0b0df2c0cecf" +dependencies = [ + "predicates-core", + "termtree", +] + +[[package]] +name = "pretty-hex" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "c6fa0831dd7cc608c38a5e323422a0077678fa5744aa2be4ad91c4ece8eec8d5" [[package]] name = "proc-macro-crate" @@ -2571,17 +3057,26 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] name = "proc-macro-crate" -version = "1.1.3" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17d47ce914bf4de440332250b0edd23ce48c005f59fab39d3335866b114f11a" +checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" dependencies = [ - "thiserror", - "toml", + "once_cell", + "toml_edit 0.19.15", +] + +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.1", ] [[package]] @@ -2591,8 +3086,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ "proc-macro-error-attr", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", "version_check", ] @@ -2603,120 +3098,95 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "version_check", ] [[package]] name = "proc-macro2" -version = "0.4.30" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf3d2011ab5c909338f7887f4fc896d35932e29146c12c8d01da6b22a80ba759" -dependencies = [ - "unicode-xid 0.1.0", -] - -[[package]] -name = "proc-macro2" -version = "1.0.59" +version = "1.0.82" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6aeca18b86b413c660b781aa319e4e2648a3e6f9eadc9b47e9038e6fe9f3451b" +checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" dependencies = [ "unicode-ident", ] [[package]] -name = "proc-macro2-diagnostics" -version = "0.9.1" +name = "qstring" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", - "version_check", - "yansi", + "percent-encoding", ] [[package]] -name = "qstring" -version = "0.7.2" +name = "qualifier_attr" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ - "percent-encoding", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "quinn" -version = "0.8.5" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b435e71d9bfa0d8889927231970c51fb89c58fa63bffcab117c9c7a41e5ef8f" +checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" dependencies = [ "bytes", - "futures-channel", - "futures-util", - "fxhash", + "pin-project-lite", "quinn-proto", "quinn-udp", + "rustc-hash", "rustls", "thiserror", "tokio", "tracing", - "webpki", ] [[package]] name = "quinn-proto" -version = "0.8.4" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fce546b9688f767a57530652488420d419a8b1f44a478b451c3d1ab6d992a55" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", - "fxhash", "rand 0.8.5", - "ring", + "ring 0.16.20", + "rustc-hash", "rustls", "rustls-native-certs", - "rustls-pemfile 0.2.1", "slab", "thiserror", "tinyvec", "tracing", - "webpki", ] [[package]] name = "quinn-udp" -version = "0.1.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b07946277141531aea269befd949ed16b2c85a780ba1043244eda0969e538e54" +checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ - "futures-util", + "bytes", "libc", - "quinn-proto", "socket2", - "tokio", "tracing", + "windows-sys 0.48.0", ] [[package]] name = "quote" -version = "0.6.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce23b6b870e8f94f81fb0a363d65d86675884b34a09043c81e5562f11c1f8e1" -dependencies = [ - "proc-macro2 0.4.30", -] - -[[package]] -name = "quote" -version = "1.0.28" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b9ab9c7eadfd8df19006f1cf1a4aed13540ed5cbc047010ece5826e10825488" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ - "proc-macro2 1.0.59", + "proc-macro2", ] [[package]] @@ -2740,7 +3210,7 @@ checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ "libc", "rand_chacha 0.3.1", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2760,7 +3230,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" dependencies = [ "ppv-lite86", - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] @@ -2774,11 +3244,11 @@ dependencies = [ [[package]] name = "rand_core" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.5", + "getrandom 0.2.15", ] [[package]] @@ -2796,14 +3266,14 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa" dependencies = [ - "rand_core 0.6.3", + "rand_core 0.6.4", ] [[package]] name = "rayon" -version = "1.7.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2df5196e37bcc87abebc0053e20787d73847bb33134a69841207dd0a47f03b" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -2811,62 +3281,72 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.11.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b8f95bd6966f5c87776639160a66bd8ab9895d9d4ab01ddba9fc60661aebe8d" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "rcgen" -version = "0.9.3" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6413f3de1edee53342e6138e75b56d32e7bc6e332b3bd62d497b1929d4cfbcdd" +checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", - "time 0.3.21", + "ring 0.16.20", + "time", "yasna", ] [[package]] name = "redox_syscall" -version = "0.2.11" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] name = "redox_syscall" -version = "0.3.5" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +checksum = "469052894dcb553421e483e4209ee581a45100d31b4018de03e5a7ad86374a7e" dependencies = [ - "bitflags", + "bitflags 2.5.0", ] [[package]] name = "redox_users" -version = "0.4.3" +version = "0.4.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +checksum = "bd283d9651eeda4b2a83a43c1c91b266c40fd76ecd39a50a8c630ae69dc72891" dependencies = [ - "getrandom 0.2.5", - "redox_syscall 0.2.11", + "getrandom 0.2.15", + "libredox", "thiserror", ] [[package]] name = "regex" -version = "1.7.3" +version = "1.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b1f693b24f6ac912f4893ef08244d70b6067480d2f1a46e950c9691e6749d1d" +checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea" dependencies = [ "aho-corasick", "memchr", @@ -2875,18 +3355,18 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.29" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" +checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56" [[package]] name = "reqwest" -version = "0.11.17" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13293b639a097af28fc8a90f22add145a9c954e49d77da06263d58cf44d5fb91" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "async-compression", - "base64 0.21.2", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -2904,19 +3384,21 @@ dependencies = [ "percent-encoding", "pin-project-lite", "rustls", - "rustls-pemfile 1.0.2", + "rustls-pemfile", "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", + "system-configuration", "tokio", "tokio-rustls", - "tokio-util 0.7.2", + "tokio-util 0.7.11", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots", + "webpki-roots 0.25.4", "winreg", ] @@ -2929,51 +3411,53 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] [[package]] -name = "rmp" -version = "0.8.11" +name = "ring" +version = "0.17.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44519172358fd6d58656c86ab8e7fbc9e1490c3e8f14d35ed78ca0dd07403c9f" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" dependencies = [ - "byteorder", - "num-traits", - "paste", + "cc", + "cfg-if", + "getrandom 0.2.15", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", ] [[package]] -name = "rmp-serde" -version = "1.1.1" +name = "rpassword" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b13be192e0220b8afb7222aa5813cb62cc269ebb5cac346ca6487681d2913e" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ - "byteorder", - "rmp", - "serde", + "libc", + "rtoolbox", + "windows-sys 0.48.0", ] [[package]] -name = "rpassword" -version = "6.0.1" +name = "rtoolbox" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2bf099a1888612545b683d2661a1940089f6c2e5a8e38979b2159da876bfd956" +checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" dependencies = [ "libc", - "serde", - "serde_json", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "rustc-demangle" -version = "0.1.21" +version = "0.1.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342" +checksum = "719b953e2095829ee67db738b3bfa9fa368c94900df327b3f07fe6e794d2fe1f" [[package]] name = "rustc-hash" @@ -3001,71 +3485,71 @@ dependencies = [ [[package]] name = "rustix" -version = "0.37.19" +version = "0.38.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "acf8729d8542766f1b2cf77eb034d52f40d375bb8b615d0b147089946e16613d" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" dependencies = [ - "bitflags", + "bitflags 2.5.0", "errno", - "io-lifetimes", "libc", "linux-raw-sys", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "rustls" -version = "0.20.8" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fff78fc74d175294f4e83b28343315ffcfb114b156f0185e9741cb5570f50e2f" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring", + "ring 0.17.8", + "rustls-webpki", "sct", - "webpki", ] [[package]] name = "rustls-native-certs" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0167bac7a9f490495f3c33013e7722b53cb087ecbe082fb0c6387c96f634ea50" +checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" dependencies = [ "openssl-probe", - "rustls-pemfile 1.0.2", + "rustls-pemfile", "schannel", "security-framework", ] [[package]] name = "rustls-pemfile" -version = "0.2.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5eebeaeb360c87bfb72e84abdb3447159c0eaececf1bef2aecd65a8be949d1c9" +checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" dependencies = [ - "base64 0.13.0", + "base64 0.21.7", ] [[package]] -name = "rustls-pemfile" -version = "1.0.2" +name = "rustls-webpki" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d194b56d58803a43635bdc398cd17e383d6f71f9182b9a192c127ca42494a59b" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "base64 0.21.2", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] name = "rustversion" -version = "1.0.12" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f3208ce4d8448b3f3e7d168a73f5e0c43a61e32930de3bceeccedb388b6bf06" +checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "same-file" @@ -3078,18 +3562,18 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.21" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "713cfb06c7059f3588fb8044c0fad1d09e3c01d225e25b9220dbfdcf16dbb1b3" +checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" dependencies = [ - "windows-sys 0.42.0", + "windows-sys 0.52.0", ] [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "scroll" @@ -3102,32 +3586,32 @@ dependencies = [ [[package]] name = "scroll_derive" -version = "0.11.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdbda6ac5cd1321e724fa9cee216f3a61885889b896f073b8f82322789c5250e" +checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "sct" -version = "0.7.0" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" +checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] name = "security-framework" -version = "2.9.1" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fc758eb7bffce5b308734e9b0c1468893cae9ff70ebf13e7090be8dcbcc83a8" +checksum = "c627723fd09706bacdb5cf41499e95098555af3c3c29d014dc3c458ef6be11c0" dependencies = [ - "bitflags", + "bitflags 2.5.0", "core-foundation", "core-foundation-sys", "libc", @@ -3136,9 +3620,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f51d0c0d83bec45f16480d0ce0058397a69e48fcdc52d1dc8855fb68acbd31a7" +checksum = "317936bbbd05227752583946b9e66d7ce3b489f84e11a94a510b4437fef407d7" dependencies = [ "core-foundation-sys", "libc", @@ -3146,50 +3630,68 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.17" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" + +[[package]] +name = "seqlock" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bebd363326d05ec3e2f532ab7660680f3b02130d780c299bca73469d521bc0ed" +checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" +dependencies = [ + "parking_lot", +] [[package]] name = "serde" -version = "1.0.163" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2113ab51b87a539ae008b5c6c02dc020ffa39afd2d83cffcb3f4eb2722cebec2" +checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.5" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.163" +version = "1.0.201" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c805777e3930c8883389c602315a24224bcc738b63905ef87cd1420353ea93e" +checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 2.0.18", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "serde_json" -version = "1.0.96" +version = "1.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057d394a50403bcac12672b2b18fb387ab6d289d957dab67dd201875391e52f1" +checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +dependencies = [ + "serde", +] + [[package]] name = "serde_urlencoded" version = "0.7.1" @@ -3202,23 +3704,46 @@ dependencies = [ "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.62", +] + [[package]] name = "serde_yaml" -version = "0.8.26" +version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "578a7433b776b56a35785ed5ce9a7e777ac0598aac5a6dd1b4b18a307c7fc71b" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap", + "indexmap 2.2.6", + "itoa", "ryu", "serde", - "yaml-rust", + "unsafe-libyaml", ] [[package]] -name = "sha-1" -version = "0.10.1" +name = "sha1" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f5058ada175748e33390e40e872bd0fe59a19f265d0158daa551c5a88a76009c" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", "cpufeatures", @@ -3240,9 +3765,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", @@ -3263,53 +3788,19 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ "digest 0.10.7", "keccak", ] -[[package]] -name = "shank" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b63e565b5e95ad88ab38f312e89444c749360641c509ef2de0093b49f55974a5" -dependencies = [ - "shank_macro", -] - -[[package]] -name = "shank_macro" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "63927d22a1e8b74bda98cc6e151fcdf178b7abb0dc6c4f81e0bbf5ffe2fc4ec8" -dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "shank_macro_impl", - "syn 1.0.109", -] - -[[package]] -name = "shank_macro_impl" -version = "0.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40ce03403df682f80f4dc1efafa87a4d0cb89b03726d0565e6364bdca5b9a441" -dependencies = [ - "anyhow", - "proc-macro2 1.0.59", - "quote 1.0.28", - "serde", - "syn 1.0.109", -] - [[package]] name = "sharded-slab" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "900fba806f70c630b0a382d0d825e17a0f19fcd059a2ade1ff237bcddf446b31" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" dependencies = [ "lazy_static", ] @@ -3322,18 +3813,24 @@ checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" [[package]] name = "signal-hook-registry" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51e73328dc4ac0c7ccbda3a494dfa03df1de2f46018127f60c693f2648455b0" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" dependencies = [ "libc", ] [[package]] name = "signature" -version = "1.5.0" +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 = "f054c6c1a6e95179d6f23ed974060dcefb2d9388bb7256900badad682c499de4" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "sized-chunks" @@ -3347,74 +3844,125 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.5" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] [[package]] name = "smallvec" -version = "1.8.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" -version = "0.4.4" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66d72b759436ae32898a2af0a14218dbf55efde3feeb170eb623637db85ee1e0" +checksum = "ce305eb0b4296696835b71df73eb912e0f1ffd2556a501fcede6e0c50349191c" dependencies = [ "libc", - "winapi", + "windows-sys 0.52.0", ] [[package]] -name = "sol-did" -version = "0.2.0" +name = "solana-account-decoder" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2546d424d6898908c205d99d3af07ad42e2e8aec8f0d459235dc0bd4e9866fe" +checksum = "142161f13c328e7807fe98fb8f6eaaa5045a8eaf4492414aa81254870c4fc8a0" dependencies = [ - "borsh", - "num-derive", - "num-traits", - "solana-program", + "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 4.0.0", + "spl-token-2022 1.0.0", + "spl-token-group-interface 0.1.0", + "spl-token-metadata-interface 0.2.0", "thiserror", + "zstd", ] [[package]] -name = "solana-account-decoder" -version = "1.14.18" +name = "solana-accounts-db" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05a799348a70a5885cf428f1921e851cec204b58de1aeb0ca4409b5973d6d59d" +checksum = "5e8b4b15e353d5f0e0ddd77966c6f01b296bd83569af455da5fd9329356ff642" dependencies = [ - "Inflector", - "base64 0.13.0", + "arrayref", "bincode", - "bs58 0.4.0", + "blake3", "bv", + "bytemuck", + "byteorder", + "bzip2", + "crossbeam-channel", + "dashmap", + "flate2", + "fnv", + "im", + "index_list", + "itertools", "lazy_static", + "log", + "lz4", + "memmap2", + "modular-bitfield", + "num-derive 0.4.2", + "num-traits", + "num_cpus", + "num_enum 0.7.2", + "ouroboros", + "percentage", + "qualifier_attr", + "rand 0.8.5", + "rayon", + "regex", + "rustc_version", + "seqlock", "serde", "serde_derive", - "serde_json", - "solana-address-lookup-table-program", + "smallvec", + "solana-bucket-map", "solana-config-program", + "solana-frozen-abi", + "solana-frozen-abi-macro", + "solana-measure", + "solana-metrics", + "solana-nohash-hasher", + "solana-program-runtime", + "solana-rayon-threadlimit", "solana-sdk", + "solana-stake-program", + "solana-system-program", "solana-vote-program", - "spl-token", - "spl-token-2022", + "static_assertions", + "strum", + "strum_macros", + "tar", + "tempfile", "thiserror", - "zstd", ] [[package]] name = "solana-address-lookup-table-program" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ef5f98a080611a417da791853ca245ea7f58efefd4b5d9c5239e82693a65697" +checksum = "4c4eef9fc8aa3ff804dbf17766ab2d2fe38561adc8b521705faa782c18a108d8" dependencies = [ "bincode", "bytemuck", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", "rustc_version", "serde", @@ -3428,11 +3976,11 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16bb04d9b8c65d94706d0b06bf02bc105052c3f8db8bcba63de5a18e89ba8bce" +checksum = "13a4cbe27e78987b706caf90cbd16da9da3955c09a660b8107a96c2cb32f1124" dependencies = [ - "borsh", + "borsh 1.5.0", "futures", "solana-banks-interface", "solana-program", @@ -3445,9 +3993,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae3830efc383b740f5026f3fbc6391e8265a6b1e28683533088293c668c211ed" +checksum = "741279a09bf5ea1a3d17e591db7b189e163722e5c46423308c6a6165bea5e74d" dependencies = [ "serde", "solana-sdk", @@ -3456,13 +4004,14 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09864a6050fcf5e6913d16f56ed0a6bce11d325df5d37614345b7e130e37f749" +checksum = "f66768544951feb91c3470e255d4613295b5cc5a58a9cc6a4207ab9a0178cfe9" dependencies = [ "bincode", "crossbeam-channel", "futures", + "solana-accounts-db", "solana-banks-interface", "solana-client", "solana-runtime", @@ -3471,21 +4020,20 @@ dependencies = [ "tarpc", "tokio", "tokio-serde", - "tokio-stream", ] [[package]] name = "solana-bpf-loader-program" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "025c1ff6e5d33de0e7a360b47b46240c6972b10125d2946b6239fbd84e7edca3" +checksum = "60e9dd5e42193260cca0794bf4ab9e248f44b3d9710041f241b130d26ed682bc" dependencies = [ "bincode", "byteorder", "libsecp256k1", "log", + "scopeguard", "solana-measure", - "solana-metrics", "solana-program-runtime", "solana-sdk", "solana-zk-token-sdk", @@ -3495,14 +4043,17 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66fea900d00099e47ccfbcde017757bda696738b7adc9b1dcaa59955c2e488e0" +checksum = "1a7b34296d69867253671a71a2231b8d5b4a810bd7a5c1c603e7b542832d5980" dependencies = [ + "bv", + "bytemuck", "log", "memmap2", "modular-bitfield", - "rand 0.7.3", + "num_enum 0.7.2", + "rand 0.8.5", "solana-measure", "solana-sdk", "tempfile", @@ -3510,14 +4061,13 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43985f76c072db0412de3dcd8976bf6bc040ee10da8480fb5ba6b9455d733e6f" +checksum = "e8e9f61034a61db538a41700b6df0b4b9f0392038adaf780150481923ff94356" dependencies = [ "chrono", "clap 2.34.0", "rpassword", - "solana-perf", "solana-remote-wallet", "solana-sdk", "thiserror", @@ -3528,9 +4078,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c6b277a2927981b7f4e437741a37fc457eed5da7de6317c2a89a6996fd573e1" +checksum = "1c11246ea0930c3e95dc489d42f1020ea423a3daced137904d42ecc10a838436" dependencies = [ "dirs-next", "lazy_static", @@ -3542,65 +4092,71 @@ dependencies = [ "url", ] +[[package]] +name = "solana-cli-output" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea94deca7268b61a245429a7798f3e673baccb5cee5909e7de403b322d4c130a" +dependencies = [ + "Inflector", + "base64 0.21.7", + "chrono", + "clap 2.34.0", + "console", + "humantime", + "indicatif", + "pretty-hex", + "semver", + "serde", + "serde_json", + "solana-account-decoder", + "solana-clap-utils", + "solana-cli-config", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status", + "solana-vote-program", + "spl-memo 4.0.0", +] + [[package]] name = "solana-client" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839f0ebb1c14a25da0e2118a96ed630a49e3aa524a459b7ab98b410f44abcc7" +checksum = "13f2bd5a986d7cac1b4ffb4344413b70b6f21fd7ffa92a985911756b4ac7682a" dependencies = [ - "async-mutex", "async-trait", - "base64 0.13.0", "bincode", - "bs58 0.4.0", - "bytes", - "clap 2.34.0", - "crossbeam-channel", - "enum_dispatch", + "dashmap", "futures", "futures-util", - "indexmap", + "indexmap 2.2.6", "indicatif", - "itertools", - "jsonrpc-core", - "lazy_static", "log", "quinn", - "quinn-proto", - "rand 0.7.3", - "rand_chacha 0.2.2", "rayon", - "reqwest", - "rustls", - "semver", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-clap-utils", - "solana-faucet", + "solana-connection-cache", "solana-measure", "solana-metrics", - "solana-net-utils", + "solana-pubsub-client", + "solana-quic-client", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-rpc-client-nonce-utils", "solana-sdk", "solana-streamer", - "solana-transaction-status", - "solana-version", - "solana-vote-program", - "spl-token-2022", + "solana-thin-client", + "solana-tpu-client", + "solana-udp-client", "thiserror", "tokio", - "tokio-stream", - "tokio-tungstenite", - "tungstenite", - "url", ] [[package]] name = "solana-compute-budget-program" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e049f35d2a223509210eab1adb2bcc2c86bf919ab948f5e3142c9c87adcc1b97" +checksum = "ca100b2bdd7e455f5f0b9791bc204dacd684a0373ad1032697dbad43f34e527f" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -3608,9 +4164,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94cd8f45fddff299b73121fbf751164b7e029b3324b274b50160d787c82673d2" +checksum = "970d28779e92a11e32a89ee453edc7d89394d3a68d8c4b75ef0ffb833944c588" dependencies = [ "bincode", "chrono", @@ -3621,58 +4177,71 @@ dependencies = [ ] [[package]] -name = "solana-faucet" -version = "1.14.18" +name = "solana-connection-cache" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a4b7f4d15cb628a7f89e570a18914551211a5f1da81352dffd93881b191986a" +checksum = "dd7d0022ded19dca32ced5528c6a050596877fc8b9a89322d876960a89466e1b" dependencies = [ + "async-trait", "bincode", - "byteorder", - "clap 2.34.0", "crossbeam-channel", + "futures-util", + "indexmap 2.2.6", "log", - "serde", - "serde_derive", - "solana-clap-utils", - "solana-cli-config", - "solana-logger", + "rand 0.8.5", + "rayon", + "rcgen", + "solana-measure", "solana-metrics", "solana-sdk", - "solana-version", - "spl-memo", "thiserror", "tokio", ] +[[package]] +name = "solana-cost-model" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd3c63699df1680535daee8e486bd496e2ec849c427de4b6a42d4f1b27430949" +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.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc7245b88e5bcedc9096d7c7ffd8cf6769987b151e381e8a3561939898d9e495" +checksum = "35a0b24cc4d0ebd5fd45d6bd47bed3790f8a75ade67af8ff24a3d719a8bc93bc" dependencies = [ - "ahash", - "blake3", - "block-buffer 0.9.0", + "block-buffer 0.10.4", "bs58 0.4.0", "bv", - "byteorder", - "cc", "either", "generic-array", - "getrandom 0.1.16", - "hashbrown 0.12.3", "im", "lazy_static", "log", "memmap2", - "once_cell", - "rand_core 0.6.3", "rustc_version", "serde", "serde_bytes", "serde_derive", - "serde_json", - "sha2 0.10.6", + "sha2 0.10.8", "solana-frozen-abi-macro", "subtle", "thiserror", @@ -3680,36 +4249,47 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "546f204604da1d6958e412f4d3bc8cad34de6a81dc379fac07e53a29e224bcf0" +checksum = "51600f4066d3663ab2981fd24e77a8c2e65f5d20ea71b550b853ca9ae40eee7f" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "rustc_version", - "syn 1.0.109", + "syn 2.0.62", ] [[package]] name = "solana-gateway" -version = "0.2.2" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243daaf437dff89891d520c3e9be7b4a6940c30a1bda2ac094e621046f303eda" +checksum = "a11e5afc65ef1845214987e9724aa6406916d4a2d67ed66e4583cb75368bb645" dependencies = [ - "bitflags", - "borsh", - "num-derive", + "borsh 1.5.0", + "num-derive 0.4.2", "num-traits", - "sol-did", "solana-program", "thiserror", ] +[[package]] +name = "solana-loader-v4-program" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c566ebf0da216efc70054bf2d6d06c16fe44b63402c6f3bb04f6a88d8571d9b" +dependencies = [ + "log", + "solana-measure", + "solana-program-runtime", + "solana-sdk", + "solana_rbpf", +] + [[package]] name = "solana-logger" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12090fa9b638f374492c86c62b79e0e82479e3632ced02a33ff560ffdce72e04" +checksum = "dd79ef26804612173c95be8da84df3128d648173cf1f746de8f183ec8dbedd92" dependencies = [ "env_logger", "lazy_static", @@ -3718,9 +4298,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c98a872ae83f2e7c00846108f98a18f7f40265b2cd86b2d44369c33d9b7fb8f1" +checksum = "300f716a5f1c2f4b562fb008a0cc7d7c0d889cff802a7f8177fdf28772ae1ed9" dependencies = [ "log", "solana-sdk", @@ -3728,9 +4308,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7557878951c7defed6e4daf34e9334d8ea85b82c9a1b2d5cc50d069fd9191db9" +checksum = "abf1705d52e4f123856725e1b3842cd4928b954ff62391a95af142a5adc58ac6" dependencies = [ "crossbeam-channel", "gethostname", @@ -3738,20 +4318,21 @@ dependencies = [ "log", "reqwest", "solana-sdk", + "thiserror", ] [[package]] name = "solana-net-utils" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7684c80c774275783bb754aa07e2e18f2064551a78cda5e54e12f44c85f3803d" +checksum = "b1f2634fd50743e2ca075e663e07b0bd5c2f94db0ac320ce5bc2022e0002d82d" dependencies = [ "bincode", "clap 3.2.25", "crossbeam-channel", "log", "nix", - "rand 0.7.3", + "rand 0.8.5", "serde", "serde_derive", "socket2", @@ -3762,27 +4343,35 @@ dependencies = [ "url", ] +[[package]] +name = "solana-nohash-hasher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" + [[package]] name = "solana-perf" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2db417718e96fd2473025d4f2afb975dd295e9f7bd479cd3a0bcea20da38088" +checksum = "ad0264d7093d44c239d9eb41beb6877b7b1eea5ad8809c93c1d9ab0c840ba390" dependencies = [ - "ahash", + "ahash 0.8.7", "bincode", "bv", "caps", "curve25519-dalek", - "dlopen", - "dlopen_derive", + "dlopen2", "fnv", "lazy_static", "libc", "log", "nix", - "rand 0.7.3", + "rand 0.8.5", "rayon", + "rustc_version", "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", "solana-metrics", "solana-rayon-threadlimit", "solana-sdk", @@ -3791,16 +4380,21 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3e7df881407995597cf32299df06cc8ac3d7fc4cd53e69e95964832beca48c3" +checksum = "2a5513a02d622ba89e76baf4b49d25ae20c2c2c623fced12b0d6dd7b8f23e006" dependencies = [ - "base64 0.13.0", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.21.7", "bincode", - "bitflags", + "bitflags 2.5.0", "blake3", - "borsh", - "borsh-derive", + "borsh 0.10.3", + "borsh 0.9.3", + "borsh 1.5.0", "bs58 0.4.0", "bv", "bytemuck", @@ -3808,27 +4402,28 @@ dependencies = [ "console_error_panic_hook", "console_log", "curve25519-dalek", - "getrandom 0.2.5", + "getrandom 0.2.15", "itertools", "js-sys", "lazy_static", "libc", "libsecp256k1", + "light-poseidon", "log", - "memoffset", - "num-derive", + "memoffset 0.9.1", + "num-bigint 0.4.5", + "num-derive 0.4.2", "num-traits", - "parking_lot 0.12.0", - "rand 0.7.3", - "rand_chacha 0.2.2", + "parking_lot", + "rand 0.8.5", "rustc_version", "rustversion", "serde", "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", + "sha2 0.10.8", + "sha3 0.10.8", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-sdk-macro", @@ -3840,21 +4435,21 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba1ad7f8f71d46673e2b68edb902856516795dd6b9d2322fa4e9edcd6cf0caac" +checksum = "64dc9f666a8e4f93166ce58eea9dfbf275e5cad461b2f1bbfa06538718dc3212" dependencies = [ - "base64 0.13.0", + "base64 0.21.7", "bincode", "eager", "enum-iterator", "itertools", "libc", - "libloading", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", - "rand 0.7.3", + "percentage", + "rand 0.8.5", "rustc_version", "serde", "solana-frozen-abi", @@ -3862,23 +4457,27 @@ dependencies = [ "solana-measure", "solana-metrics", "solana-sdk", + "solana_rbpf", "thiserror", ] [[package]] name = "solana-program-test" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3003f9f008193bdcdc00e04c64f52da465d96d48148a2b60c68b483e9cef89" +checksum = "2760112327ffce892f6a21030f7c9e4b6da3ded8c8eadf1dbfffcb5a754c61db" dependencies = [ "assert_matches", "async-trait", - "base64 0.13.0", + "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", @@ -3886,15 +4485,69 @@ dependencies = [ "solana-runtime", "solana-sdk", "solana-vote-program", + "solana_rbpf", + "test-case", + "thiserror", + "tokio", +] + +[[package]] +name = "solana-pubsub-client" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5ffdcbdad685b87475a91909fdb442d2edfabc2870110580c7f0cf7eb7883f97" +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.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "056e909037b05097d2ff0181cb7e3d26876d8dff6d50701463a61e990cf84afd" +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 = "solana-rayon-threadlimit" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccad09c8fbcb13ba7a1aca9d6337bf439593e1ea104d7ba9519d6d09c89da63c" +checksum = "e93a5e1ef891dca2cca907f7196b6a5d3b80af4183f2be0f981906b16711ff5d" dependencies = [ "lazy_static", "num_cpus", @@ -3902,16 +4555,16 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a34ea5c66161b5f6a2085804bd0364bcdfdd584cfdb7237f88b6c3255199601" +checksum = "52c06eaf47d9a98ba22e890e68868f5d48c91e01268c541a53b5960288b617d6" dependencies = [ "console", "dialoguer", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", - "parking_lot 0.12.0", + "parking_lot", "qstring", "semver", "solana-sdk", @@ -3919,13 +4572,76 @@ dependencies = [ "uriparse", ] +[[package]] +name = "solana-rpc-client" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1d4b6f1f4e3dab7509401e85edc1c1ac208c61819de90178e01cf162c9c051" +dependencies = [ + "async-trait", + "base64 0.21.7", + "bincode", + "bs58 0.4.0", + "indicatif", + "log", + "reqwest", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder", + "solana-rpc-client-api", + "solana-sdk", + "solana-transaction-status", + "solana-version", + "solana-vote-program", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31feddef24d3e0aab189571adea7f109639ef6179fcd3cd34ffc8c73d3409f1" +dependencies = [ + "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 1.0.0", + "thiserror", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1837728262063723c659e4b8c0acf0baa99cd38cb333511456465d2c9e654474" +dependencies = [ + "clap 2.34.0", + "solana-clap-utils", + "solana-rpc-client", + "solana-sdk", + "thiserror", +] + [[package]] name = "solana-runtime" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04528c39dace2ee513d2c0fa849e02a54581470634fe9ec0699354f35c29409d" +checksum = "9a3480088ad0ffb701ada496f19754b4ff737e516c6b5f1231508e50ae2e0ea3" dependencies = [ + "aquamarine", "arrayref", + "base64 0.21.7", "bincode", "blake3", "bv", @@ -3945,32 +4661,46 @@ dependencies = [ "lru", "lz4", "memmap2", - "num-derive", + "mockall", + "modular-bitfield", + "num-derive 0.4.2", "num-traits", "num_cpus", - "once_cell", + "num_enum 0.7.2", "ouroboros", - "rand 0.7.3", + "percentage", + "qualifier_attr", + "rand 0.8.5", "rayon", "regex", "rustc_version", "serde", "serde_derive", + "serde_json", + "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-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", @@ -3982,15 +4712,15 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bdc5c047bf29730ad00e2c9ef92d396877c836633177089a00b7311e6eb3ead" +checksum = "8f50cac89269a01235f6b421bc580132191f4df388f4265513e78fd00cf864dd" dependencies = [ "assert_matches", - "base64 0.13.0", + "base64 0.21.7", "bincode", - "bitflags", - "borsh", + "bitflags 2.5.0", + "borsh 1.5.0", "bs58 0.4.0", "bytemuck", "byteorder", @@ -4007,20 +4737,24 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive", + "num-derive 0.4.2", "num-traits", + "num_enum 0.7.2", "pbkdf2 0.11.0", "qstring", + "qualifier_attr", "rand 0.7.3", - "rand_chacha 0.2.2", + "rand 0.8.5", "rustc_version", "rustversion", "serde", "serde_bytes", "serde_derive", "serde_json", - "sha2 0.10.6", - "sha3 0.10.6", + "serde_with", + "sha2 0.10.8", + "sha3 0.10.8", + "siphasher", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger", @@ -4033,22 +4767,28 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43cff60ba1f94594f1de7baf649bf781383e806e834e26607ff8857a9452cd3c" +checksum = "5cb099b2f9c0a65a6f23ced791325141cd68c27b04d11c04fef838a00f613861" dependencies = [ "bs58 0.4.0", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "rustversion", - "syn 1.0.109", + "syn 2.0.62", ] +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + [[package]] name = "solana-send-transaction-service" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626f605b0f5601a6cc7d7390bbe7248bf624e130dacd4c18ea8f7e3d5eca390d" +checksum = "0deed4fe8bb31ff178d8b7e8295bc81e6e1d704fc0e2c5565f58d9eb8feec89d" dependencies = [ "crossbeam-channel", "log", @@ -4057,41 +4797,36 @@ dependencies = [ "solana-metrics", "solana-runtime", "solana-sdk", + "solana-tpu-client", ] [[package]] name = "solana-stake-program" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d12cac4413492df0e92b7caa99db81f1e81ee2ca103b97cae215cb7189d3ec7" +checksum = "4ea02d44b82ed0eb271871cf8a1b8179a0ab50f4f995e7d8ae691c1971bd0a0e" dependencies = [ "bincode", "log", - "num-derive", - "num-traits", "rustc_version", - "serde", - "serde_derive", "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-metrics", "solana-program-runtime", "solana-sdk", "solana-vote-program", - "thiserror", ] [[package]] name = "solana-streamer" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "753f510e0e145e70238fc597571e2bb5f2871dc022b04e869024b5dcf1fd82c3" +checksum = "f8a20843e8370adb3c04f47caa79ffdc92ae1bf078ad26530be1bca5d7bdd5d2" dependencies = [ + "async-channel", + "bytes", "crossbeam-channel", "futures-util", "histogram", - "indexmap", + "indexmap 2.2.6", "itertools", "libc", "log", @@ -4100,9 +4835,11 @@ dependencies = [ "percentage", "pkcs8", "quinn", - "rand 0.7.3", + "quinn-proto", + "rand 0.8.5", "rcgen", "rustls", + "smallvec", "solana-metrics", "solana-perf", "solana-sdk", @@ -4111,16 +4848,69 @@ dependencies = [ "x509-parser", ] +[[package]] +name = "solana-system-program" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01294e45b407b7d4c8ff546af6f60344efd6591cf162c88e231ee3ba2c544672" +dependencies = [ + "bincode", + "log", + "serde", + "serde_derive", + "solana-program-runtime", + "solana-sdk", +] + +[[package]] +name = "solana-thin-client" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c74da8f36b89b28c47e5ba3bad5279ff3dfea5829154882845d4821fc76ff497" +dependencies = [ + "bincode", + "log", + "rayon", + "solana-connection-cache", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", +] + +[[package]] +name = "solana-tpu-client" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f2fd4b4aeffa14b9c5be9913072ea8e72ca261254a65a999f3d2fd70e7a660" +dependencies = [ + "async-trait", + "bincode", + "futures-util", + "indexmap 2.2.6", + "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.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe6a451415da98f850d5777df18d588d7504393106aea295b642cd243115ed77" +checksum = "3efa0d30f78dbc74e795638b053dd6ec7230739301e7f0e06b586f7731fd25c8" dependencies = [ "Inflector", - "base64 0.13.0", + "base64 0.21.7", "bincode", - "borsh", + "borsh 0.10.3", "bs58 0.4.0", "lazy_static", "log", @@ -4128,23 +4918,34 @@ dependencies = [ "serde_derive", "serde_json", "solana-account-decoder", - "solana-address-lookup-table-program", - "solana-measure", - "solana-metrics", "solana-sdk", - "solana-vote-program", - "spl-associated-token-account", - "spl-memo", - "spl-token", - "spl-token-2022", + "spl-associated-token-account 2.3.0", + "spl-memo 4.0.0", + "spl-token 4.0.0", + "spl-token-2022 1.0.0", + "thiserror", +] + +[[package]] +name = "solana-udp-client" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32af58cadd37be19d04e0f3877104b8640bccc4be8ca1dbf431549b399b784c2" +dependencies = [ + "async-trait", + "solana-connection-cache", + "solana-net-utils", + "solana-sdk", + "solana-streamer", "thiserror", + "tokio", ] [[package]] name = "solana-version" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a3d9aa0a819a22f5befc7e8df5413259621b5d20be0a5a210d1fb41a083a09b" +checksum = "42c7cef8aa9f1c633bf09dd91b8e635b6b30c40236652031b1800b245dc1bd02" dependencies = [ "log", "rustc_version", @@ -4156,15 +4957,34 @@ dependencies = [ "solana-sdk", ] +[[package]] +name = "solana-vote" +version = "1.18.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12945ee508c751ffdce58f976be6e58a05529ce0032c1f7db76eed6a8d76b33c" +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.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb0bb49cc1490ce16133368f4a04e0671f856d481f95416f03f08fede7d993ba" +checksum = "725a39044d455c08fe83fca758e94e5ddfaa25f6e2e2cfd5c31d7afdcad8de38" dependencies = [ "bincode", "log", - "num-derive", + "num-derive 0.4.2", "num-traits", "rustc_version", "serde", @@ -4172,6 +4992,7 @@ dependencies = [ "solana-frozen-abi", "solana-frozen-abi-macro", "solana-metrics", + "solana-program", "solana-program-runtime", "solana-sdk", "thiserror", @@ -4179,13 +5000,12 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9f1fd63cbd19d05b61c8416f00ca8f8f9c61340b292166e76b19743aed93579" +checksum = "39263f3e47a160b9b67896f2225d56e6872905c066152cbe61f5fd201c52a6d2" dependencies = [ "bytemuck", - "getrandom 0.1.16", - "num-derive", + "num-derive 0.4.2", "num-traits", "solana-program-runtime", "solana-sdk", @@ -4194,23 +5014,21 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.14.18" +version = "1.18.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7a679b4dabee8d23a7bfa657440c892a88420191da11352313ab83f986826a7" +checksum = "630dc0b5f6250cf6a4c8b2bd3895283738915e83eba5453db20bb02b2527f302" dependencies = [ "aes-gcm-siv", - "arrayref", - "base64 0.13.0", + "base64 0.21.7", "bincode", "bytemuck", "byteorder", - "cipher 0.4.3", "curve25519-dalek", "getrandom 0.1.16", "itertools", "lazy_static", "merlin", - "num-derive", + "num-derive 0.4.2", "num-traits", "rand 0.7.3", "serde", @@ -4225,9 +5043,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.2.31" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80a28c5dfe7e8af38daa39d6561c8e8b9ed7a2f900951ebe7362ad6348d36c73" +checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" dependencies = [ "byteorder", "combine", @@ -4239,6 +5057,7 @@ dependencies = [ "rustc-demangle", "scroll", "thiserror", + "winapi", ] [[package]] @@ -4247,6 +5066,12 @@ 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" @@ -4259,129 +5084,741 @@ dependencies = [ [[package]] name = "spl-associated-token-account" -version = "1.1.3" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978dba3bcbe88d0c2c58366c254d9ea41c5f73357e72fc0bdee4d6b5fc99c8f4" +checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" dependencies = [ "assert_matches", - "borsh", - "num-derive", + "borsh 0.10.3", + "num-derive 0.4.2", "num-traits", "solana-program", - "spl-token", - "spl-token-2022", + "spl-token 4.0.0", + "spl-token-2022 1.0.0", "thiserror", ] [[package]] -name = "spl-governance" -version = "3.1.1" +name = "spl-associated-token-account" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7a42340af2f3334ee1ee718e6d68b939c98cab4ceb381429f952c72d68e1ebf" +checksum = "a2e688554bac5838217ffd1fab7845c573ff106b6336bf7d290db7c98d5a8efd" dependencies = [ - "arrayref", - "bincode", - "borsh", - "num-derive", + "assert_matches", + "borsh 1.5.0", + "num-derive 0.4.2", "num-traits", - "serde", - "serde_derive", "solana-program", - "spl-governance-addin-api", - "spl-governance-tools", - "spl-token", + "spl-token 4.0.0", + "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "thiserror", ] [[package]] -name = "spl-governance-addin-api" -version = "0.1.3" +name = "spl-discriminator" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e0feddb2c7efa42f39954e3bb1b0bfc6dc7e9292ca467eff40ecd934c14106b" +checksum = "daa600f2fe56f32e923261719bae640d873edadbc5237681a39b8e37bfd4d263" dependencies = [ - "borsh", + "bytemuck", "solana-program", - "spl-governance-tools", + "spl-discriminator-derive 0.1.2", ] [[package]] -name = "spl-governance-addin-mock" -version = "0.1.3" +name = "spl-discriminator" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49390332293d75d973dec617090157ab39d3d63f064ea7790cc8fee36d26c149" +checksum = "34d1814406e98b08c5cd02c1126f83fd407ad084adce0b05fda5730677822eac" dependencies = [ - "arrayref", - "bincode", - "borsh", - "num-derive", - "num-traits", - "serde", - "serde_derive", + "bytemuck", "solana-program", - "spl-governance-addin-api", - "spl-governance-tools", - "spl-token", - "thiserror", + "spl-discriminator-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] -name = "spl-governance-tools" -version = "0.1.3" +name = "spl-discriminator" +version = "0.2.2" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive 0.2.0 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3bd674d9e8f3fc9ea628dcbe56d48991ea1cb05b994a7845782572c705efd836" +checksum = "07fd7858fc4ff8fb0e34090e41d7eb06a823e1057945c26d480bfc21d2338a93" dependencies = [ - "arrayref", - "bincode", - "borsh", - "num-derive", - "num-traits", - "serde", - "serde_derive", + "quote", + "spl-discriminator-syn 0.1.2", + "syn 2.0.62", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 2.0.62", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "quote", + "spl-discriminator-syn 0.2.0 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "syn 2.0.62", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18fea7be851bd98d10721782ea958097c03a0c2a07d8d4997041d0ece6319a63" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.62", + "thiserror", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.62", + "thiserror", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.62", + "thiserror", +] + +[[package]] +name = "spl-governance" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79362b8e4616f4f84ca5a2a413f84e88fb4dd00322fe4baaa407254901ef6d62" +dependencies = [ + "arrayref", + "bincode", + "borsh 0.10.3", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-program", + "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 4.0.0", + "thiserror", +] + +[[package]] +name = "spl-governance" +version = "4.0.0" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "arrayref", + "bincode", + "borsh 1.5.0", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-program", + "spl-governance-addin-api 0.1.4 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-governance-tools 0.1.4 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-token 4.0.1", + "spl-token-2022 3.0.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-transfer-hook-example", + "spl-transfer-hook-interface 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "thiserror", +] + +[[package]] +name = "spl-governance-addin-api" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dc1be90f8b71e336933fedbe17f645cd33d36e8451dfb6ce1210ef585dc73b6" +dependencies = [ + "borsh 0.10.3", + "solana-program", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spl-governance-addin-api" +version = "0.1.4" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "borsh 1.5.0", + "solana-program", + "spl-governance-tools 0.1.4 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", +] + +[[package]] +name = "spl-governance-addin-mock" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79cd47d0f9128ec6ae713b61ab2225c73e97460550f383f4f9cabad4e0c7a6e3" +dependencies = [ + "arrayref", + "bincode", + "borsh 0.10.3", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-program", + "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 4.0.0", + "thiserror", +] + +[[package]] +name = "spl-governance-tools" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73b9c475357534e31e296a40491a5a834cf1289292f9eb592628a8f6e2525d7f" +dependencies = [ + "arrayref", + "bincode", + "borsh 0.10.3", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-program", + "spl-token 4.0.0", + "thiserror", +] + +[[package]] +name = "spl-governance-tools" +version = "0.1.4" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "arrayref", + "bincode", + "borsh 1.5.0", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-program", + "spl-token 4.0.1", + "thiserror", +] + +[[package]] +name = "spl-memo" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-memo" +version = "4.0.1" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "solana-program", +] + +[[package]] +name = "spl-pod" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5db7e4efb1107b0b8e52a13f035437cdcb36ef99c58f6d467f089d9b2915a" +dependencies = [ + "borsh 0.10.3", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error 0.3.1", +] + +[[package]] +name = "spl-pod" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046ce669f48cf2eca1ec518916d8725596bfb655beb1c74374cf71dc6cb773c9" +dependencies = [ + "borsh 1.5.0", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error 0.4.1", +] + +[[package]] +name = "spl-pod" +version = "0.2.2" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "borsh 1.5.0", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error 0.4.0", +] + +[[package]] +name = "spl-program-error" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0657b6490196971d9e729520ba934911ff41fbb2cb9004463dbe23cf8b4b4f" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-program-error-derive 0.3.2", + "thiserror", +] + +[[package]] +name = "spl-program-error" +version = "0.4.0" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-program-error-derive 0.4.0", + "thiserror", +] + +[[package]] +name = "spl-program-error" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49065093ea91f57b9b2bd81493ff705e2ad4e64507a07dbc02b085778e02770e" +dependencies = [ + "num-derive 0.4.2", + "num-traits", + "solana-program", + "spl-program-error-derive 0.4.1", + "thiserror", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1845dfe71fd68f70382232742e758557afe973ae19e6c06807b2c30f5d5cb474" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.62", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.0" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.62", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.62", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f335787add7fa711819f9e7c573f8145a5358a709446fe2d24bf2a88117c90" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.1.1", + "spl-pod 0.1.1", + "spl-program-error 0.3.1", + "spl-type-length-value 0.3.1", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cace91ba08984a41556efe49cbf2edca4db2f577b649da7827d3621161784bf8" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-program-error 0.4.1", + "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.6.3" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-program-error 0.4.0", + "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", +] + +[[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 0.3.3", + "num-traits", + "num_enum 0.5.11", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-token" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.3.3", + "num-traits", + "num_enum 0.6.1", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-token" +version = "4.0.1" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum 0.7.2", + "solana-program", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum 0.7.2", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo 4.0.0", + "spl-pod 0.1.1", + "spl-token 4.0.0", + "spl-token-group-interface 0.1.0", + "spl-token-metadata-interface 0.2.0", + "spl-transfer-hook-interface 0.4.1", + "spl-type-length-value 0.3.1", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5412f99ae7ee6e0afde00defaa354e6228e47e30c0e3adf553e2e01e6abb584" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum 0.7.2", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo 4.0.0", + "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 4.0.0", + "spl-token-group-interface 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-metadata-interface 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-transfer-hook-interface 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "3.0.2" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum 0.7.2", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo 4.0.1", + "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-token 4.0.1", + "spl-token-group-interface 0.2.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-token-metadata-interface 0.3.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-transfer-hook-interface 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "thiserror", +] + +[[package]] +name = "spl-token-client" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5d42e4192995c4702c06544e834882c3c26f754a76821fe34790f157914a365" +dependencies = [ + "async-trait", + "curve25519-dalek", + "futures", + "futures-util", + "solana-banks-interface", + "solana-cli-output", + "solana-program-test", + "solana-rpc-client", + "solana-rpc-client-api", + "solana-sdk", + "spl-associated-token-account 3.0.2", + "spl-memo 4.0.0", + "spl-token 4.0.0", + "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-group-interface 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-metadata-interface 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-transfer-hook-interface 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.1.1", + "spl-pod 0.1.1", + "spl-program-error 0.3.1", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d419b5cfa3ee8e0f2386fd7e02a33b3ec8a7db4a9c7064a2ea24849dc4a273b6" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-program-error 0.4.1", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.2.3" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-program-error 0.4.0", +] + +[[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 0.1.1", + "spl-pod 0.1.1", + "spl-program-error 0.3.1", + "spl-type-length-value 0.3.1", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30179c47e93625680dabb620c6e7931bd12d62af390f447bc7beb4a3a9b5feee" +dependencies = [ + "borsh 1.5.0", + "solana-program", + "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-program-error 0.4.1", + "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.3.3" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "borsh 1.5.0", + "solana-program", + "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-program-error 0.4.0", + "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", +] + +[[package]] +name = "spl-transfer-hook-example" +version = "0.6.0" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "arrayref", + "solana-program", + "spl-tlv-account-resolution 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-token-2022 3.0.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-transfer-hook-interface 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator 0.1.1", + "spl-pod 0.1.1", + "spl-program-error 0.3.1", + "spl-tlv-account-resolution 0.5.2", + "spl-type-length-value 0.3.1", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a98359769cd988f7b35c02558daa56d496a7e3bd8626e61f90a7c757eedb9b" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-program-error 0.4.1", + "spl-tlv-account-resolution 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.6.3" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +dependencies = [ + "arrayref", + "bytemuck", "solana-program", - "spl-token", - "thiserror", + "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-program-error 0.4.0", + "spl-tlv-account-resolution 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", ] [[package]] -name = "spl-memo" -version = "3.0.1" +name = "spl-type-length-value" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd0dc6f70db6bacea7ff25870b016a65ba1d1b6013536f08e4fd79a8f9005325" +checksum = "8f9ebd75d29c5f48de5f6a9c114e08531030b75b8ac2c557600ac7da0b73b1e8" dependencies = [ + "bytemuck", "solana-program", + "spl-discriminator 0.1.1", + "spl-pod 0.1.1", + "spl-program-error 0.3.1", ] [[package]] -name = "spl-token" -version = "3.5.0" +name = "spl-type-length-value" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e85e168a785e82564160dcb87b2a8e04cee9bfd1f4d488c729d53d6a4bd300d" +checksum = "422ce13429dbd41d2cee8a73931c05fda0b0c8ca156a8b0c19445642550bb61a" dependencies = [ - "arrayref", "bytemuck", - "num-derive", - "num-traits", - "num_enum", "solana-program", - "thiserror", + "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-program-error 0.4.1", ] [[package]] -name = "spl-token-2022" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0043b590232c400bad5ee9eb983ced003d15163c4c5d56b090ac6d9a57457b47" +name = "spl-type-length-value" +version = "0.4.3" +source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" dependencies = [ - "arrayref", "bytemuck", - "num-derive", - "num-traits", - "num_enum", "solana-program", - "solana-zk-token-sdk", - "spl-memo", - "spl-token", - "thiserror", + "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-program-error 0.4.0", ] [[package]] @@ -4418,8 +5855,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e385be0d24f186b4ce2f9982191e7101bb737312ad61c1f2f984f34bcf85d59" dependencies = [ "heck 0.4.1", - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "rustversion", "syn 1.0.109", ] @@ -4438,54 +5875,82 @@ checksum = "a7973cce6668464ea31f176d85b13c7ab3bba2cb3b77a2ed26abd7801688010a" [[package]] name = "syn" -version = "0.15.44" +version = "1.0.109" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ca4b3b69a77cbe1ffc9e198781b7acb0c7365a883670e8f1c1bc66fba79a5c5" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" dependencies = [ - "proc-macro2 0.4.30", - "quote 0.6.13", - "unicode-xid 0.1.0", + "proc-macro2", + "quote", + "unicode-ident", ] [[package]] name = "syn" -version = "1.0.109" +version = "2.0.62" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +checksum = "9f660c3bfcefb88c538776b6685a0c472e3128b51e74d48793dc2a488196e8eb" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "unicode-ident", ] [[package]] -name = "syn" -version = "2.0.18" +name = "syn_derive" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32d41677bcbe24c20c52e7c70b0d8db04134c5d1066bf98662e2871ad200ea3e" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "unicode-ident", + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.62", ] +[[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 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", - "unicode-xid 0.2.2", + "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.38" +version = "0.4.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" +checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" dependencies = [ "filetime", "libc", @@ -4511,7 +5976,7 @@ dependencies = [ "thiserror", "tokio", "tokio-serde", - "tokio-util 0.6.9", + "tokio-util 0.6.10", "tracing", "tracing-opentelemetry", ] @@ -4522,33 +5987,71 @@ version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ee42b4e559f17bce0385ebf511a7beb67d5cc33c12c96b7f4e9789919d9c10f" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", + "proc-macro2", + "quote", "syn 1.0.109", ] [[package]] name = "tempfile" -version = "3.5.0" +version = "3.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9fbec84f381d5795b08656e4912bec604d162bff9291d6189a78f4c8ab87998" +checksum = "85b77fafb263dd9d05cbeac119526425676db3784113aa9295c88498cbf8bff1" dependencies = [ "cfg-if", "fastrand", - "redox_syscall 0.3.5", "rustix", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] name = "termcolor" -version = "1.1.3" +version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bab24d30b911b2376f3a13cc2cd443142f0c81dda04c118693e35b3835757755" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" dependencies = [ "winapi-util", ] +[[package]] +name = "termtree" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3369f5ac52d5eb6ab48c6b4ffdc8efbcad6b89c765749064ba298f2c68a16a76" + +[[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.62", +] + +[[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.62", + "test-case-core", +] + [[package]] name = "textwrap" version = "0.11.0" @@ -4560,56 +6063,50 @@ dependencies = [ [[package]] name = "textwrap" -version = "0.16.0" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" +checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.40" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978c9a314bd8dc99be594bc3c175faaa9794be04a5a5e153caba6915336cebac" +checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.40" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9456a42c5b0d803c8cd86e73dd7cc9edd429499f37a3550d286d5e86720569f" +checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 2.0.18", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "thread_local" -version = "1.1.4" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5516c27b78311c50bf42c071425c560ac799b11c30b31f87e3081965fe5e0180" +checksum = "8b9ef9bad013ada3808854ceac7b46812a6465ba368859a37e2100283d2d719c" dependencies = [ + "cfg-if", "once_cell", ] [[package]] name = "time" -version = "0.1.43" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" -dependencies = [ - "libc", - "winapi", -] - -[[package]] -name = "time" -version = "0.3.21" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3403384eaacbca9923fa06940178ac13e4edb725486d70e8e15881d0c836cc" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ + "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -4617,16 +6114,17 @@ dependencies = [ [[package]] name = "time-core" -version = "0.1.1" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7300fbefb4dadc1af235a9cef3737cea692a9d97e1b9cbcd4ebdae6f8868e6fb" +checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.9" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "372950940a5f07bf38dbe211d7283c9e6d7327df53794992d293e534c733d09b" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -4651,59 +6149,82 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] [[package]] name = "tinyvec_macros" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "token-voter" +version = "0.1.0" +dependencies = [ + "ahash 0.8.7", + "anchor-lang", + "anchor-spl", + "arrayref", + "borsh 0.10.3", + "env_logger", + "log", + "solana-program", + "solana-program-test", + "solana-sdk", + "spl-associated-token-account 3.0.2", + "spl-governance 4.0.0 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 3.5.0", + "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-client", + "spl-transfer-hook-interface 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "static_assertions", +] [[package]] name = "tokio" -version = "1.14.1" +version = "1.37.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d0183f6f6001549ab68f8c7585093bb732beefbcf6d23a10b9b95c73a1dd49" +checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" dependencies = [ - "autocfg", + "backtrace", "bytes", "libc", - "memchr", "mio", "num_cpus", - "once_cell", - "parking_lot 0.11.2", + "parking_lot", "pin-project-lite", "signal-hook-registry", + "socket2", "tokio-macros", - "winapi", + "windows-sys 0.48.0", ] [[package]] name = "tokio-macros" -version = "1.7.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b557f72f448c511a979e2564e55d74e6c4432fc96ff4f6241bc6bded342643b7" +checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "tokio-rustls" -version = "0.23.2" +version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a27d5f2b839802bd8267fa19b0530f5a08b9c08cd417976be2a65d130fe1c11b" +checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ "rustls", "tokio", - "webpki", ] [[package]] @@ -4724,9 +6245,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.12" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8fb52b74f05dbf495a8fba459fdc331812b96aa086d9eb78101fa0d4569c3313" +checksum = "267ac89e0bec6e691e5813911606935d77c476ff49024f98abcea3e7b15e37af" dependencies = [ "futures-core", "pin-project-lite", @@ -4735,9 +6256,9 @@ dependencies = [ [[package]] name = "tokio-tungstenite" -version = "0.17.2" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f714dd15bead90401d77e04243611caec13726c2408afd5b31901dfcdcb3b181" +checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", @@ -4745,15 +6266,14 @@ dependencies = [ "tokio", "tokio-rustls", "tungstenite", - "webpki", - "webpki-roots", + "webpki-roots 0.25.4", ] [[package]] name = "tokio-util" -version = "0.6.9" +version = "0.6.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99e1983e5d376cd8eb4b66604d2e99e79f5bd988c3055891dcd8c9e2604cc0" +checksum = "36943ee01a6d67977dd3f84a5a1d2efeb4ada3a1ae771cadfaa535d9d9fc6507" dependencies = [ "bytes", "futures-core", @@ -4766,46 +6286,94 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.2" +version = "0.7.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f988a1a1adc2fb21f9c12aa96441da33a1728193ae0b95d2be22dbd17fcb4e5c" +checksum = "9cf6b47b3771c49ac75ad09a6162f53ad4b8088b76ac60e8ec1455b31a189fe1" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] name = "toml" -version = "0.5.8" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" dependencies = [ "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.12", ] [[package]] name = "toml_datetime" -version = "0.6.1" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.19.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap 2.2.6", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ab8ed2edee10b50132aed5f331333428b011c99402b5a534154ed15746f9622" +checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +dependencies = [ + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.8", +] [[package]] name = "tower-service" -version = "0.3.1" +version = "0.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "360dfd1d6d30e05fda32ace2c8c70e9c0a9da713275777f5a4dbb8a1893930c6" +checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" [[package]] name = "tracing" -version = "0.1.32" +version = "0.1.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" dependencies = [ - "cfg-if", "log", "pin-project-lite", "tracing-attributes", @@ -4814,22 +6382,22 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.20" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b" +checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] name = "tracing-core" -version = "0.1.23" +version = "0.1.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" dependencies = [ - "lazy_static", + "once_cell", "valuable", ] @@ -4848,9 +6416,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.11" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bc28f93baff38037f64e6f43d34cfa1605f27a49c34e8a04c5e78b0babf2596" +checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" dependencies = [ "sharded-slab", "thread_local", @@ -4859,82 +6427,75 @@ dependencies = [ [[package]] name = "try-lock" -version = "0.2.3" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59547bce71d9c38b83d9c0e92b6066c4253371f15005def0c30d9657f50c7642" +checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" [[package]] name = "tungstenite" -version = "0.17.3" +version = "0.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e27992fd6a8c29ee7eef28fc78349aa244134e10ad447ce3b9f0ac0ed0fa4ce0" +checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" dependencies = [ - "base64 0.13.0", "byteorder", "bytes", + "data-encoding", "http", "httparse", "log", "rand 0.8.5", "rustls", - "sha-1", + "sha1", "thiserror", "url", "utf-8", - "webpki", - "webpki-roots", + "webpki-roots 0.24.0", ] [[package]] name = "typenum" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-bidi" -version = "0.3.7" +version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a01404663e3db436ed2746d9fefef640d868edae3cceb81c3b8d5732fda678f" +checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" [[package]] name = "unicode-ident" -version = "1.0.9" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b15811caf2415fb889178633e7724bad2509101cde276048e013b9def5e51fa0" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] name = "unicode-normalization" -version = "0.1.19" +version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54590932941a9e9266f0832deed84ebe1bf2e4c9e4a3554d393d18f5e854bf9" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" dependencies = [ "tinyvec", ] [[package]] name = "unicode-segmentation" -version = "1.9.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "unicode-width" -version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b" - -[[package]] -name = "unicode-xid" -version = "0.1.0" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc" +checksum = "68f5e5f3158ecfd4b8ff6fe086db7c8467a2dfdac97fe420f2b7c4aa97af66d6" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" [[package]] name = "universal-hash" @@ -4955,12 +6516,24 @@ dependencies = [ "void", ] +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + [[package]] name = "untrusted" version = "0.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" @@ -4973,13 +6546,12 @@ dependencies = [ [[package]] name = "url" -version = "2.2.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a507c383b2d33b5fc35d1861e77e6b383d158b2da5e14fe51b83dfedf6fd578c" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", - "matches", "percent-encoding", ] @@ -5015,22 +6587,20 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" -version = "2.3.2" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", - "winapi", "winapi-util", ] [[package]] name = "want" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ce8a968cb1cd110d136ff8b819a556d6fb6d919363c61534f6860c7eb172ba0" +checksum = "bfa7760aed19e106de2c7c0b581b509f2f25d3dacaf737cb82ac61bc6d760b0e" dependencies = [ - "log", "try-lock", ] @@ -5042,15 +6612,15 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.86" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bba0e8cb82ba49ff4e229459ff22a191bbe9a1cb3a341610c9c33efc27ddf73" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -5058,24 +6628,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.86" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b04bc93f9d6bdee709f6bd2118f57dd6679cf1176a1af464fca3ab0d66d8fb" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 2.0.18", + "proc-macro2", + "quote", + "syn 2.0.62", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.29" +version = "0.4.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2eb6ec270a31b1d3c7e266b999739109abce8b6c87e4b31fcfcd788b65267395" +checksum = "76bc14366121efc8dbb487ab05bcc9d346b3b5ec0eaa76e46594cabbe51762c0" dependencies = [ "cfg-if", "js-sys", @@ -5085,61 +6655,57 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.86" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14d6b024f1a526bb0234f52840389927257beb670610081360e5a03c5df9c258" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ - "quote 1.0.28", + "quote", "wasm-bindgen-macro-support", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.86" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e128beba882dd1eb6200e1dc92ae6c5dbaa4311aa7bb211ca035779e5efc39f8" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 2.0.18", + "proc-macro2", + "quote", + "syn 2.0.62", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.86" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9d5b4305409d1fc9482fee2d7f9bcbf24b3972bf59817ef757e23982242a93" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] [[package]] -name = "webpki" -version = "0.22.0" +name = "webpki-roots" +version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f095d78192e208183081cc07bc5515ef55216397af48b873e5edcd72637fa1bd" +checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" dependencies = [ - "ring", - "untrusted", + "rustls-webpki", ] [[package]] name = "webpki-roots" -version = "0.22.2" +version = "0.25.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "552ceb903e957524388c4d3475725ff2c8b7960922063af6ce53c9a43da07449" -dependencies = [ - "webpki", -] +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] name = "winapi" @@ -5159,11 +6725,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.5" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b" dependencies = [ - "winapi", + "windows-sys 0.52.0", ] [[package]] @@ -5173,211 +6739,179 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] -name = "windows-sys" -version = "0.32.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3df6e476185f92a12c072be4a189a0210dcdcf512a1891d6dff9edb874deadc6" -dependencies = [ - "windows_aarch64_msvc 0.32.0", - "windows_i686_gnu 0.32.0", - "windows_i686_msvc 0.32.0", - "windows_x86_64_gnu 0.32.0", - "windows_x86_64_msvc 0.32.0", -] - -[[package]] -name = "windows-sys" -version = "0.42.0" +name = "windows-core" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7" +checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.5", ] [[package]] name = "windows-sys" -version = "0.45.0" +version = "0.48.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" dependencies = [ - "windows-targets 0.42.2", + "windows-targets 0.48.5", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.48.0", + "windows-targets 0.52.5", ] [[package]] name = "windows-targets" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "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.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b1eb6f0cd7c80c79759c929114ef071b87354ce476d9d94271031c0497adfd5" +checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb" dependencies = [ - "windows_aarch64_gnullvm 0.48.0", - "windows_aarch64_msvc 0.48.0", - "windows_i686_gnu 0.48.0", - "windows_i686_msvc 0.48.0", - "windows_x86_64_gnu 0.48.0", - "windows_x86_64_gnullvm 0.48.0", - "windows_x86_64_msvc 0.48.0", + "windows_aarch64_gnullvm 0.52.5", + "windows_aarch64_msvc 0.52.5", + "windows_i686_gnu 0.52.5", + "windows_i686_gnullvm", + "windows_i686_msvc 0.52.5", + "windows_x86_64_gnu 0.52.5", + "windows_x86_64_gnullvm 0.52.5", + "windows_x86_64_msvc 0.52.5", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91ae572e1b79dba883e0d315474df7305d12f569b400fcf90581b06062f7e1bc" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.32.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8e92753b1c443191654ec532f14c199742964a061be25d77d7a96f09db20bf5" +checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263" [[package]] name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] name = "windows_aarch64_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2ef27e0d7bdfcfc7b868b317c1d32c641a6fe4629c171b8928c7b08d98d7cf3" - -[[package]] -name = "windows_i686_gnu" -version = "0.32.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a711c68811799e017b6038e0922cb27a5e2f43a2ddb609fe0b6f3eeda9de615" +checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6" [[package]] name = "windows_i686_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] name = "windows_i686_gnu" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "622a1962a7db830d6fd0a69683c80a18fda201879f0f447f065a3b7467daa241" +checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670" [[package]] -name = "windows_i686_msvc" -version = "0.32.0" +name = "windows_i686_gnullvm" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "146c11bb1a02615db74680b32a68e2d61f553cc24c4eb5b4ca10311740e44172" +checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9" [[package]] name = "windows_i686_msvc" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] name = "windows_i686_msvc" -version = "0.48.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4542c6e364ce21bf45d69fdd2a8e455fa38d316158cfd43b3ac1c5b1b19f8e00" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.32.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c912b12f7454c6620635bbff3450962753834be2a594819bd5e945af18ec64bc" +checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf" [[package]] name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] name = "windows_x86_64_gnu" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca2b8a661f7628cbd23440e50b05d705db3686f894fc9580820623656af974b1" +checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.0" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7896dbc1f41e08872e9d5e8f8baa8fdd2677f29468c4e156210174edc7f7b953" +checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596" [[package]] name = "windows_x86_64_msvc" -version = "0.32.0" +version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "504a2476202769977a040c6364301a3f65d0cc9e3fb08600b2bda150a0488316" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" [[package]] name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.52.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0" [[package]] -name = "windows_x86_64_msvc" -version = "0.48.0" +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a515f5799fe4961cb532f983ce2b23082366b898e52ffbce459c86f67c8378a" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] [[package]] name = "winnow" -version = "0.4.1" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae8970b36c66498d8ff1d66685dc86b91b29db0c7739899012f63a63814b4b28" +checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" dependencies = [ "memchr", ] [[package]] name = "winreg" -version = "0.10.1" +version = "0.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80d0f4e272c85def139476380b12f9ac60926689dd2e01d4923222f40580869d" +checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" dependencies = [ - "winapi", + "cfg-if", + "windows-sys 0.48.0", ] [[package]] @@ -5387,7 +6921,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" dependencies = [ "asn1-rs", - "base64 0.13.0", + "base64 0.13.1", "data-encoding", "der-parser", "lazy_static", @@ -5395,40 +6929,47 @@ dependencies = [ "oid-registry", "rusticata-macros", "thiserror", - "time 0.3.21", + "time", ] [[package]] name = "xattr" -version = "0.2.2" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "244c3741f4240ef46274860397c7c74e50eb23624996930e484c16679633a54c" +checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" dependencies = [ "libc", + "linux-raw-sys", + "rustix", ] [[package]] -name = "yaml-rust" -version = "0.4.5" +name = "yasna" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" +checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" dependencies = [ - "linked-hash-map", + "time", ] [[package]] -name = "yansi" -version = "0.5.0" +name = "zerocopy" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" +checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087" +dependencies = [ + "zerocopy-derive", +] [[package]] -name = "yasna" -version = "0.5.2" +name = "zerocopy-derive" +version = "0.7.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ - "time 0.3.21", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] @@ -5442,14 +6983,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.3.2" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3f8f187641dad4f680d25c4bfc4225b418165984179f26ca76ec4fb6441d3a17" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ - "proc-macro2 1.0.59", - "quote 1.0.28", - "syn 1.0.109", - "synstructure", + "proc-macro2", + "quote", + "syn 2.0.62", ] [[package]] @@ -5473,11 +7013,10 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.8+zstd.1.5.5" +version = "2.0.10+zstd.1.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5556e6ee25d32df2586c098bbfa278803692a20d0ab9565e049480d52707ec8c" +checksum = "c253a4914af5bafc8fa8c86ee400827e83cf6ec01195ec1f1ed8441bf00d65aa" dependencies = [ "cc", - "libc", "pkg-config", ] diff --git a/Cargo.toml b/Cargo.toml index a60de986..b5d8aea2 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,3 +2,7 @@ members = [ "programs/*" ] +resolver = "2" + +[profile.release] +overflow-checks = true \ No newline at end of file diff --git a/package.json b/package.json index 1ac49486..aa40b842 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,7 @@ "trailingComma": "all" }, "dependencies": { - "@project-serum/anchor": "^0.24.2", - "@project-serum/serum": "^0.13.61" - } + "@coral-xyz/anchor": "^0.30.0" + }, + "packageManager": "yarn@1.22.21+sha1.1959a18351b811cdeedbd484a8f86c3cc3bbaf72" } diff --git a/programs/gateway/Cargo.toml b/programs/gateway/Cargo.toml index 14294453..bd955058 100644 --- a/programs/gateway/Cargo.toml +++ b/programs/gateway/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gpl-civic-gateway" -version = "0.1.1" +version = "0.2.0" description = "SPL Governance addin for Civic Pass (www.civic.com)" license = "Apache-2.0" edition = "2018" @@ -15,25 +15,26 @@ no-idl = [] no-log-ix-name = [] cpi = ["no-entrypoint"] default = [] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] [dependencies] arrayref = "0.3.6" -anchor-lang = { version = "0.26.0", features = ["init-if-needed"] } -anchor-spl = "0.26.0" +anchor-lang = { version = "0.30.0", features = ["init-if-needed"] } +anchor-spl = "0.30.0" enum_dispatch = "0.3.8" itertools = "0.10.2" num = "0.4" num-derive = "0.3" num-traits = "0.2" -solana-gateway = "0.2.2" -solana-program = "1.14.16" -spl-governance = { version = "3.1.1", features = ["no-entrypoint"] } -spl-governance-tools= "0.1.3" -spl-governance-addin-api = "0.1.3" -spl-token = { version = "3.3", features = [ "no-entrypoint" ] } +solana-gateway = { version = "0.6.0", features = ["no-entrypoint"] } +solana-program = "1.18.12" +spl-governance = { version = "4.0.0", features = ["no-entrypoint"] } +spl-governance-tools= "0.1.4" +spl-governance-addin-api = "0.1.4" +spl-token = { version = "4.0.0", features = [ "no-entrypoint" ] } [dev-dependencies] -borsh = "0.9.1" -solana-sdk = "1.14.16" -solana-program-test = "1.14.16" -spl-governance-addin-mock = "0.1.3" \ No newline at end of file +borsh = "0.10.3" +solana-sdk = "1.18.12" +solana-program-test = "1.18.12" +spl-governance-addin-mock = "0.1.4" \ No newline at end of file diff --git a/programs/gateway/src/instructions/configure_registrar.rs b/programs/gateway/src/instructions/configure_registrar.rs index c02a6d00..9582eb1f 100644 --- a/programs/gateway/src/instructions/configure_registrar.rs +++ b/programs/gateway/src/instructions/configure_registrar.rs @@ -19,8 +19,8 @@ pub struct ConfigureRegistrar<'info> { /// - realm_authority is realm.authority /// CHECK: Owned by spl-governance instance specified in governance_program_id #[account( - address = registrar.realm @ GatewayError::InvalidRealmForRegistrar, - owner = registrar.governance_program_id.key() + owner = registrar.governance_program_id.key(), + constraint = realm.key() == registrar.realm @ GatewayError::InvalidRealmForRegistrar, )] pub realm: UncheckedAccount<'info>, diff --git a/programs/gateway/tests/program_test/gateway_voter_test.rs b/programs/gateway/tests/program_test/gateway_voter_test.rs index 4707e4a3..7fd57678 100644 --- a/programs/gateway/tests/program_test/gateway_voter_test.rs +++ b/programs/gateway/tests/program_test/gateway_voter_test.rs @@ -4,8 +4,8 @@ use std::sync::Arc; use anchor_lang::prelude::Pubkey; use itertools::Either; use solana_gateway::{ - instruction::{add_gatekeeper, issue_vanilla}, - state::{get_gatekeeper_address_with_seed, get_gateway_token_address_with_seed}, + instruction::{add_gatekeeper, issue}, + state::{get_gatekeeper_account_address, get_gateway_token_address_with_seed}, }; use solana_program::instruction::AccountMeta; @@ -47,7 +47,7 @@ pub struct GatewayCookie { impl GatewayCookie { pub fn get_gatekeeper_account(&self) -> Pubkey { - let (gatekeeper_account, _) = get_gatekeeper_address_with_seed( + let (gatekeeper_account, _) = get_gatekeeper_account_address( &self.gatekeeper.pubkey(), &self.gatekeeper_network.pubkey(), ); @@ -309,7 +309,7 @@ impl GatewayVoterTest { let gatekeeper_account = gateway_cookie.get_gatekeeper_account(); let gateway_token_cookie = GatewayTokenCookie::new(&wallet_cookie.address, gateway_cookie); - let mut issue_ix = issue_vanilla( + let mut issue_ix = issue( &self.bench.payer.pubkey(), &wallet_cookie.address, &gatekeeper_account, diff --git a/programs/gateway/tests/program_test/program_test_bench.rs b/programs/gateway/tests/program_test/program_test_bench.rs index 9d684bb7..fa01f293 100644 --- a/programs/gateway/tests/program_test/program_test_bench.rs +++ b/programs/gateway/tests/program_test/program_test_bench.rs @@ -18,7 +18,7 @@ use solana_sdk::{ transport::TransportError, }; -use borsh::BorshDeserialize; +use borsh::de::BorshDeserialize; use crate::program_test::tools::clone_keypair; diff --git a/programs/nft-voter/Cargo.toml b/programs/nft-voter/Cargo.toml index 0acf4d30..87440ca1 100644 --- a/programs/nft-voter/Cargo.toml +++ b/programs/nft-voter/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "gpl-nft-voter" -version = "0.2.2" +version = "0.3.0" description = "SPL Governance addin implementing NFT based governance" license = "Apache-2.0" edition = "2018" @@ -15,24 +15,21 @@ no-idl = [] no-log-ix-name = [] cpi = ["no-entrypoint"] default = [] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] [dependencies] arrayref = "0.3.6" -anchor-lang = { version = "0.26.0", features = ["init-if-needed"] } -anchor-spl = { version = "0.26.0", features = ["token"] } +anchor-lang = { version = "0.30.0", features = ["init-if-needed"] } +anchor-spl = { version = "0.30.0", features = ["token"] } itertools = "0.10.2" -mpl-token-metadata = { version = "1.12.0", features = ["no-entrypoint"] } -solana-program = "1.14.16" -spl-governance = { version = "3.1.1", features = ["no-entrypoint"] } -spl-governance-tools= "0.1.3" -spl-token = { version = "3.5", features = [ "no-entrypoint" ] } +mpl-token-metadata = "^4.1.2" +solana-program = "1.18.12" +spl-governance = { version = "4.0.0", features = ["no-entrypoint"] } +spl-governance-tools= "0.1.4" +spl-token = { version = "4.0.0", features = [ "no-entrypoint" ] } -# The explicit versions are required to compile Anchor <= 0.27.0 -# Once upgraded to the higher version this can be removed -winnow = "=0.4.1" -toml_datetime = "=0.6.1" [dev-dependencies] -borsh = "0.9.1" -solana-sdk = "1.14.16" -solana-program-test = "1.14.16" \ No newline at end of file +borsh = "0.10.3" +solana-sdk = "1.18.12" +solana-program-test = "1.18.12" \ No newline at end of file diff --git a/programs/nft-voter/src/instructions/configure_collection.rs b/programs/nft-voter/src/instructions/configure_collection.rs index c217718f..648f098e 100644 --- a/programs/nft-voter/src/instructions/configure_collection.rs +++ b/programs/nft-voter/src/instructions/configure_collection.rs @@ -22,8 +22,8 @@ pub struct ConfigureCollection<'info> { pub registrar: Account<'info, Registrar>, #[account( - address = registrar.realm @ NftVoterError::InvalidRealmForRegistrar, - owner = registrar.governance_program_id + owner = registrar.governance_program_id, + constraint = realm.key() == registrar.realm @ NftVoterError::InvalidRealmForRegistrar, )] /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id pub realm: UncheckedAccount<'info>, diff --git a/programs/nft-voter/src/tools/token_metadata.rs b/programs/nft-voter/src/tools/token_metadata.rs index 05c3d397..66cdead8 100644 --- a/programs/nft-voter/src/tools/token_metadata.rs +++ b/programs/nft-voter/src/tools/token_metadata.rs @@ -1,6 +1,5 @@ use anchor_lang::prelude::*; - -use mpl_token_metadata::state::{Metadata, TokenMetadataAccount}; +use mpl_token_metadata::accounts::Metadata; use crate::error::NftVoterError; @@ -8,12 +7,12 @@ pub fn get_token_metadata(account_info: &AccountInfo) -> Result { if *account_info.owner != mpl_token_metadata::ID { return Err(NftVoterError::InvalidAccountOwner.into()); } - - let metadata = Metadata::from_account_info(account_info)?; + let metadata_data_bytes = &account_info.data.borrow() as &[u8]; + let metadata = Metadata::from_bytes(metadata_data_bytes)?; // I'm not sure if this is needed but try_from_slice_checked in from_account_info // ignores Key::Uninitialized and hence checking for the exact Key match here - if metadata.key != mpl_token_metadata::state::Key::MetadataV1 { + if metadata.key != mpl_token_metadata::types::Key::MetadataV1 { return Err(NftVoterError::InvalidTokenMetadataAccount.into()); } diff --git a/programs/nft-voter/tests/program_test/token_metadata_test.rs b/programs/nft-voter/tests/program_test/token_metadata_test.rs index 093ab891..52ec6179 100644 --- a/programs/nft-voter/tests/program_test/token_metadata_test.rs +++ b/programs/nft-voter/tests/program_test/token_metadata_test.rs @@ -1,9 +1,9 @@ use std::{str::FromStr, sync::Arc}; use anchor_lang::prelude::Pubkey; -use mpl_token_metadata::state::Collection; +use mpl_token_metadata::{types::Collection, types::DataV2}; use solana_program_test::ProgramTest; -use solana_sdk::{signer::Signer, transport::TransportError}; +use solana_sdk::{signer::Signer, system_program, transport::TransportError}; use crate::program_test::program_test_bench::{MintCookie, ProgramTestBench, WalletCookie}; @@ -79,24 +79,34 @@ impl TokenMetadataTest { let coll_symbol = "NFT_C".to_string(); let coll_uri = "URI".to_string(); - let create_coll_metadata_ix = mpl_token_metadata::instruction::create_metadata_accounts_v3( - self.program_id, - coll_metadata_key, - coll_mint_cookie.address, - coll_mint_cookie.mint_authority.pubkey(), - payer.clone(), - update_authority.clone(), - coll_name, - coll_symbol, - coll_uri, - None, - 10, - false, - false, - None, - None, - None, - ); + // instruction args + let args = mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs { + data: DataV2 { + name: coll_name, + symbol: coll_symbol, + uri: coll_uri, + seller_fee_basis_points: 10, + creators: None, + collection: None, + uses: None, + }, + is_mutable: true, + collection_details: None, + }; + + // instruction accounts + let create_coll_metadata_ix_accounts = mpl_token_metadata::instructions::CreateMetadataAccountV3 { + metadata: coll_metadata_key, + mint: coll_mint_cookie.address, + mint_authority: coll_mint_cookie.mint_authority.pubkey(), + payer: payer, + update_authority: (payer, true), + system_program: system_program::ID, + rent: None, + }; + + // creates the instruction + let create_coll_metadata_ix = create_coll_metadata_ix_accounts.instruction(args); self.bench .process_transaction( @@ -114,16 +124,26 @@ impl TokenMetadataTest { let (master_edition_key, _) = Pubkey::find_program_address(master_edition_seeds, &self.program_id); - let create_master_edition_ix = mpl_token_metadata::instruction::create_master_edition_v3( - self.program_id, - master_edition_key, - coll_mint_cookie.address, - update_authority, - coll_mint_cookie.mint_authority.pubkey(), - coll_metadata_key, - payer, - Some(0), - ); + + // instruction args + let args_master_edition_v3 = mpl_token_metadata::instructions::CreateMasterEditionV3InstructionArgs { + max_supply: Some(0), + }; + + // instruction accounts + let create_master_edition_v3_ix_accounts = mpl_token_metadata::instructions::CreateMasterEditionV3 { + edition: master_edition_key, + metadata: coll_metadata_key, + mint: coll_mint_cookie.address, + mint_authority: coll_mint_cookie.mint_authority.pubkey(), + payer: payer, + update_authority: payer, + system_program: system_program::ID, + token_program: self.program_id, + rent: None, + }; + + let create_master_edition_ix = create_master_edition_v3_ix_accounts.instruction(args_master_edition_v3); self.bench .process_transaction( @@ -174,40 +194,50 @@ impl TokenMetadataTest { key: nft_collection_cookie.mint, }; - let create_metadata_ix = mpl_token_metadata::instruction::create_metadata_accounts_v3( - self.program_id, - metadata_key, - mint_cookie.address, - mint_cookie.mint_authority.pubkey(), - self.bench.payer.pubkey(), - self.bench.payer.pubkey(), - name, - symbol, - uri, - None, - 10, - false, - false, - Some(collection), - None, - None, - ); + // instruction args + let args = mpl_token_metadata::instructions::CreateMetadataAccountV3InstructionArgs { + data: DataV2 { + name: name, + symbol: symbol, + uri: uri, + seller_fee_basis_points: 10, + creators: None, + collection: Some(collection), + uses: None, + }, + is_mutable: true, + collection_details: None, + }; + + // instruction accounts + let create_metadata_ix_accounts = mpl_token_metadata::instructions::CreateMetadataAccountV3 { + metadata: metadata_key, + mint: mint_cookie.address, + mint_authority: mint_cookie.mint_authority.pubkey(), + payer: self.bench.payer.pubkey(), + update_authority: (self.bench.payer.pubkey(), true), + system_program: system_program::ID, + rent: None, + }; + + // creates the instruction + let create_metadata_ix = create_metadata_ix_accounts.instruction(args); self.bench .process_transaction(&[create_metadata_ix], Some(&[&mint_cookie.mint_authority])) .await?; if verify_collection { - let verify_collection = mpl_token_metadata::instruction::verify_collection( - self.program_id, - metadata_key, - self.bench.payer.pubkey(), - self.bench.payer.pubkey(), - nft_collection_cookie.mint, - nft_collection_cookie.metadata, - nft_collection_cookie.master_edition, - None, - ); + let verify_collection_accounts = mpl_token_metadata::instructions::VerifyCollection { + metadata: metadata_key, + collection_authority: self.bench.payer.pubkey(), + payer: self.bench.payer.pubkey(), + collection_mint: nft_collection_cookie.mint, + collection: nft_collection_cookie.metadata, + collection_master_edition_account: nft_collection_cookie.master_edition, + collection_authority_record: None, + }; + let verify_collection = verify_collection_accounts.instruction(); self.bench .process_transaction(&[verify_collection], None) diff --git a/programs/realm-voter/Cargo.toml b/programs/realm-voter/Cargo.toml index 7a4f43f0..3468941e 100644 --- a/programs/realm-voter/Cargo.toml +++ b/programs/realm-voter/Cargo.toml @@ -15,17 +15,18 @@ no-idl = [] no-log-ix-name = [] cpi = ["no-entrypoint"] default = [] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] [dependencies] arrayref = "0.3.6" -anchor-lang = { version = "0.26.0" } -anchor-spl = "0.26.0" -solana-program = "1.14.16" -spl-governance = { version = "3.1.1", features = ["no-entrypoint"] } +anchor-lang = { version = "0.30.0" } +anchor-spl = "0.30.0" +solana-program = "1.18.12" +spl-governance = { version = "4.0.0", features = ["no-entrypoint"] } spl-governance-tools= "0.1.3" -spl-token = { version = "3.3", features = [ "no-entrypoint" ] } +spl-token = { version = "4.0.0", features = [ "no-entrypoint" ] } [dev-dependencies] -borsh = "0.9.1" -solana-sdk = "1.14.16" -solana-program-test = "1.14.16" \ No newline at end of file +borsh = "0.10.3" +solana-sdk = "1.18.12" +solana-program-test = "1.18.12" \ No newline at end of file diff --git a/programs/realm-voter/src/instructions/configure_governance_program.rs b/programs/realm-voter/src/instructions/configure_governance_program.rs index 94a7e36f..1c983993 100644 --- a/programs/realm-voter/src/instructions/configure_governance_program.rs +++ b/programs/realm-voter/src/instructions/configure_governance_program.rs @@ -1,9 +1,3 @@ -use anchor_lang::{ - account, - prelude::{Context, Signer}, - Accounts, -}; - use anchor_lang::prelude::*; use spl_governance::state::realm; @@ -19,8 +13,8 @@ pub struct ConfigureGovernanceProgram<'info> { pub registrar: Account<'info, Registrar>, #[account( - address = registrar.realm @ RealmVoterError::InvalidRealmForRegistrar, - owner = registrar.governance_program_id + owner = registrar.governance_program_id, + constraint = realm.key() == registrar.realm @ RealmVoterError::InvalidRealmForRegistrar, )] /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id pub realm: UncheckedAccount<'info>, diff --git a/programs/realm-voter/src/instructions/configure_voter_weights.rs b/programs/realm-voter/src/instructions/configure_voter_weights.rs index 9b8d01d4..914b71c4 100644 --- a/programs/realm-voter/src/instructions/configure_voter_weights.rs +++ b/programs/realm-voter/src/instructions/configure_voter_weights.rs @@ -14,8 +14,8 @@ pub struct ConfigureVoterWeights<'info> { pub registrar: Account<'info, Registrar>, #[account( - address = registrar.realm @ RealmVoterError::InvalidRealmForRegistrar, - owner = registrar.governance_program_id + owner = registrar.governance_program_id, + constraint = realm.key() == registrar.realm @ RealmVoterError::InvalidRealmForRegistrar, )] /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id pub realm: UncheckedAccount<'info>, diff --git a/programs/realm-voter/src/state/max_voter_weight_record.rs b/programs/realm-voter/src/state/max_voter_weight_record.rs index 66ac8da7..e56987d5 100644 --- a/programs/realm-voter/src/state/max_voter_weight_record.rs +++ b/programs/realm-voter/src/state/max_voter_weight_record.rs @@ -1,6 +1,5 @@ use crate::id; use crate::tools::anchor::DISCRIMINATOR_SIZE; -use anchor_lang::prelude::Pubkey; use anchor_lang::prelude::*; use solana_program::pubkey::PUBKEY_BYTES; diff --git a/programs/realm-voter/src/state/registrar.rs b/programs/realm-voter/src/state/registrar.rs index 8ff3fa20..2d4b6220 100644 --- a/programs/realm-voter/src/state/registrar.rs +++ b/programs/realm-voter/src/state/registrar.rs @@ -1,10 +1,9 @@ use crate::{id, state::GovernanceProgramConfig, tools::anchor::DISCRIMINATOR_SIZE}; -use anchor_lang::prelude::*; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; +use anchor_lang::prelude::{borsh::BorshSchema, *}; use solana_program::pubkey::PUBKEY_BYTES; /// Enum defining collection item change type -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] +#[derive(Clone, Debug, PartialEq, AnchorDeserialize, AnchorSerialize, BorshSchema)] pub enum CollectionItemChangeType { /// Update item in the collection if it already exists and Insert the item if it doesn't Upsert, diff --git a/programs/realm-voter/tests/program_test/program_test_bench.rs b/programs/realm-voter/tests/program_test/program_test_bench.rs index cd65942a..c9f0ff1c 100644 --- a/programs/realm-voter/tests/program_test/program_test_bench.rs +++ b/programs/realm-voter/tests/program_test/program_test_bench.rs @@ -5,21 +5,13 @@ use anchor_lang::{ AccountDeserialize, }; -use solana_program::{borsh::try_from_slice_unchecked, system_program}; +use borsh::BorshDeserialize; +use solana_program::system_program; use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; use solana_sdk::{ - account::{Account, ReadableAccount}, - instruction::Instruction, - program_pack::Pack, - signature::Keypair, - signer::Signer, - system_instruction, - transaction::Transaction, - transport::TransportError, + account::{Account, ReadableAccount}, borsh0_10::{try_from_slice_unchecked}, instruction::Instruction, program_pack::Pack, signature::Keypair, signer::Signer, system_instruction, transaction::Transaction, transport::TransportError }; -use borsh::BorshDeserialize; - use crate::program_test::tools::clone_keypair; pub struct MintCookie { diff --git a/programs/token-voter/Cargo.toml b/programs/token-voter/Cargo.toml new file mode 100644 index 00000000..096e19ad --- /dev/null +++ b/programs/token-voter/Cargo.toml @@ -0,0 +1,42 @@ +[package] +name = "token-voter" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[lib] +crate-type = ["cdylib", "lib"] +name = "token_voter" + +[features] +no-entrypoint = [] +no-idl = [] +no-log-ix-name = [] +cpi = ["no-entrypoint"] +default = [] +idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] + +[dependencies] +anchor-lang = { version = "0.30.0", features = ["init-if-needed"] } +anchor-spl = "0.30.0" +arrayref = "0.3.7" +solana-program = "1.18.12" +# spl-governance = { version = "4.0.0", features = ["no-entrypoint"] } +spl-governance = { git = "https://github.com/crypt0miester/solana-program-library.git", branch = "gib-bounty-jlFb5", default-features = false, features = ["no-entrypoint"] } +spl-governance-tools = "0.1.4" +spl-token = { version = "3.5", features = [ "no-entrypoint" ] } +spl-token-2022 = { version = "3.0.2", features = [ "no-entrypoint" ] } +spl-transfer-hook-interface = { version = "0.6.3" } +ahash = "=0.8.7" +static_assertions = "1.1" +spl-governance-addin-api = "0.1.4" + + +[dev-dependencies] +borsh = "0.10.3" +spl-associated-token-account = { version = "^3.0.2", features = ["no-entrypoint"] } +solana-sdk = "1.18.12" +solana-program-test = "1.18.12" +log = "0.4.14" +env_logger = "0.9.0" +spl-token-client = "0.10.0" diff --git a/programs/token-voter/Xargo.toml b/programs/token-voter/Xargo.toml new file mode 100644 index 00000000..475fb71e --- /dev/null +++ b/programs/token-voter/Xargo.toml @@ -0,0 +1,2 @@ +[target.bpfel-unknown-unknown.dependencies.std] +features = [] diff --git a/programs/token-voter/src/error.rs b/programs/token-voter/src/error.rs new file mode 100644 index 00000000..a7bdc69d --- /dev/null +++ b/programs/token-voter/src/error.rs @@ -0,0 +1,190 @@ +use anchor_lang::prelude::*; + +#[error_code] +pub enum TokenVoterError { + #[msg("Invalid Realm Authority")] + InvalidRealmAuthority, + + #[msg("Invalid Realm for Registrar")] + InvalidRealmForRegistrar, + + #[msg("Invalid Collection Size")] + InvalidCollectionSize, + + #[msg("Invalid MaxVoterWeightRecord Realm")] + InvalidMaxVoterWeightRecordRealm, + + #[msg("Invalid MaxVoterWeightRecord Mint")] + InvalidMaxVoterWeightRecordMint, + + #[msg("CastVote Is Not Allowed")] + CastVoteIsNotAllowed, + + #[msg("Invalid VoterWeightRecord Realm")] + InvalidVoterWeightRecordRealm, + + #[msg("Invalid VoterWeightRecord Mint")] + InvalidVoterWeightRecordMint, + + #[msg("Invalid TokenOwner for VoterWeightRecord")] + InvalidTokenOwnerForVoterWeightRecord, + + #[msg("Collection must be verified")] + CollectionMustBeVerified, + + #[msg("Voter does not own NFT")] + VoterDoesNotOwnNft, + + #[msg("Collection not found")] + CollectionNotFound, + + #[msg("Missing Metadata collection")] + MissingMetadataCollection, + + #[msg("Token Metadata doesn't match")] + TokenMetadataDoesNotMatch, + + #[msg("Invalid account owner")] + InvalidAccountOwner, + + #[msg("Invalid token metadata account")] + InvalidTokenMetadataAccount, + + #[msg("Duplicated NFT detected")] + DuplicatedNftDetected, + + #[msg("Invalid NFT amount")] + InvalidNftAmount, + + #[msg("NFT already voted")] + NftAlreadyVoted, + + #[msg("Invalid Proposal for NftVoteRecord")] + InvalidProposalForNftVoteRecord, + + #[msg("Invalid TokenOwner for NftVoteRecord")] + InvalidTokenOwnerForNftVoteRecord, + + #[msg("VoteRecord must be withdrawn")] + VoteRecordMustBeWithdrawn, + + #[msg("Invalid VoteRecord for NftVoteRecord")] + InvalidVoteRecordForNftVoteRecord, + + #[msg("VoterWeightRecord must be expired")] + VoterWeightRecordMustBeExpired, + + #[msg("Mathematical Overflow")] + Overflow, + + /// Invalid Token account owner + #[msg("Invalid Token account owner")] + SplTokenAccountWithInvalidOwner, + + /// Invalid Mint account owner + #[msg("Invalid Mint account owner")] + SplTokenMintWithInvalidOwner, + + /// Token Account is not initialized + #[msg("Token Account is not initialized")] + SplTokenAccountNotInitialized, + + /// Token Account doesn't exist + #[msg("Token Account doesn't exist")] + SplTokenAccountDoesNotExist, + + /// Token account data is invalid + #[msg("Token account data is invalid")] + SplTokenInvalidTokenAccountData, + + /// Token mint account data is invalid + #[msg("Token mint account data is invalid")] + SplTokenInvalidMintAccountData, + + /// Token Mint is not initialized + #[msg("Token Mint account is not initialized")] + SplTokenMintNotInitialized, + + /// Token Mint account doesn't exist + #[msg("Token Mint account doesn't exist")] + SplTokenMintDoesNotExist, + + /// Current mint authority must sign transaction + #[msg("Current mint authority must sign transaction")] + MintAuthorityMustSign, + + /// Invalid mint authority + #[msg("Invalid mint authority")] + InvalidMintAuthority, + + /// Mint has no authority + #[msg("Mint has no authority")] + MintHasNoAuthority, + + /// Invalid token owner + #[msg("Invalid token owner")] + InvalidTokenOwner, + + /// Current token owner must sign transaction + #[msg("Current token owner must sign transaction")] + TokenOwnerMustSign, + + /// Account data is empty or invalid + #[msg("Account Data is empty or invalid")] + InvalidAccountData, + + /// Invalid Governing Token Mint + #[msg("Invalid Governing Token Mint")] + InvalidGoverningTokenMint, + + /// Math Overflow in VoterWeight + #[msg("Math Overflow in VoterWeight")] + VoterWeightOverflow, + + #[msg("Invalid Proposal for NftVoteRecord")] + InvalidProposalForTokenVoteRecord, + + #[msg("Invalid TokenOwner for NftVoteRecord")] + InvalidTokenOwnerForTokenVoteRecord, + + #[msg("Mint Not Found in Mint Configs")] + MintNotFound, + + #[msg("Governing TokenOwner must match")] + GoverningTokenOwnerMustMatch, + + #[msg("Invalid Token Owner Records")] + InvalidTokenOwnerRecord, + + #[msg("Index is out of Deposit Entry bounds")] + OutOfBoundsDepositEntryIndex, + + #[msg("No Cpi Allowed")] + ForbiddenCpi, + + #[msg("Voting Tokens are not withdrawn")] + VotingTokenNonZero, + + #[msg("Vault Tokens are not withdrawn")] + VaultTokenNonZero, + + #[msg("Invalid Voter Token Authority")] + InvalidAuthority, + + /// Token Amount Overflow + #[msg("Math Overflow in Token Amount")] + TokenAmountOverflow, + + /// Withdrawal in the same slot. + #[msg("Cannot Withdraw in the same slot")] + CannotWithdraw, + + #[msg("Voting Mint has Incorrect Index")] + VotingMintConfiguredWithDifferentIndex, + + #[msg("Voting Mint index is already in use")] + VotingMintConfigIndexAlreadyInUse, + + #[msg("Index is out of Voting Mint Config bounds")] + OutOfBoundsVotingMintConfigIndex, +} diff --git a/programs/token-voter/src/governance.rs b/programs/token-voter/src/governance.rs new file mode 100644 index 00000000..2e775ae6 --- /dev/null +++ b/programs/token-voter/src/governance.rs @@ -0,0 +1,217 @@ +/// A macro is exposed so that we can embed the program ID. +#[macro_export] +macro_rules! vote_weight_record { + ($id:expr) => { + /// Anchor wrapper for the SPL governance program's VoterWeightRecord type. + #[derive(Clone)] + pub struct VoterWeightRecord(spl_governance_addin_api::voter_weight::VoterWeightRecord); + + impl VoterWeightRecord { + pub fn get_space() -> usize { + 8 + 32 * 4 + 8 + 1 + 8 + 1 + 1 + 1 + 8 + } + + pub fn new( + realm: Pubkey, + governing_token_mint: Pubkey, + governing_token_owner: Pubkey, + voter_weight: u64, + voter_weight_expiry: Option, + weight_action: Option, + weight_action_target: Option, + ) -> Self { + let vwr = spl_governance_addin_api::voter_weight::VoterWeightRecord { + account_discriminator: spl_governance_addin_api::voter_weight::VoterWeightRecord::ACCOUNT_DISCRIMINATOR, + realm, + governing_token_mint, + governing_token_owner, + voter_weight, + voter_weight_expiry, + weight_action, + weight_action_target, + reserved: [0; 8], + }; + VoterWeightRecord(vwr) + } + } + + impl anchor_lang::AccountDeserialize for VoterWeightRecord { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data = buf; + let vwr: spl_governance_addin_api::voter_weight::VoterWeightRecord = + anchor_lang::AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + if !solana_program::program_pack::IsInitialized::is_initialized(&vwr) { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + Ok(VoterWeightRecord(vwr)) + } + + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data = buf; + let vwr: spl_governance_addin_api::voter_weight::VoterWeightRecord = + anchor_lang::AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + Ok(VoterWeightRecord(vwr)) + } + } + + impl anchor_lang::AccountSerialize for VoterWeightRecord { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + anchor_lang::AnchorSerialize::serialize(&self.0, writer) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + Ok(()) + } + } + + impl anchor_lang::Owner for VoterWeightRecord { + fn owner() -> Pubkey { + $id + } + } + + impl std::ops::Deref for VoterWeightRecord { + type Target = spl_governance_addin_api::voter_weight::VoterWeightRecord; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for VoterWeightRecord { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + #[cfg(feature = "idl-build")] + impl anchor_lang::IdlBuild for VoterWeightRecord {} + + #[cfg(feature = "idl-build")] + impl anchor_lang::Discriminator for VoterWeightRecord { + const DISCRIMINATOR: [u8; 8] = [0; 8]; + fn discriminator() -> [u8; 8] { + spl_governance_addin_api::voter_weight::VoterWeightRecord::ACCOUNT_DISCRIMINATOR + } + } + }; +} + + +/// A macro is exposed so that we can embed the program ID. +#[macro_export] +macro_rules! max_voter_weight_record { + ($id:expr) => { + /// Anchor wrapper for the SPL governance program's MaxVoterWeightRecord type. + #[derive(Clone)] + pub struct MaxVoterWeightRecord(spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord); + + impl MaxVoterWeightRecord { + pub fn get_space() -> usize { + 8 + 32 * 2 + 8 + 1 + 8 + 8 + } + + pub fn new( + realm: Pubkey, + governing_token_mint: Pubkey, + max_voter_weight: u64, + max_voter_weight_expiry: Option, + ) -> Self { + let mvwr = spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord { + account_discriminator: spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord::ACCOUNT_DISCRIMINATOR, + realm, + governing_token_mint, + max_voter_weight, + max_voter_weight_expiry, + reserved: [0; 8], + }; + MaxVoterWeightRecord(mvwr) + } + + /// Returns MaxVoterWeightRecord PDA seeds + pub fn get_max_voter_weight_record_seeds<'a>( + realm: &'a Pubkey, + governing_token_mint: &'a Pubkey, + ) -> [&'a [u8]; 3] { + [ + b"max-voter-weight-record", + realm.as_ref(), + governing_token_mint.as_ref(), + ] + } + + /// Returns MaxVoterWeightRecord PDA address + pub fn get_max_voter_weight_record_address( + realm: &Pubkey, + governing_token_mint: &Pubkey, + ) -> Pubkey { + Pubkey::find_program_address( + &Self::get_max_voter_weight_record_seeds(realm, governing_token_mint), + &id(), + ) + .0 + } + } + + + impl anchor_lang::AccountDeserialize for MaxVoterWeightRecord { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data = buf; + let mvwr: spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord = + anchor_lang::AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + if !solana_program::program_pack::IsInitialized::is_initialized(&mvwr) { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + Ok(MaxVoterWeightRecord(mvwr)) + } + + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data = buf; + let mvwr: spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord = + anchor_lang::AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?; + Ok(MaxVoterWeightRecord(mvwr)) + } + } + + impl anchor_lang::AccountSerialize for MaxVoterWeightRecord { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + anchor_lang::AnchorSerialize::serialize(&self.0, writer) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotSerialize)?; + Ok(()) + } + } + + impl anchor_lang::Owner for MaxVoterWeightRecord { + fn owner() -> Pubkey { + $id + } + } + + impl std::ops::Deref for MaxVoterWeightRecord { + type Target = spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl std::ops::DerefMut for MaxVoterWeightRecord { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.0 + } + } + + #[cfg(feature = "idl-build")] + impl anchor_lang::IdlBuild for MaxVoterWeightRecord {} + + #[cfg(feature = "idl-build")] + impl anchor_lang::Discriminator for MaxVoterWeightRecord { + const DISCRIMINATOR: [u8; 8] = [0; 8]; + fn discriminator() -> [u8; 8] { + spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord::ACCOUNT_DISCRIMINATOR + } + } + }; +} diff --git a/programs/token-voter/src/instructions/close_voter.rs b/programs/token-voter/src/instructions/close_voter.rs new file mode 100644 index 00000000..cad3af3a --- /dev/null +++ b/programs/token-voter/src/instructions/close_voter.rs @@ -0,0 +1,79 @@ +use { + crate::{error::*, state::*, tools::spl_token::get_spl_token_amount}, + anchor_lang::prelude::*, + anchor_spl::{ + token_2022::{self, CloseAccount}, + token_interface::TokenInterface, + }, + spl_governance::tools::spl_token::get_spl_token_owner, +}; + +// Remaining accounts must be all the token accounts owned by voter account they want to close, +// they should be writable so that they can be closed and sol rented +// would be transfered to sol_destination +#[derive(Accounts)] +pub struct CloseVoter<'info> { + pub registrar: Box>, + + #[account( + mut, + seeds = [voter.registrar.as_ref(), b"voter".as_ref(), voter_authority.key().as_ref()], + bump = voter.voter_bump, + close = sol_destination + )] + pub voter: Box>, + + pub voter_authority: Signer<'info>, + + /// CHECK: Destination may be any address. + #[account(mut)] + pub sol_destination: UncheckedAccount<'info>, + + pub token_program: Interface<'info, TokenInterface>, +} + +/// Closes the voter account (Optionally, also token vaults, as part of remaining_accounts), +/// allowing one to retrieve rent exemption SOL. +/// Only accounts with no remaining deposits can be closed. +pub fn close_voter<'key, 'accounts, 'remaining, 'info>( + ctx: Context<'key, 'accounts, 'remaining, 'info, CloseVoter<'info>>, +) -> Result<()> { + let voter = &ctx.accounts.voter; + let voter_authority = &ctx.accounts.voter_authority; + let amount = voter.deposits.iter().fold(0u64, |sum, d| { + sum.checked_add(d.amount_deposited_native).unwrap() + }); + require_eq!(amount, 0, TokenVoterError::VotingTokenNonZero); + let voter_authority_key = voter_authority.key(); + let voter_seeds = voter_seeds!(voter, voter_authority_key); + + for account in ctx.remaining_accounts { + let account_clone = &account.clone(); + let token_owner = get_spl_token_owner(account_clone)?; + let token_amount = get_spl_token_amount(account_clone)?; + + require_keys_eq!( + token_owner, + ctx.accounts.voter.key(), + TokenVoterError::InvalidAuthority + ); + require_eq!(token_amount, 0, TokenVoterError::VaultTokenNonZero); + + let cpi_accounts = CloseAccount { + account: account.to_account_info(), + destination: ctx.accounts.sol_destination.to_account_info(), + authority: ctx.accounts.voter.to_account_info(), + }; + + let cpi_program = ctx.accounts.token_program.to_account_info(); + token_2022::close_account(CpiContext::new_with_signer( + cpi_program, + cpi_accounts, + &[voter_seeds], + ))?; + + account.exit(ctx.program_id)?; + } + + Ok(()) +} diff --git a/programs/token-voter/src/instructions/configure_mint_config.rs b/programs/token-voter/src/instructions/configure_mint_config.rs new file mode 100644 index 00000000..e13e51b1 --- /dev/null +++ b/programs/token-voter/src/instructions/configure_mint_config.rs @@ -0,0 +1,111 @@ +use { + crate::{error::*, state::*}, + anchor_lang::prelude::*, + anchor_spl::token_interface::Mint, + spl_governance::state::realm, +}; + +/// Creates or updates configuration for spl-governance program instances to define which spl-governance instances can be used to grant governance power +#[derive(Accounts)] +pub struct ConfigureVotingMintConfig<'info> { + /// Registrar which we configure the provided spl-governance instance for + #[account(mut)] + pub registrar: Account<'info, Registrar>, + + #[account( + owner = registrar.governance_program_id, + constraint = realm.key() == registrar.realm @ TokenVoterError::InvalidRealmForRegistrar, + )] + /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id + // Validated below + pub realm: UncheckedAccount<'info>, + + /// Authority of the Realm must sign the transaction and must match realm.authority + pub realm_authority: Signer<'info>, + + /// Tokens of this mint will be included in the Mint Configs + pub mint: InterfaceAccount<'info, Mint>, + + #[account( + mut, + constraint = max_voter_weight_record.realm == registrar.realm + @ TokenVoterError::InvalidMaxVoterWeightRecordRealm, + + constraint = max_voter_weight_record.governing_token_mint == registrar.governing_token_mint + @ TokenVoterError::InvalidMaxVoterWeightRecordMint, + )] + pub max_voter_weight_record: Account<'info, MaxVoterWeightRecord>, + + /// CHECK: It can be any instance of spl-governance and there is no way to validate it's a correct instance + /// The onus is entirely on the caller side to ensure the provided instance is correct + /// In future versions once we have the registry of spl-governance instances it could be validated against the registry + #[account(executable)] + pub governance_program_id: UncheckedAccount<'info>, +} + +pub fn configure_mint_config( + ctx: Context, + digit_shift: i8, +) -> Result<()> { + let registrar = &mut ctx.accounts.registrar; + let mint = &ctx.accounts.mint; + let max_voter_weight_record = &mut ctx.accounts.max_voter_weight_record; + + let realm = realm::get_realm_data_for_governing_token_mint( + ®istrar.governance_program_id, + &ctx.accounts.realm, + ®istrar.governing_token_mint, + )?; + + require_eq!( + realm.authority.unwrap(), + ctx.accounts.realm_authority.key(), + TokenVoterError::InvalidRealmAuthority + ); + + let token_supply = mint.supply; + let supply_with_digit_shift = digit_shift_native(digit_shift, token_supply)?; + let voting_mint_config = VotingMintConfig { + mint: mint.key(), + digit_shift, + reserved1: [0; 63], + }; + + let mint_config_idx = registrar + .voting_mint_configs + .iter() + .position(|vmc| vmc.mint == mint.key()); + + if let Some(mint_config_idx) = mint_config_idx { + registrar.voting_mint_configs[mint_config_idx] = voting_mint_config; + } else { + // Note: In the current runtime version push() would throw an error if we exceed + // max_mints specified when the Registrar was created + registrar.voting_mint_configs.push(voting_mint_config); + } + + // Update MaxVoterWeightRecord.max_voter_weight + max_voter_weight_record.max_voter_weight = max_voter_weight_record + .max_voter_weight + .checked_add(supply_with_digit_shift) + .ok_or_else(|| error!(TokenVoterError::VoterWeightOverflow))?; + + max_voter_weight_record.max_voter_weight_expiry = None; + + Ok(()) +} + +/// Converts an amount in this voting mints's native currency +/// to the base vote weight +/// by applying the digit_shift factor. +pub fn digit_shift_native(digit_shift: i8, amount_native: u64) -> Result { + let compute = || -> Option { + let val = if digit_shift < 0 { + (amount_native as u128).checked_div(10u128.pow((-digit_shift) as u32))? + } else { + (amount_native as u128).checked_mul(10u128.pow(digit_shift as u32))? + }; + u64::try_from(val).ok() + }; + compute().ok_or_else(|| error!(TokenVoterError::VoterWeightOverflow)) +} diff --git a/programs/token-voter/src/instructions/create_max_voter_weight_record.rs b/programs/token-voter/src/instructions/create_max_voter_weight_record.rs new file mode 100644 index 00000000..fdbf011a --- /dev/null +++ b/programs/token-voter/src/instructions/create_max_voter_weight_record.rs @@ -0,0 +1,60 @@ +use { + crate::state::*, + anchor_lang::prelude::*, anchor_spl::token_interface::Mint, spl_governance::state::realm, +}; + +/// Creates MaxVoterWeightRecord used by spl-governance +/// This instruction should only be executed once per realm/governing_token_mint to create the account +#[derive(Accounts)] +pub struct CreateMaxVoterWeightRecord<'info> { + // The Registrar the MaxVoterWeightRecord account belongs to + pub registrar: Account<'info, Registrar>, + + #[account( + init, + seeds = [ b"max-voter-weight-record".as_ref(), + registrar.realm.key().as_ref(), + registrar.governing_token_mint.key().as_ref()], + bump, + payer = payer, + space = MaxVoterWeightRecord::get_space() + )] + pub max_voter_weight_record: Account<'info, MaxVoterWeightRecord>, + + /// The program id of the spl-governance program the realm belongs to + /// CHECK: Can be any instance of spl-governance and it's not known at the compilation time + #[account(executable)] + pub governance_program_id: UncheckedAccount<'info>, + + #[account(owner = governance_program_id.key())] + /// CHECK: Owned by spl-governance instance specified in governance_program_id + pub realm: UncheckedAccount<'info>, + + /// Either the realm community mint or the council mint. + pub realm_governing_token_mint: InterfaceAccount<'info, Mint>, + + #[account(mut)] + pub payer: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +pub fn create_max_voter_weight_record(ctx: Context) -> Result<()> { + // Deserialize the Realm to validate it + let _realm = realm::get_realm_data_for_governing_token_mint( + &ctx.accounts.governance_program_id.key(), + &ctx.accounts.realm, + &ctx.accounts.realm_governing_token_mint.key(), + )?; + + let max_voter_weight_record = &mut ctx.accounts.max_voter_weight_record; + let registrar = &ctx.accounts.registrar; + max_voter_weight_record.account_discriminator = spl_governance_addin_api::max_voter_weight::MaxVoterWeightRecord::ACCOUNT_DISCRIMINATOR; + max_voter_weight_record.realm = registrar.realm; + max_voter_weight_record.governing_token_mint = registrar.governing_token_mint; + + // Set expiry to expired + max_voter_weight_record.max_voter_weight_expiry = Some(0); + + Ok(()) +} diff --git a/programs/token-voter/src/instructions/create_registrar.rs b/programs/token-voter/src/instructions/create_registrar.rs new file mode 100644 index 00000000..452a6426 --- /dev/null +++ b/programs/token-voter/src/instructions/create_registrar.rs @@ -0,0 +1,81 @@ +use { + crate::{error::*, state::*}, + anchor_lang::prelude::*, + anchor_spl::token_interface::Mint, + spl_governance::state::realm, +}; + +/// Creates Registrar storing Realm Voter configuration for spl-governance Realm +/// This instruction should only be executed once per realm/governing_token_mint to create the account +#[derive(Accounts)] +#[instruction(max_mints: u8)] +pub struct CreateRegistrar<'info> { + /// The Realm Voter Registrar + /// There can only be a single registrar per governance Realm and governing mint of the Realm + #[account( + init, + seeds = [b"registrar".as_ref(), realm.key().as_ref(), governing_token_mint.key().as_ref()], + bump, + payer = payer, + space = Registrar::get_space(max_mints) + )] + pub registrar: Account<'info, Registrar>, + + /// The program id of the spl-governance program the realm belongs to + /// CHECK: Can be any instance of spl-governance and it's not known at the compilation time + #[account(executable)] + pub governance_program_id: UncheckedAccount<'info>, + + /// An spl-governance Realm + /// + /// Realm is validated in the instruction: + /// - Realm is owned by the governance_program_id + /// - governing_token_mint must be the community or council mint + /// - realm_authority is realm.authority + /// CHECK: Owned by spl-governance instance specified in governance_program_id + #[account(owner = governance_program_id.key())] + pub realm: UncheckedAccount<'info>, + + /// Either the realm community mint or the council mint. + /// It must match Realm.community_mint or Realm.config.council_mint + /// + /// Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity + /// for the voting population and the tokens of that are no longer used + pub governing_token_mint: InterfaceAccount<'info, Mint>, + + /// realm_authority must sign and match Realm.authority + pub realm_authority: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +/// Creates a new Registrar which stores Realms voter configuration for the given Realm +/// +/// max_mints is used to allocate account size for the maximum number of configured mint instances +pub fn create_registrar(ctx: Context, max_mints: u8) -> Result<()> { + let registrar = &mut ctx.accounts.registrar; + registrar.governance_program_id = ctx.accounts.governance_program_id.key(); + registrar.realm = ctx.accounts.realm.key(); + registrar.governing_token_mint = ctx.accounts.governing_token_mint.key(); + registrar.voting_mint_configs = vec![]; + registrar.max_mints = max_mints; + + // Verify that realm_authority is the expected authority of the Realm + // and that the mint matches one of the realm mints too + let realm = realm::get_realm_data_for_governing_token_mint( + ®istrar.governance_program_id, + &ctx.accounts.realm, + ®istrar.governing_token_mint, + )?; + + require_eq!( + realm.authority.unwrap(), + ctx.accounts.realm_authority.key(), + TokenVoterError::InvalidRealmAuthority + ); + + Ok(()) +} diff --git a/programs/token-voter/src/instructions/create_voter_weight_record.rs b/programs/token-voter/src/instructions/create_voter_weight_record.rs new file mode 100644 index 00000000..6cda2956 --- /dev/null +++ b/programs/token-voter/src/instructions/create_voter_weight_record.rs @@ -0,0 +1,80 @@ +use { + crate::{error::*, state::*}, + anchor_lang::prelude::*, + anchor_lang::solana_program::sysvar::instructions as tx_instructions, +}; + +/// Creates VoterWeightRecord used by spl-gov +/// This instruction should only be executed once per realm/governing_token_mint/governing_token_owner +/// to create the account +#[derive(Accounts)] +pub struct CreateVoterWeightRecord<'info> { + // The Registrar the VoterWeightRecord account belongs to + pub registrar: Box>, + + #[account( + init, + seeds = [registrar.key().as_ref(), b"voter".as_ref(), voter_authority.key().as_ref()], + bump, + payer = voter_authority, + space = Voter::get_space(registrar.max_mints), + )] + pub voter: Box>, + + #[account( + init, + seeds = [registrar.key().as_ref(), b"voter-weight-record".as_ref(), voter_authority.key().as_ref()], + bump, + payer = voter_authority, + space = VoterWeightRecord::get_space() + )] + pub voter_weight_record: Box>, + + #[account(mut)] + pub voter_authority: Signer<'info>, + + pub system_program: Program<'info, System>, + + /// CHECK: Address constraint is set + #[account(address = tx_instructions::ID)] + pub instructions: UncheckedAccount<'info>, +} + +pub fn create_voter_weight_record( + ctx: Context, +) -> Result<()> { + // Forbid creating voter accounts from CPI. The goal is to make automation + // impossible that weakens some of the limitations intentionally imposed on + // tokens. + { + let ixns = ctx.accounts.instructions.to_account_info(); + let current_index = tx_instructions::load_current_index_checked(&ixns)? as usize; + let current_ixn = tx_instructions::load_instruction_at_checked(current_index, &ixns)?; + require_keys_eq!( + current_ixn.program_id, + *ctx.program_id, + TokenVoterError::ForbiddenCpi + ); + } + + let voter = &mut ctx.accounts.voter; + let voter_authority = &ctx.accounts.voter_authority; + let registrar = &ctx.accounts.registrar; + + voter.voter_bump = ctx.bumps.voter; + voter.voter_weight_record_bump = ctx.bumps.voter_weight_record; + voter.voter_authority = voter_authority.key(); + voter.registrar = registrar.key(); + voter.deposits = vec![]; + + let voter_weight_record = &mut ctx.accounts.voter_weight_record; + + voter_weight_record.account_discriminator = spl_governance_addin_api::voter_weight::VoterWeightRecord::ACCOUNT_DISCRIMINATOR; + voter_weight_record.realm = registrar.realm.key(); + voter_weight_record.governing_token_mint = registrar.governing_token_mint.key(); + voter_weight_record.governing_token_owner = voter_authority.key(); + + // Set expiry to expired + voter_weight_record.voter_weight_expiry = Some(0); + Ok(()) +} diff --git a/programs/token-voter/src/instructions/deposit.rs b/programs/token-voter/src/instructions/deposit.rs new file mode 100644 index 00000000..72ce0004 --- /dev/null +++ b/programs/token-voter/src/instructions/deposit.rs @@ -0,0 +1,170 @@ +use { + crate::{error::*, state::*, tools::spl_token::transfer_checked_spl_tokens}, + anchor_lang::{prelude::*, solana_program::sysvar::instructions as tx_instructions}, + anchor_spl::{associated_token::AssociatedToken, token_interface::{Mint, TokenAccount, TokenInterface}}, spl_governance::state::token_owner_record, +}; + +#[derive(Accounts)] +pub struct Deposit<'info> { + pub registrar: Box>, + + #[account( + mut, + seeds = [registrar.key().as_ref(), b"voter".as_ref(), deposit_authority.key().as_ref()], + bump = voter.voter_bump, + has_one = registrar)] + pub voter: Box>, + + #[account( + init_if_needed, + associated_token::authority = voter, + associated_token::mint = mint, + associated_token::token_program = token_program, + payer = deposit_authority + )] + pub vault: Box>, + + #[account( + mut, + seeds = [registrar.key().as_ref(), b"voter-weight-record".as_ref(), deposit_authority.key().as_ref()], + bump = voter.voter_weight_record_bump, + constraint = voter_weight_record.realm == registrar.realm + @ TokenVoterError::InvalidVoterWeightRecordRealm, + + constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint + @ TokenVoterError::InvalidVoterWeightRecordMint, + )] + pub voter_weight_record: Box>, + + /// TokenOwnerRecord for any of the configured spl-governance instances + /// CHECK: Owned by any of the spl-governance instances specified in registrar.governance_program_configs + pub token_owner_record: UncheckedAccount<'info>, + + /// Tokens of this mint must be included in the Voting Mint Configs + pub mint: Box>, + + #[account( + mut, + associated_token::authority = deposit_authority, + associated_token::mint = mint, + associated_token::token_program = token_program, + )] + pub deposit_token: Box>, + + #[account(mut)] + pub deposit_authority: Signer<'info>, + + pub token_program: Interface<'info, TokenInterface>, + pub system_program: Program<'info, System>, + pub associated_token_program: Program<'info, AssociatedToken>, + /// CHECK: Address constraint is set + #[account(address = tx_instructions::ID)] + pub instructions: UncheckedAccount<'info>, +} + + +/// Adds tokens to a deposit entry. +/// +/// Tokens will be transfered from deposit_token to vault using the deposit_authority. +/// +/// The deposit entry must have been initialized with create_deposit_entry. +/// +/// `deposit_entry_index`: Index of the deposit entry. +/// `amount`: Number of native tokens to transfer. +pub fn deposit<'key, 'accounts, 'remaining, 'info>( + ctx: Context<'key, 'accounts, 'remaining, 'info, Deposit<'info>>, + deposit_entry_index: u8, + amount: u64, +) -> Result<()> { + if amount == 0 { + return Ok(()); + } + + // Deposit tokens into the vault and increase the amount too. + // fail early if amount does not exist. + { + transfer_checked_spl_tokens( + &ctx.accounts.deposit_token.to_account_info(), + &ctx.accounts.vault.to_account_info(), + &ctx.accounts.deposit_authority.to_account_info(), + amount, + &ctx.accounts.token_program.to_account_info(), + &ctx.accounts.mint.to_account_info(), + ctx.remaining_accounts, + )?; + } + + let registrar = &ctx.accounts.registrar; + let voter = &mut ctx.accounts.voter; + + let d_entry = match voter.active_deposit_mut(deposit_entry_index) { + Ok(d_entry) => { + Some(d_entry) + }, + Err(_) => { + None + } + }; + + // Get the exchange rate entry associated with this deposit. + // fails if registrat.voting_mint_configs does not exist. + let mint_idx = registrar.voting_mint_config_index(ctx.accounts.deposit_token.mint)?; + // deposit_entry_index + require_eq!( + mint_idx, + deposit_entry_index as usize, + TokenVoterError::OutOfBoundsDepositEntryIndex + ); + + let clock = Clock::get()?; + let current_slot_hash = clock.slot; + + match d_entry { + Some(d_entry) => { + + d_entry.amount_deposited_native = d_entry.amount_deposited_native.checked_add(amount).unwrap(); + + // Deposit is only valid as of the current slot + d_entry.deposit_slot_hash = current_slot_hash; + d_entry.is_used = true; + }, + None => { + let deposit_entry = DepositEntry { + deposit_slot_hash: current_slot_hash, + amount_deposited_native: amount, + voting_mint_config_idx: mint_idx as u8, + is_used: true, + reserved: [0;38] + }; + voter.deposits.push(deposit_entry); + } + } + + + let voter_weight_record = &mut ctx.accounts.voter_weight_record; + + let governance_program_id = ctx.accounts.token_owner_record.owner; + + let token_owner_record = token_owner_record::get_token_owner_record_data( + governance_program_id, + &ctx.accounts.token_owner_record, + )?; + + // Ensure VoterWeightRecord and TokenOwnerRecord are for the same governing_token_owner + require_eq!( + token_owner_record.governing_token_owner, + voter_weight_record.governing_token_owner, + TokenVoterError::GoverningTokenOwnerMustMatch + ); + + // Setup voter_weight + voter_weight_record.voter_weight = voter.weight(registrar)?; + + // Record is only valid as of the current slot + voter_weight_record.voter_weight_expiry = Some(Clock::get()?.slot); + + // Set action and target to None to indicate the weight is valid for any action and target + voter_weight_record.weight_action = None; + voter_weight_record.weight_action_target = None; + Ok(()) +} diff --git a/programs/token-voter/src/instructions/mod.rs b/programs/token-voter/src/instructions/mod.rs new file mode 100644 index 00000000..e5766ab3 --- /dev/null +++ b/programs/token-voter/src/instructions/mod.rs @@ -0,0 +1,20 @@ +pub use configure_mint_config::*; +mod configure_mint_config; + +pub use create_registrar::*; +mod create_registrar; + +pub use create_voter_weight_record::*; +mod create_voter_weight_record; + +pub use create_max_voter_weight_record::*; +mod create_max_voter_weight_record; + +pub use close_voter::*; +mod close_voter; + +pub use withdraw::*; +mod withdraw; + +pub use deposit::*; +mod deposit; diff --git a/programs/token-voter/src/instructions/withdraw.rs b/programs/token-voter/src/instructions/withdraw.rs new file mode 100644 index 00000000..a00ae6f2 --- /dev/null +++ b/programs/token-voter/src/instructions/withdraw.rs @@ -0,0 +1,154 @@ +use { + crate::{error::*, state::*, tools::spl_token::transfer_spl_tokens_signed_checked, ID}, + anchor_lang::prelude::*, + anchor_spl::{associated_token::AssociatedToken, token_interface::{Mint, TokenAccount, TokenInterface}}, +}; + +#[derive(Accounts)] +pub struct Withdraw<'info> { + pub registrar: Box>, + + // checking the PDA address it just an extra precaution, + // the other constraints must be exhaustive + #[account( + mut, + seeds = [registrar.key().as_ref(), b"voter".as_ref(), voter_authority.key().as_ref()], + bump = voter.voter_bump, + has_one = registrar, + )] + pub voter: Box>, + + #[account(mut)] + pub voter_authority: Signer<'info>, + + /// The token_owner_record for the voter_authority. This is needed + /// to be able to forbid withdraws while the voter is engaged with + /// a vote or has an open proposal. + /// + /// CHECK: token_owner_record is validated in the instruction: + /// - owned by registrar.governance_program_id + /// - for the registrar.realm + /// - for the registrar.realm_governing_token_mint + /// - governing_token_owner is voter_authority + pub token_owner_record: UncheckedAccount<'info>, + + /// Tokens of this mint must be included in the Voting Mint Configs + pub mint: InterfaceAccount<'info, Mint>, + + /// Withdraws must update the voter weight record, to prevent a stale + /// record being used to vote after the withdraw. + #[account( + mut, + seeds = [registrar.key().as_ref(), b"voter-weight-record".as_ref(), voter_authority.key().as_ref()], + bump = voter.voter_weight_record_bump, + constraint = voter_weight_record.realm == registrar.realm, + constraint = voter_weight_record.governing_token_owner == voter_authority.key(), + constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint, + )] + pub voter_weight_record: Box>, + + #[account( + mut, + associated_token::authority = voter, + associated_token::mint = mint, + associated_token::token_program = token_program, + )] + pub vault: Box>, + + #[account( + init_if_needed, + associated_token::authority = voter_authority, + associated_token::mint = mint, + associated_token::token_program = token_program, + payer = voter_authority + )] + pub destination: Box>, + pub system_program: Program<'info, System>, + pub associated_token_program: Program<'info, AssociatedToken>, + + pub token_program: Interface<'info, TokenInterface>, +} + +/// Withdraws tokens from a deposit entry. +/// +/// `deposit_entry_index`: The deposit entry to withdraw from. +/// `amount`: is in units of the native currency being withdrawn. +pub fn withdraw<'key, 'accounts, 'remaining, 'info>( + ctx: Context<'key, 'accounts, 'remaining, 'info, Withdraw<'info>>, + deposit_entry_index: u8, + amount: u64, +) -> Result<()> { + let voter_authority_key = &ctx.accounts.voter_authority.key(); + let voter = &mut ctx.accounts.voter; + + { + transfer_spl_tokens_signed_checked( + &ctx.accounts.vault.to_account_info(), + &ctx.accounts.destination.to_account_info(), + &voter.to_account_info(), + voter_seeds_no_seeds!(voter, voter_authority_key), + &ID, + amount, + &ctx.accounts.token_program.to_account_info(), + &ctx.accounts.mint.to_account_info(), + ctx.remaining_accounts, + )?; + } + + // Load the accounts. + let registrar = &ctx.accounts.registrar; + + // Get the exchange rate for the token being withdrawn. + let mint_idx = registrar.voting_mint_config_index(ctx.accounts.destination.mint)?; + + // Governance may forbid withdraws, for example when engaged in a vote. + // Not applicable for tokens that don't contribute to voting power. + let token_owner_record = voter.load_token_owner_record( + &ctx.accounts.token_owner_record.to_account_info(), + registrar, + voter_authority_key, + )?; + token_owner_record.assert_can_withdraw_governing_tokens(Clock::get()?.unix_timestamp)?; + + let deposit_entry = voter.active_deposit_mut(deposit_entry_index)?; + + require_eq!( + mint_idx, + deposit_entry.voting_mint_config_idx as usize, + TokenVoterError::MintNotFound + ); + + // Bookkeeping for withdrawn funds. + require_gte!( + deposit_entry.amount_deposited_native, + amount, + TokenVoterError::TokenAmountOverflow + ); + + deposit_entry.amount_deposited_native = deposit_entry + .amount_deposited_native + .checked_sub(amount) + .unwrap(); + + if deposit_entry.amount_deposited_native == 0 { + deposit_entry.is_used = false; + } + + let clock = Clock::get()?; + let current_slot_hash = clock.slot; + + // Using the slot hash to enforce withdrawal and depositing to be not + // in the same slot to prevent flash loan style governance attacks + require_neq!( + current_slot_hash, + deposit_entry.deposit_slot_hash, + TokenVoterError::CannotWithdraw + ); + + // Update the voter weight record + let voter_weight_record = &mut ctx.accounts.voter_weight_record; + voter_weight_record.voter_weight = voter.weight(registrar)?; + voter_weight_record.voter_weight_expiry = Some(Clock::get()?.slot); + + Ok(()) +} diff --git a/programs/token-voter/src/lib.rs b/programs/token-voter/src/lib.rs new file mode 100644 index 00000000..4b68d12f --- /dev/null +++ b/programs/token-voter/src/lib.rs @@ -0,0 +1,70 @@ +use anchor_lang::prelude::*; + +pub mod error; + +mod instructions; +use instructions::*; + +pub mod state; + +pub mod tools; +mod governance; + +#[macro_use] +extern crate static_assertions; + +declare_id!("3JhBg9bSPcfWGFa3t8LH7ooVtrjm45yCkHpxYXMXstUM"); + +#[program] +pub mod token_voter { + use super::*; + + pub fn create_registrar(ctx: Context, max_mints: u8) -> Result<()> { + log_version(); + instructions::create_registrar(ctx, max_mints) + } + pub fn create_voter_weight_record(ctx: Context) -> Result<()> { + log_version(); + instructions::create_voter_weight_record(ctx) + } + + pub fn create_max_voter_weight_record(ctx: Context) -> Result<()> { + log_version(); + instructions::create_max_voter_weight_record(ctx) + } + + pub fn configure_mint_config( + ctx: Context, + digit_shift: i8, + ) -> Result<()> { + log_version(); + instructions::configure_mint_config(ctx, digit_shift) + } + + pub fn deposit<'key, 'accounts, 'remaining, 'info>( + ctx: Context<'key, 'accounts, 'remaining, 'info, Deposit<'info>>, + deposit_entry_index: u8, + amount: u64, + ) -> Result<()> { + instructions::deposit(ctx, deposit_entry_index, amount) + } + + pub fn withdraw<'key, 'accounts, 'remaining, 'info>( + ctx: Context<'key, 'accounts, 'remaining, 'info, Withdraw<'info>>, + deposit_entry_index: u8, + amount: u64, + ) -> Result<()> { + instructions::withdraw(ctx, deposit_entry_index, amount) + } + + pub fn close_voter<'key, 'accounts, 'remaining, 'info>( + ctx: Context<'key, 'accounts, 'remaining, 'info, CloseVoter<'info>>, + ) -> Result<()> { + instructions::close_voter(ctx) + } +} + +fn log_version() { + // TODO: Check if Anchor allows to log it before instruction is deserialized + msg!("VERSION:{:?}", env!("CARGO_PKG_VERSION")); +} diff --git a/programs/token-voter/src/state/deposit_entry.rs b/programs/token-voter/src/state/deposit_entry.rs new file mode 100644 index 00000000..17e8bcdb --- /dev/null +++ b/programs/token-voter/src/state/deposit_entry.rs @@ -0,0 +1,43 @@ +use { + crate::state::VotingMintConfig, + anchor_lang::prelude::* +}; + +/// Bookkeeping for a single deposit for a given mint. +#[derive(AnchorSerialize, AnchorDeserialize, Debug, Clone, Copy, PartialEq)] +pub struct DepositEntry { + /// Amount in deposited, in native currency. + /// Withdraws directly reduce this amount. + /// + /// This directly tracks the total amount added by the user. They may + /// never withdraw more than this amount. + pub amount_deposited_native: u64, + + /// Points to the VotingMintConfig this deposit uses. + pub voting_mint_config_idx: u8, + + /// Deposit slot hash. + /// saves deposit slot hash so that depositor cannot withdraw at the same slot. + pub deposit_slot_hash: u64, + + // True if the deposit entry is being used. + pub is_used: bool, + + /// Reserved for future upgrades + pub reserved: [u8; 38], +} + +const_assert!(std::mem::size_of::() == 8 + 1 + 8 + 1 + 38); +const_assert!(std::mem::size_of::() % 8 == 0); + +impl DepositEntry { + /// # Voting Power Caclulation + /// + /// Returns the voting power for the deposit. + pub fn voting_power(&self, mint_config: &VotingMintConfig) -> Result { + let vote_weight = + mint_config.digit_shift_native(self.amount_deposited_native)?; + + Ok(vote_weight) + } +} \ No newline at end of file diff --git a/programs/token-voter/src/state/mod.rs b/programs/token-voter/src/state/mod.rs new file mode 100644 index 00000000..39003221 --- /dev/null +++ b/programs/token-voter/src/state/mod.rs @@ -0,0 +1,11 @@ +pub use registrar::*; +pub mod registrar; + +pub use voting_mint_config::*; +pub mod voting_mint_config; + +pub use deposit_entry::*; +pub mod deposit_entry; + +pub use voter::*; +pub mod voter; \ No newline at end of file diff --git a/programs/token-voter/src/state/registrar.rs b/programs/token-voter/src/state/registrar.rs new file mode 100644 index 00000000..b8f2ce29 --- /dev/null +++ b/programs/token-voter/src/state/registrar.rs @@ -0,0 +1,156 @@ +use { + crate::{ + error::TokenVoterError, id, state::VotingMintConfig, + tools::spl_token::get_spl_token_mint_supply, vote_weight_record, max_voter_weight_record + }, + anchor_lang::{prelude::*, Discriminator}, + solana_program::pubkey::PUBKEY_BYTES, + spl_governance::state::token_owner_record, +}; + +// Generate a VoteWeightRecord Anchor wrapper, owned by the current program. +// VoteWeightRecords are unique in that they are defined by the SPL governance +// program, but they are actually owned by this program. +vote_weight_record!(crate::ID); + +// Generate a MaxVoterWeightRecord Anchor wrapper, owned by the current program. +// MaxVoterWeightRecord are unique in that they are defined by the SPL governance +// program, but they are actually owned by this program. +max_voter_weight_record!(crate::ID); + +/// Registrar which stores Token Voting configuration for the given Realm +#[account] +#[derive(Debug, PartialEq)] +pub struct Registrar { + /// spl-governance program the Realm belongs to + pub governance_program_id: Pubkey, + + /// Realm of the Registrar + pub realm: Pubkey, + + /// Governing token mint the Registrar is for + /// It can either be the Community or the Council mint of the Realm + /// When the plugin is used the mint is only used as identity of the governing power (voting population) + /// and the actual token of the mint is not used + pub governing_token_mint: Pubkey, + + /// Storage for voting mints and their configuration. + /// The length should be adjusted for one's use case. + pub voting_mint_configs: Vec, + + /// Max mints that voters can create. + pub max_mints: u8, + + /// Reserved for future upgrades + pub reserved: [u8; 127], +} + +impl Registrar { + pub fn get_space(max_mints: u8) -> usize { + Registrar::discriminator().len() + + PUBKEY_BYTES * 3 + + 4 + + max_mints as usize * (PUBKEY_BYTES + 1 + 63) + + 128 + } + + pub fn voting_mint_config_index(&self, mint: Pubkey) -> Result { + self.voting_mint_configs + .iter() + .position(|r| r.mint == mint) + .ok_or_else(|| error!(TokenVoterError::MintNotFound)) + } + + pub fn max_vote_weight(&self, mint_accounts: &[AccountInfo]) -> Result { + self.voting_mint_configs + .iter() + .try_fold(0u64, |mut sum, mint_config| -> Result { + if !mint_config.in_use() { + return Ok(sum); + } + let mint_account = mint_accounts + .iter() + .find(|a| a.key() == mint_config.mint) + .ok_or_else(|| error!(TokenVoterError::MintNotFound))?; + let mint_supply = get_spl_token_mint_supply(mint_account)?; + sum = sum + .checked_add(mint_config.digit_shift_native(mint_supply)?) + .ok_or_else(|| error!(TokenVoterError::VoterWeightOverflow))?; + Ok(sum) + }) + } +} + +/// Returns Registrar PDA seeds +pub fn get_registrar_seeds<'a>( + realm: &'a Pubkey, + governing_token_mint: &'a Pubkey, +) -> [&'a [u8]; 3] { + [b"registrar", realm.as_ref(), governing_token_mint.as_ref()] +} + +/// Returns Registrar PDA address +pub fn get_registrar_address(realm: &Pubkey, governing_token_mint: &Pubkey) -> Pubkey { + Pubkey::find_program_address(&get_registrar_seeds(realm, governing_token_mint), &id()).0 +} + +// Resolves governing_token_owner from voter TokenOwnerRecord and +// 1) asserts it matches the given Registrar and VoterWeightRecord +// 2) asserts governing_token_owner or its delegate is a signer +pub fn resolve_governing_token_owner( + registrar: &Registrar, + voter_token_owner_record_info: &AccountInfo, + voter_authority_info: &AccountInfo, + voter_weight_record: &VoterWeightRecord, +) -> Result { + let voter_token_owner_record = + token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint( + ®istrar.governance_program_id, + voter_token_owner_record_info, + ®istrar.realm, + ®istrar.governing_token_mint, + )?; + + voter_token_owner_record.assert_token_owner_or_delegate_is_signer(voter_authority_info)?; + + // Assert voter TokenOwnerRecord and VoterWeightRecord are for the same governing_token_owner + require_eq!( + voter_token_owner_record.governing_token_owner, + voter_weight_record.governing_token_owner, + TokenVoterError::InvalidTokenOwnerForVoterWeightRecord + ); + + Ok(voter_token_owner_record.governing_token_owner) +} + +#[cfg(test)] +mod test { + + use super::*; + + #[test] + fn test_get_space() { + // Arrange + let expected_space = Registrar::get_space(3); + let mint_config = VotingMintConfig { + mint: Pubkey::default(), + digit_shift: 0, + reserved1: [0; 63], + }; + + let registrar = Registrar { + governance_program_id: Pubkey::default(), + voting_mint_configs: vec![mint_config, mint_config, mint_config], + realm: Pubkey::default(), + governing_token_mint: Pubkey::default(), + max_mints: 0, + reserved: [0; 127], + }; + + // Act + let actual_space = Registrar::discriminator().len() + registrar.try_to_vec().unwrap().len(); + + // Assert + assert_eq!(expected_space, actual_space); + } +} diff --git a/programs/token-voter/src/state/voter.rs b/programs/token-voter/src/state/voter.rs new file mode 100644 index 00000000..98a27b88 --- /dev/null +++ b/programs/token-voter/src/state/voter.rs @@ -0,0 +1,107 @@ +use { + super::{DepositEntry, Registrar}, + crate::error::TokenVoterError, + anchor_lang::{prelude::*, Discriminator}, + solana_program::pubkey::PUBKEY_BYTES, + spl_governance::state::token_owner_record, +}; + +/// User account for minting voting rights. +#[account] +#[derive(Debug, PartialEq)] +pub struct Voter { + /// Voter Authority who owns the account tokens. + pub voter_authority: Pubkey, + + /// Registrar in which the voter is created in. + pub registrar: Pubkey, + + /// Deposit entries for a deposit for a given mint. + pub deposits: Vec, + + /// Voter account bump. + pub voter_bump: u8, + + /// Voter weight record account bump. + pub voter_weight_record_bump: u8, + + /// Reserved for future upgrades + pub reserved: [u8; 94], +} + +const_assert!(std::mem::size_of::() % 8 == 0); + +impl Voter { + pub fn get_space(max_mints: u8) -> usize { + Voter::discriminator().len() + PUBKEY_BYTES * 2 + (max_mints as usize * 64) + 1 + 1 + 94 + } + + pub fn clock_unix_timestamp(&self) -> i64 { + Clock::get().unwrap().unix_timestamp + } + + /// The full vote weight available to the voter + pub fn weight(&self, registrar: &Registrar) -> Result { + self.deposits.iter().filter(|d| d.is_used).try_fold(0u64, |sum, d| { + d.voting_power(®istrar.voting_mint_configs[d.voting_mint_config_idx as usize]) + .map(|vp| sum.checked_add(vp).unwrap()) + }) + } + + pub fn active_deposit_mut(&mut self, index: u8) -> Result<&mut DepositEntry> { + let index = index as usize; + require_gt!( + self.deposits.len(), + index, + TokenVoterError::OutOfBoundsDepositEntryIndex + ); + let d = &mut self.deposits[index]; + Ok(d) + } + + pub fn load_token_owner_record( + &self, + account_info: &AccountInfo, + registrar: &Registrar, + voter_authority: &Pubkey, + ) -> Result { + let record = token_owner_record::get_token_owner_record_data_for_realm_and_governing_mint( + ®istrar.governance_program_id, + account_info, + ®istrar.realm, + ®istrar.governing_token_mint, + )?; + require_keys_eq!( + record.governing_token_owner, + *voter_authority, + TokenVoterError::InvalidTokenOwnerRecord + ); + Ok(record) + } +} + +#[macro_export] +macro_rules! voter_seeds_no_seeds { + ( $voter:expr, $voter_authority:expr ) => { + &[ + $voter.registrar.as_ref(), + b"voter".as_ref(), + $voter_authority.as_ref(), + ] + }; +} +#[macro_export] +macro_rules! voter_seeds { + ( $voter:expr, $voter_authority:expr ) => { + &[ + $voter.registrar.as_ref(), + b"voter".as_ref(), + $voter_authority.as_ref(), + &[$voter.voter_bump], + ] + }; +} + +pub use voter_seeds_no_seeds; + +pub use voter_seeds; diff --git a/programs/token-voter/src/state/voting_mint_config.rs b/programs/token-voter/src/state/voting_mint_config.rs new file mode 100644 index 00000000..31e4787b --- /dev/null +++ b/programs/token-voter/src/state/voting_mint_config.rs @@ -0,0 +1,43 @@ +use crate::error::*; +use anchor_lang::prelude::*; + +/// Exchange rate for an asset that can be used to mint voting rights. +/// +/// See documentation of configure_voting_mint for details on how +/// native token amounts convert to vote weight. +#[derive(AnchorSerialize, AnchorDeserialize, Debug, Clone, Copy, PartialEq)] +pub struct VotingMintConfig { + /// Mint for this entry. + pub mint: Pubkey, + + /// Number of digits to shift native amounts, applying a 10^digit_shift factor. + pub digit_shift: i8, + + // Empty bytes for future upgrades. + pub reserved1: [u8; 63], +} + +const_assert!(std::mem::size_of::() == 32 + 1 + 63); +const_assert!(std::mem::size_of::() % 8 == 0); + +impl VotingMintConfig { + /// Converts an amount in this voting mints's native currency + /// to the base vote weight + /// by applying the digit_shift factor. + pub fn digit_shift_native(&self, amount_native: u64) -> Result { + let compute = || -> Option { + let val = if self.digit_shift < 0 { + (amount_native as u128).checked_div(10u128.pow((-self.digit_shift) as u32))? + } else { + (amount_native as u128).checked_mul(10u128.pow(self.digit_shift as u32))? + }; + u64::try_from(val).ok() + }; + compute().ok_or_else(|| error!(TokenVoterError::VoterWeightOverflow)) + } + + /// Whether this voting mint is configured. + pub fn in_use(&self) -> bool { + self.mint != Pubkey::default() + } +} diff --git a/programs/token-voter/src/tools/mod.rs b/programs/token-voter/src/tools/mod.rs new file mode 100644 index 00000000..f784c78b --- /dev/null +++ b/programs/token-voter/src/tools/mod.rs @@ -0,0 +1 @@ +pub mod spl_token; diff --git a/programs/token-voter/src/tools/spl_token.rs b/programs/token-voter/src/tools/spl_token.rs new file mode 100644 index 00000000..aee1c553 --- /dev/null +++ b/programs/token-voter/src/tools/spl_token.rs @@ -0,0 +1,683 @@ +//! General purpose SPL token utility functions + +use { + crate::error::TokenVoterError, + anchor_lang::prelude::*, + arrayref::array_ref, + solana_program::{ + entrypoint::ProgramResult, + msg, + program::{invoke, invoke_signed}, + program_option::COption, + program_pack::Pack, + system_instruction, + sysvar::Sysvar, + }, + spl_governance::tools::pack::unpack_coption_pubkey, + spl_token::state::Multisig, + spl_token_2022::{ + cmp_pubkeys, + extension::{ + transfer_fee::TransferFeeConfig, transfer_hook, AccountType, BaseStateWithExtensions, + ExtensionType, PodStateWithExtensions, StateWithExtensions, + }, + generic_token_account::GenericTokenAccount, + instruction::AuthorityType, + pod::PodMint, + state::{Account, Mint}, + }, + spl_transfer_hook_interface::onchain::add_extra_accounts_for_execute_cpi, +}; + +/// Computationally cheap method to get amount from a token account +/// It reads amount without deserializing full account data +pub fn get_spl_token_amount(token_account_info: &AccountInfo) -> Result { + assert_is_valid_spl_token_account(token_account_info)?; + + // TokeAccount layout: mint(32), owner(32), amount(8), ... + let data = token_account_info.try_borrow_data()?; + let amount_bytes = array_ref![data, 64, 8]; + + Ok(u64::from_le_bytes(*amount_bytes)) +} + +/// Checks if the provided spl_token_program is spl token 2022 +pub fn is_spl_token_2022(spl_token_program_id: &Pubkey) -> bool { + if cmp_pubkeys(spl_token_program_id, &spl_token::id()) { + return false; + } + return true; +} + +/// Creates and initializes SPL token account with PDA using the provided PDA +/// seeds +#[allow(clippy::too_many_arguments)] +pub fn create_spl_token_account_signed<'a>( + payer_info: &AccountInfo<'a>, + token_account_info: &AccountInfo<'a>, + token_account_address_seeds: &[&[u8]], + token_mint_info: &AccountInfo<'a>, + token_account_owner_info: &AccountInfo<'a>, + program_id: &Pubkey, + system_info: &AccountInfo<'a>, + spl_token_info: &AccountInfo<'a>, + rent_sysvar_info: &AccountInfo<'a>, + rent: &Rent, +) -> Result<()> { + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + + // Get the token space for if the token has extensions. + let space = if is_spl_token_2022(spl_token_program_id) { + let mint_data = token_mint_info.data.borrow(); + + let state = PodStateWithExtensions::::unpack(&mint_data).map_err(|_| { + Into::::into(TokenVoterError::InvalidGoverningTokenMint) + })?; + let mint_extensions = state.get_extension_types()?; + let required_extensions = + ExtensionType::get_required_init_account_extensions(&mint_extensions); + ExtensionType::try_calculate_account_len::(&required_extensions)? + } else { + spl_token_2022::state::Account::get_packed_len() + }; + + let create_account_instruction = system_instruction::create_account( + payer_info.key, + token_account_info.key, + 1.max(rent.minimum_balance(space)), + space as u64, + spl_token_program_id, + ); + + let (account_address, bump_seed) = + Pubkey::find_program_address(token_account_address_seeds, program_id); + + if account_address != *token_account_info.key { + msg!( + "Create SPL Token Account with PDA: {:?} was requested while PDA: {:?} was expected", + token_account_info.key, + account_address + ); + return Err(ProgramError::InvalidSeeds.into()); + } + + let mut signers_seeds = token_account_address_seeds.to_vec(); + let bump = &[bump_seed]; + signers_seeds.push(bump); + + invoke_signed( + &create_account_instruction, + &[ + payer_info.clone(), + token_account_info.clone(), + system_info.clone(), + ], + &[&signers_seeds[..]], + )?; + + let initialize_account_instruction = spl_token_2022::instruction::initialize_account( + spl_token_program_id, + token_account_info.key, + token_mint_info.key, + token_account_owner_info.key, + )?; + + invoke( + &initialize_account_instruction, + &[ + payer_info.clone(), + token_account_info.clone(), + token_account_owner_info.clone(), + token_mint_info.clone(), + spl_token_info.clone(), + rent_sysvar_info.clone(), + ], + )?; + + Ok(()) +} + +/// Transfers SPL Tokens +pub fn transfer_spl_tokens<'a>( + source_info: &AccountInfo<'a>, + destination_info: &AccountInfo<'a>, + authority_info: &AccountInfo<'a>, + amount: u64, + spl_token_info: &AccountInfo<'a>, +) -> ProgramResult { + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + // for previous instruction compatibility we do not use transfer_checked() here. + #[allow(deprecated)] + let transfer_instruction = spl_token_2022::instruction::transfer( + spl_token_program_id, + source_info.key, + destination_info.key, + authority_info.key, + &[], + amount, + ) + .unwrap(); + + invoke( + &transfer_instruction, + &[ + spl_token_info.clone(), + authority_info.clone(), + source_info.clone(), + destination_info.clone(), + ], + )?; + + Ok(()) +} + +/// Transfers SPL Tokens +pub fn transfer_checked_spl_tokens<'a>( + source_info: &AccountInfo<'a>, + destination_info: &AccountInfo<'a>, + authority_info: &AccountInfo<'a>, + amount: u64, + spl_token_info: &AccountInfo<'a>, + mint_info: &AccountInfo<'a>, + additional_accounts: &[AccountInfo<'a>], +) -> ProgramResult { + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + + let mut transfer_instruction = spl_token_2022::instruction::transfer_checked( + spl_token_program_id, + source_info.key, + mint_info.key, + destination_info.key, + authority_info.key, + &[], + amount, + get_mint_decimals(mint_info)?, + ) + .unwrap(); + + let mut cpi_account_infos = vec![ + source_info.clone(), + mint_info.clone(), + destination_info.clone(), + authority_info.clone(), + ]; + + // if it's a signer, it might be a multisig signer, throw it in! + additional_accounts + .iter() + .filter(|ai| ai.is_signer) + .for_each(|ai| { + cpi_account_infos.push(ai.clone()); + transfer_instruction + .accounts + .push(AccountMeta::new_readonly(*ai.key, ai.is_signer)); + }); + // used for transfer_hooks + // scope the borrowing to avoid a double-borrow during CPI + { + let mint_data = mint_info.try_borrow_data()?; + let mint = StateWithExtensions::::unpack(&mint_data)?; + if let Some(program_id) = transfer_hook::get_program_id(&mint) { + add_extra_accounts_for_execute_cpi( + &mut transfer_instruction, + &mut cpi_account_infos, + &program_id, + source_info.clone(), + mint_info.clone(), + destination_info.clone(), + authority_info.clone(), + amount, + additional_accounts, + )?; + } + } + + invoke(&transfer_instruction, &cpi_account_infos)?; + + Ok(()) +} + +/// Mint SPL Tokens +pub fn mint_spl_tokens_to<'a>( + mint_info: &AccountInfo<'a>, + destination_info: &AccountInfo<'a>, + mint_authority_info: &AccountInfo<'a>, + amount: u64, + spl_token_info: &AccountInfo<'a>, +) -> ProgramResult { + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + + let mint_to_ix = spl_token_2022::instruction::mint_to( + spl_token_program_id, + mint_info.key, + destination_info.key, + mint_authority_info.key, + &[], + amount, + ) + .unwrap(); + + invoke( + &mint_to_ix, + &[ + spl_token_info.clone(), + mint_authority_info.clone(), + mint_info.clone(), + destination_info.clone(), + ], + )?; + + Ok(()) +} + +/// Transfers SPL Tokens from a token account owned by the provided PDA +/// authority with seeds +pub fn transfer_spl_tokens_signed<'a>( + source_info: &AccountInfo<'a>, + destination_info: &AccountInfo<'a>, + authority_info: &AccountInfo<'a>, + authority_seeds: &[&[u8]], + program_id: &Pubkey, + amount: u64, + spl_token_info: &AccountInfo<'a>, +) -> ProgramResult { + let (authority_address, bump_seed) = Pubkey::find_program_address(authority_seeds, program_id); + + if authority_address != *authority_info.key { + msg!( + "Transfer SPL Token with Authority PDA: {:?} was requested while PDA: {:?} was expected", + authority_info.key, + authority_address + ); + return Err(ProgramError::InvalidSeeds); + } + + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + // for previous instruction compatibility we do not use transfer_checked() here. + #[allow(deprecated)] + let transfer_instruction = spl_token_2022::instruction::transfer( + spl_token_program_id, + source_info.key, + destination_info.key, + authority_info.key, + &[], + amount, + ) + .unwrap(); + + let mut signers_seeds = authority_seeds.to_vec(); + let bump = &[bump_seed]; + signers_seeds.push(bump); + + invoke_signed( + &transfer_instruction, + &[ + spl_token_info.clone(), + authority_info.clone(), + source_info.clone(), + destination_info.clone(), + ], + &[&signers_seeds[..]], + )?; + + Ok(()) +} + +/// Transfers SPL Tokens checked from a token account owned by the provided PDA +/// authority with seeds +pub fn transfer_spl_tokens_signed_checked<'a>( + source_info: &AccountInfo<'a>, + destination_info: &AccountInfo<'a>, + authority_info: &AccountInfo<'a>, + authority_seeds: &[&[u8]], + program_id: &Pubkey, + amount: u64, + spl_token_info: &AccountInfo<'a>, + mint_info: &AccountInfo<'a>, + additional_accounts: &[AccountInfo<'a>], +) -> ProgramResult { + let (authority_address, bump_seed) = Pubkey::find_program_address(authority_seeds, program_id); + + if authority_address != *authority_info.key { + msg!( + "Transfer SPL Token with Authority PDA: {:?} was requested while PDA: {:?} was expected", + authority_info.key, + authority_address + ); + return Err(ProgramError::InvalidSeeds); + } + + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + + let mut transfer_instruction = spl_token_2022::instruction::transfer_checked( + spl_token_program_id, + source_info.key, + mint_info.key, + destination_info.key, + authority_info.key, + &[], + amount, + get_mint_decimals(mint_info)?, + ) + .unwrap(); + + let mut signers_seeds = authority_seeds.to_vec(); + let bump = &[bump_seed]; + signers_seeds.push(bump); + + let mut cpi_account_infos = vec![ + source_info.clone(), + mint_info.clone(), + destination_info.clone(), + authority_info.clone(), + ]; + + // if it's a signer, it might be a multisig signer, throw it in! + additional_accounts + .iter() + .filter(|ai| ai.is_signer) + .for_each(|ai| { + cpi_account_infos.push(ai.clone()); + transfer_instruction + .accounts + .push(AccountMeta::new_readonly(*ai.key, ai.is_signer)); + }); + + // used for transfer_hooks + // scope the borrowing to avoid a double-borrow during CPI + { + let mint_data = mint_info.try_borrow_data()?; + let mint = StateWithExtensions::::unpack(&mint_data)?; + if let Some(program_id) = transfer_hook::get_program_id(&mint) { + add_extra_accounts_for_execute_cpi( + &mut transfer_instruction, + &mut cpi_account_infos, + &program_id, + source_info.clone(), + mint_info.clone(), + destination_info.clone(), + authority_info.clone(), + amount, + additional_accounts, + )?; + } + } + + invoke_signed( + &transfer_instruction, + &cpi_account_infos, + &[&signers_seeds[..]], + )?; + + Ok(()) +} + +/// Burns SPL Tokens from a token account owned by the provided PDA authority +/// with seeds +pub fn burn_spl_tokens_signed<'a>( + token_account_info: &AccountInfo<'a>, + token_mint_info: &AccountInfo<'a>, + authority_info: &AccountInfo<'a>, + authority_seeds: &[&[u8]], + program_id: &Pubkey, + amount: u64, + spl_token_info: &AccountInfo<'a>, +) -> ProgramResult { + let (authority_address, bump_seed) = Pubkey::find_program_address(authority_seeds, program_id); + + if authority_address != *authority_info.key { + msg!( + "Burn SPL Token with Authority PDA: {:?} was requested while PDA: {:?} was expected", + authority_info.key, + authority_address + ); + return Err(ProgramError::InvalidSeeds); + } + + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + let burn_ix = spl_token_2022::instruction::burn( + spl_token_program_id, + token_account_info.key, + token_mint_info.key, + authority_info.key, + &[], + amount, + ) + .unwrap(); + + let mut signers_seeds = authority_seeds.to_vec(); + let bump = &[bump_seed]; + signers_seeds.push(bump); + + invoke_signed( + &burn_ix, + &[ + spl_token_info.clone(), + token_account_info.clone(), + token_mint_info.clone(), + authority_info.clone(), + ], + &[&signers_seeds[..]], + )?; + + Ok(()) +} + +/// Asserts the given account_info represents a valid SPL Token account which is +/// initialized and belongs to spl_token program +pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<()> { + if account_info.data_is_empty() { + return Err(TokenVoterError::SplTokenAccountDoesNotExist.into()); + } + + if account_info.owner != &spl_token_2022::id() && account_info.owner != &spl_token::id() { + return Err(TokenVoterError::SplTokenAccountWithInvalidOwner.into()); + } + + // Check if the account data is a valid token account + // also checks if the account is initialized or not. + if !Account::valid_account_data(&account_info.try_borrow_data()?) { + return Err(TokenVoterError::SplTokenInvalidTokenAccountData.into()); + } + + Ok(()) +} + +/// Checks if the given account_info is spl-token token account +pub fn is_spl_token_account(account_info: &AccountInfo) -> bool { + assert_is_valid_spl_token_account(account_info).is_ok() +} + +/// Asserts the given mint_info represents a valid SPL Token Mint account which +/// is initialized and belongs to spl_token program +pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<()> { + if mint_info.data_is_empty() { + return Err(TokenVoterError::SplTokenMintDoesNotExist.into()); + } + + if mint_info.owner != &spl_token_2022::id() && mint_info.owner != &spl_token::id() { + return Err(TokenVoterError::SplTokenMintWithInvalidOwner.into()); + } + + // assert that length is mint + if !valid_mint_length(&mint_info.try_borrow_data()?) { + return Err(TokenVoterError::SplTokenInvalidMintAccountData.into()); + } + + // In token program [36, 8, 1, is_initialized(1), 36] is the layout + let data = mint_info.try_borrow_data()?; + let is_initialized = array_ref![data, 45, 1]; + + if is_initialized == &[0] { + return Err(TokenVoterError::SplTokenMintNotInitialized.into()); + } + + Ok(()) +} + +/// Checks if the given account_info is be spl-token mint account +pub fn is_spl_token_mint(mint_info: &AccountInfo) -> bool { + assert_is_valid_spl_token_mint(mint_info).is_ok() +} + +/// Computationally cheap method to get mint from a token account +/// It reads mint without deserializing full account data +pub fn get_spl_token_mint(token_account_info: &AccountInfo) -> Result { + assert_is_valid_spl_token_account(token_account_info)?; + + // TokeAccount layout: mint(32), owner(32), amount(8), ... + let data = token_account_info.try_borrow_data()?; + let mint_data = array_ref![data, 0, 32]; + Ok(Pubkey::new_from_array(*mint_data)) +} + +/// Computationally cheap method to get owner from a token account +/// It reads owner without deserializing full account data +pub fn get_spl_token_owner(token_account_info: &AccountInfo) -> Result { + assert_is_valid_spl_token_account(token_account_info)?; + + // TokeAccount layout: mint(32), owner(32), amount(8) + let data = token_account_info.try_borrow_data()?; + let owner_data = array_ref![data, 32, 32]; + Ok(Pubkey::new_from_array(*owner_data)) +} + +/// Computationally cheap method to just get supply from a mint without +/// unpacking the whole object +pub fn get_spl_token_mint_supply(mint_info: &AccountInfo) -> Result { + assert_is_valid_spl_token_mint(mint_info)?; + // In token program, 36, 8, 1, 1 is the layout, where the first 8 is supply u64. + // so we start at 36. + let data = mint_info.try_borrow_data().unwrap(); + let bytes = array_ref![data, 36, 8]; + + Ok(u64::from_le_bytes(*bytes)) +} + +/// Computationally cheap method to just get authority from a mint without +/// unpacking the whole object +pub fn get_spl_token_mint_authority(mint_info: &AccountInfo) -> Result> { + assert_is_valid_spl_token_mint(mint_info)?; + // In token program, 36, 8, 1, 1 is the layout, where the first 36 is authority. + let data = mint_info.try_borrow_data().unwrap(); + let bytes = array_ref![data, 0, 36]; + + Ok(unpack_coption_pubkey(bytes)?) +} + +/// Asserts current mint authority matches the given authority and it's signer +/// of the transaction +pub fn assert_spl_token_mint_authority_is_signer( + mint_info: &AccountInfo, + mint_authority_info: &AccountInfo, +) -> Result<()> { + let mint_authority = get_spl_token_mint_authority(mint_info)?; + + if mint_authority.is_none() { + return Err(TokenVoterError::MintHasNoAuthority.into()); + } + + if !mint_authority.contains(mint_authority_info.key) { + return Err(TokenVoterError::InvalidMintAuthority.into()); + } + + if !mint_authority_info.is_signer { + return Err(TokenVoterError::MintAuthorityMustSign.into()); + } + + Ok(()) +} + +/// Asserts current token owner matches the given owner and it's signer of the +/// transaction +pub fn assert_spl_token_owner_is_signer( + token_info: &AccountInfo, + token_owner_info: &AccountInfo, +) -> Result<()> { + let token_owner = get_spl_token_owner(token_info)?; + + if token_owner != *token_owner_info.key { + return Err(TokenVoterError::InvalidTokenOwner.into()); + } + + if !token_owner_info.is_signer { + return Err(TokenVoterError::TokenOwnerMustSign.into()); + } + + Ok(()) +} + +/// Sets spl-token account (Mint or TokenAccount) authority +pub fn set_spl_token_account_authority<'a>( + account_info: &AccountInfo<'a>, + account_authority: &AccountInfo<'a>, + new_account_authority: &Pubkey, + authority_type: AuthorityType, + spl_token_info: &AccountInfo<'a>, +) -> Result<()> { + let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + let set_authority_ix = spl_token_2022::instruction::set_authority( + spl_token_program_id, + account_info.key, + Some(new_account_authority), + authority_type, + account_authority.key, + &[], + )?; + + invoke( + &set_authority_ix, + &[ + account_info.clone(), + account_authority.clone(), + spl_token_info.clone(), + ], + )?; + + Ok(()) +} + +fn get_spl_token_program_id(spl_token_info: &AccountInfo) -> Pubkey { + if is_spl_token_2022(spl_token_info.key) { + spl_token_2022::id() + } else { + spl_token::id() + } +} + +/// Computationally cheap method to just get supply off a mint without unpacking whole object +pub fn get_mint_decimals(account_info: &AccountInfo) -> Result { + // In token program, 36, 8, 1, 1, is the layout, where the first 1 is decimals u8. + // so we start at 36. + let data = account_info.try_borrow_data()?; + + // If we don't check this and an empty account is passed in, we get a panic when + // we try to index into the data. + if data.is_empty() { + return Err(TokenVoterError::InvalidAccountData.into()); + } + + Ok(data[44]) +} + +const ACCOUNTTYPE_MINT: u8 = AccountType::Mint as u8; +fn valid_mint_length(mint_data: &[u8]) -> bool { + mint_data.len() == Mint::LEN + || (mint_data.len() > Mint::LEN + && mint_data.len() != Multisig::LEN + && ACCOUNTTYPE_MINT == mint_data[Mint::LEN]) +} + +/// Get current TransferFee, returns 0 if no TransferFeeConfig exist. +pub fn get_current_mint_fee(mint_info: &AccountInfo, amount: u64) -> Result { + let mint_data = mint_info.try_borrow_data()?; + let mint = PodStateWithExtensions::::unpack(&mint_data)?; + + if let Ok(transfer_fee_config) = mint.get_extension::() { + Ok(transfer_fee_config + .calculate_epoch_fee(Clock::get()?.epoch, amount) + .ok_or(TokenVoterError::Overflow)?) + } else { + Ok(0) + } +} diff --git a/programs/token-voter/tests/configure_voter_weights.rs b/programs/token-voter/tests/configure_voter_weights.rs new file mode 100644 index 00000000..a1092749 --- /dev/null +++ b/programs/token-voter/tests/configure_voter_weights.rs @@ -0,0 +1,200 @@ +use program_test::token_voter_test::TokenVoterTest; +use program_test::tools::*; +use solana_program_test::*; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::transport::TransportError; + +mod program_test; + +#[tokio::test] +async fn test_configure_voter_weights_with_token_extensions() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + + let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _mint_cookie = token_voter_test.configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ).await?; + + // Assert + + let voter_data = token_voter_test + .get_voter(&voter_cookie.address) + .await; + + assert_eq!(voter_data.deposits.len(), 0); + assert_eq!(voter_data.registrar, registrar_cookie.address); + + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + + assert_eq!(registrar.voting_mint_configs.len(), 1); + assert_eq!(registrar.voting_mint_configs.first().unwrap().mint, first_mint_cookie.address); + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // supply is 100 + assert_eq!(max_voter_weight_record.max_voter_weight, 100); + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.realm, realm_cookie.address); + assert_eq!( + max_voter_weight_record.governing_token_mint, + realm_cookie.account.community_mint + ); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_voter_weights() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _mint_cookie = token_voter_test.configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ).await?; + + // Assert + + let voter_data = token_voter_test + .get_voter(&voter_cookie.address) + .await; + + assert_eq!(voter_data.deposits.len(), 0); + assert_eq!(voter_data.registrar, registrar_cookie.address); + + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + + assert_eq!(registrar.voting_mint_configs.len(), 1); + assert_eq!(registrar.voting_mint_configs.first().unwrap().mint, first_mint_cookie.address); + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // supply is 100 + assert_eq!(max_voter_weight_record.max_voter_weight, 100); + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.realm, realm_cookie.address); + assert_eq!( + max_voter_weight_record.governing_token_mint, + realm_cookie.account.community_mint + ); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_voter_weights_with_invalid_voter_error() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + + // Act + let err = token_voter_test + .with_voter_using_ix( + ®istrar_cookie, + &first_user_cookie, + |i| i.accounts[1].pubkey = Pubkey::new_unique(), // voter + ) + .await + .err() + .unwrap(); + + // Assert + + assert_anchor_err(err, anchor_lang::error::ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_configure_voter_weights_with_realm_authority_must_sign_error( +) -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + // Act + + let err = token_voter_test.configure_mint_config_using_ix( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift, + |i| i.accounts[2].is_signer = false, // realm_authority + Some(&[]), + ).await + .err() + .unwrap(); + + // Assert + assert_anchor_err(err, anchor_lang::error::ErrorCode::AccountNotSigner); + + Ok(()) +} diff --git a/programs/token-voter/tests/create_max_voter_weight_record.rs b/programs/token-voter/tests/create_max_voter_weight_record.rs new file mode 100644 index 00000000..87d3c533 --- /dev/null +++ b/programs/token-voter/tests/create_max_voter_weight_record.rs @@ -0,0 +1,103 @@ +use crate::program_test::token_voter_test::TokenVoterTest; +use program_test::tools::assert_ix_err; +use solana_program::instruction::InstructionError; +use solana_program_test::*; +use solana_sdk::transport::TransportError; + +mod program_test; + +#[tokio::test] +async fn test_create_max_voter_weight_record_with_token_extensions() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + + let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + // Act + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Assert + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + assert_eq!( + max_voter_weight_record_cookie.account.max_voter_weight, + max_voter_weight_record.max_voter_weight + ); + assert_eq!( + max_voter_weight_record_cookie.account.realm, + max_voter_weight_record.realm + ); + + Ok(()) +} + +#[tokio::test] +async fn test_create_max_voter_weight_record() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + // Act + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + // Assert + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + assert_eq!( + max_voter_weight_record_cookie.account.max_voter_weight, + max_voter_weight_record.max_voter_weight + ); + assert_eq!( + max_voter_weight_record_cookie.account.realm, + max_voter_weight_record.realm + ); + + Ok(()) +} + + +#[tokio::test] +async fn test_create_max_voter_weight_record_with_already_exists_error( +) -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + token_voter_test.bench.advance_clock().await; + + // Act + let err = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await + .err() + .unwrap(); + + // Assert + + // InstructionError::Custom(0) is returned for TransactionError::AccountInUse + assert_ix_err(err, InstructionError::Custom(0)); + + Ok(()) +} diff --git a/programs/token-voter/tests/create_registrar.rs b/programs/token-voter/tests/create_registrar.rs new file mode 100644 index 00000000..820f80a4 --- /dev/null +++ b/programs/token-voter/tests/create_registrar.rs @@ -0,0 +1,200 @@ +mod program_test; + +use anchor_lang::prelude::{ErrorCode, Pubkey}; +use token_voter::error::TokenVoterError; +use program_test::token_voter_test::TokenVoterTest; + +use solana_program::instruction::InstructionError; +use solana_program_test::*; +use solana_sdk::{signature::Keypair, transport::TransportError}; +use crate::program_test::program_test_bench::MintType; +use program_test::tools::{assert_anchor_err, assert_ix_err, assert_token_voter_err}; + +#[tokio::test] +async fn test_create_registrar_with_token_extensions() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + + let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + + // Act + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + // Assert + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar, registrar_cookie.account); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + // Act + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + // Assert + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar, registrar_cookie.account); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_realm_authority_error() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let mut realm_cookie = token_voter_test.governance.with_realm().await?; + realm_cookie.realm_authority = Keypair::new(); + + // Act + let err = token_voter_test + .with_registrar(&realm_cookie) + .await + .err() + .unwrap(); + + assert_token_voter_err(err, TokenVoterError::InvalidRealmAuthority); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_realm_authority_must_sign_error() -> Result<(), TransportError> +{ + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + // Act + let err = token_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[4].is_signer = false, // realm_authority + Some(&[]), + ) + .await + .err() + .unwrap(); + + assert_anchor_err(err, anchor_lang::error::ErrorCode::AccountNotSigner); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_spl_gov_program_id_error() -> Result<(), TransportError> +{ + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + // Try to use a different program id + let governance_program_id = token_voter_test.program_id; + + // Act + let err = token_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[1].pubkey = governance_program_id, //governance_program_id + None, + ) + .await + .err() + .unwrap(); + + assert_anchor_err(err, anchor_lang::error::ErrorCode::ConstraintOwner); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_realm_error() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + // Act + let err = token_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[2].pubkey = Pubkey::new_unique(), // realm + None, + ) + .await + .err() + .unwrap(); + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_invalid_governing_token_mint_error( +) -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let mint_cookie = token_voter_test.bench.with_mint(&MintType::SplToken, None).await?; + + // Act + let err = token_voter_test + .with_registrar_using_ix( + &realm_cookie, + |i| i.accounts[3].pubkey = mint_cookie.address, // governing_token_mint + None, + ) + .await + .err() + .unwrap(); + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} + +#[tokio::test] +async fn test_create_registrar_with_registrar_already_exists_error() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + token_voter_test.with_registrar(&realm_cookie).await?; + + token_voter_test.bench.advance_clock().await; + + // Act + + let err = token_voter_test + .with_registrar(&realm_cookie) + .await + .err() + .unwrap(); + + // Assert + + // Registrar already exists and it throws Custom(0) error + assert_ix_err(err, InstructionError::Custom(0)); + + Ok(()) +} diff --git a/programs/token-voter/tests/deposit.rs b/programs/token-voter/tests/deposit.rs new file mode 100644 index 00000000..8cbdd7e3 --- /dev/null +++ b/programs/token-voter/tests/deposit.rs @@ -0,0 +1,647 @@ +use anchor_lang::error::ErrorCode; +use program_test::token_voter_test::TokenVoterTest; +use program_test::tools::*; +use solana_program_test::*; +use solana_sdk::instruction::InstructionError; +use solana_sdk::transport::TransportError; +use token_voter::error::TokenVoterError; + +mod program_test; + +#[tokio::test] +async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + + let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token_2022::id(), + 0, + amount_deposited, + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + // println!("{:?}", voter_data); + assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, amount_deposited); + assert_eq!(voter_data.deposits.len(), 1); + + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.voting_mint_configs.len(), 1); + assert_eq!( + registrar.voting_mint_configs.first().unwrap().mint, + first_mint_cookie.address + ); + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // supply is 100 + assert_eq!(max_voter_weight_record.max_voter_weight, 100); + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.realm, realm_cookie.address); + assert_eq!( + max_voter_weight_record.governing_token_mint, + realm_cookie.account.community_mint + ); + + Ok(()) +} + +#[tokio::test] +async fn test_deposit_entry() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + // println!("{:?}", voter_data); + assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, amount_deposited); + assert_eq!(voter_data.deposits.len(), 1); + + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.voting_mint_configs.len(), 1); + assert_eq!( + registrar.voting_mint_configs.first().unwrap().mint, + first_mint_cookie.address + ); + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // supply is 100 + assert_eq!(max_voter_weight_record.max_voter_weight, 100); + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.realm, realm_cookie.address); + assert_eq!( + max_voter_weight_record.governing_token_mint, + realm_cookie.account.community_mint + ); + + Ok(()) +} + +#[tokio::test] +async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let mut users_iter = token_voter_test.users.iter(); + let first_user_cookie = users_iter.next().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); + + + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, &first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &second_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + + let amount_deposited = 3_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + token_voter_test.bench.advance_clock().await; + + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + token_voter_test.bench.advance_clock().await; + + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + let mut deposit_entries = voter_data.deposits.iter(); + let first_deposit_entry = deposit_entries.next().unwrap(); + assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited * 3); + assert_eq!(voter_data.deposits.len(), 1); + + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.voting_mint_configs.len(), 2); + assert_eq!( + registrar.voting_mint_configs.first().unwrap().mint, + first_mint_cookie.address + ); + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // supply is 100 * 2 + assert_eq!(max_voter_weight_record.max_voter_weight, 200); + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.realm, realm_cookie.address); + assert_eq!( + max_voter_weight_record.governing_token_mint, + realm_cookie.account.community_mint + ); + + Ok(()) +} + +#[tokio::test] +async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let mut users_iter = token_voter_test.users.iter(); + let first_user_cookie = users_iter.next().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); + + + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, &first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &second_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &second_mint_cookie, + &spl_token::id(), + 1, + amount_deposited, + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + + let mut deposit_entries = voter_data.deposits.iter(); + let first_deposit_entry = deposit_entries.next().unwrap(); + let second_deposit_entry = deposit_entries.next().unwrap(); + assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited); + assert_eq!(second_deposit_entry.amount_deposited_native, amount_deposited); + assert_eq!(voter_data.deposits.len(), 2); + + let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie).await; + assert_eq!(first_vault_balance, amount_deposited); + let second_vault_balance = token_voter_test.vault_balance(&voter_cookie, &second_mint_cookie).await; + assert_eq!(second_vault_balance, amount_deposited); + + + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.voting_mint_configs.len(), 2); + assert_eq!( + registrar.voting_mint_configs.first().unwrap().mint, + first_mint_cookie.address + ); + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // supply is 100 * 2 + assert_eq!(max_voter_weight_record.max_voter_weight, 200); + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.realm, realm_cookie.address); + assert_eq!( + max_voter_weight_record.governing_token_mint, + realm_cookie.account.community_mint + ); + + Ok(()) +} + +#[tokio::test] +async fn test_deposit_entry_invalid_deposit_entry_index() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let mut users_iter = token_voter_test.users.iter(); + let first_user_cookie = users_iter.next().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); + + + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, &first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &second_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + + let amount_deposited = 5_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + let err = token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 2, + amount_deposited, + ) + .await + .err() + .unwrap(); + + // Deposit entry entered out of bounds + assert_token_voter_err(err, TokenVoterError::OutOfBoundsDepositEntryIndex); + + Ok(()) +} + + +#[tokio::test] +async fn test_deposit_entry_insufficient_funds() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let mut users_iter = token_voter_test.users.iter(); + let first_user_cookie = users_iter.next().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + + + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, &first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + + let amount_deposited = 20; + + let err = token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await + .err() + .unwrap(); + + // Insufficient funds it throws Custom(1) error + assert_ix_err(err, InstructionError::Custom(1)); + + Ok(()) +} + +#[tokio::test] +async fn test_deposit_entry_with_invalid_registrar_error() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + + let second_realm_cookie = token_voter_test.governance.with_realm().await?; + + let second_registrar_cookie = token_voter_test.with_registrar(&second_realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let mut users_iter = token_voter_test.users.iter(); + let first_user_cookie = users_iter.next().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + + + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, &first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + + let amount_deposited = 20; + + let err = token_voter_test + .deposit_entry( + &second_registrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await + .err() + .unwrap(); + + // Assert + + // PDA doesn't match and hence the error is ConstraintSeeds + assert_anchor_err(err, ErrorCode::ConstraintSeeds); + + Ok(()) +} \ No newline at end of file diff --git a/programs/token-voter/tests/fixtures/spl_governance.so b/programs/token-voter/tests/fixtures/spl_governance.so new file mode 100755 index 0000000000000000000000000000000000000000..84786e9a1d8cdc4ca1b65a7d3e90c59aaa218fed GIT binary patch literal 673864 zcmdpf3!GI~b@v&P%PUdHV}OiCE+GkI>?ld|Kg6h^cQ zxJ=@AelX{refC*Zl(eHq%o@IHAzcq{VR-T&@HdbQ;J_%3z- zD85^wcl&M(C3AVZd+}ZBj?aSKdLOU%@)Z1NJmIw9e){12 zsDOn>j~)$YOq1uRY4>mWM>rD|j^+*G`D{Rr7WCoyEXf{3&Asv*O({x3bg{y@Lcc#3 z-*Nd&yGZeRA3hJt{rEACUd|^x9wHcOu*{=3 zXSo_KzqmZ+m%(2+1i!)}Ll1(+;O)ZEa0bdPorZff?+Ey(&*KO#XN)eu`!YTA#py(j zqtOKl?}V!aUg&t+CBbd94sp?x&EOus+zN_>Ah=O%hI$}Jd2 zN{@?-m}zvCSqaj`=_IB{qpS7%!ln4W5eSyitb=j%nv0Cq%4b0t*(LpX{(h}~KmIlN zei{%gpMm`2sIhR7(PsS~YAxXO|Kaa9>-Q7R$Mre^~mzV|TNClj!iVyIMx(=q` zFe$R&JXZndr3wdxi@FY^;IPHZg7a(zoPxrEeT=&Hr{J8F1Lwah;5<*cf}k{&b5prp z`%-XD=JX7H{jvhiFXa2uRL;$C_NL&xgwr$N{GtNRyv^&JQc#TqWO^rgCnEGbaUS zI;UsA`9TGo`SLwmuY;6cn#y0%cVl3OxPMgS=TkYA`uzh3rJQBdZQvYX{~>vPtG(|( zfcNwrYa*AvKTc-}bLsoy^kPN&-Z*`>m)>~?=i+iv-_9x1^%->RoC11;{oqgM6wo=; zaY5%4@GtCNDDXR{KrX_5$Z6*k$XnRIMBhV>!+x}@&M9agVgE{fk9HUKuhwU@=diz9 zpP?th{`L9{{S)^0=riBH(2wc72mPVW zx1nFvc?J4sofo5@7xo{~?}$M{$361Aj2`FEv*XL|IDM{{9(m(6{=Oi+wIG;A-=m}; zIET`?zyH&xNp8kMj%<9_spFXU@yB$PXX#zjt-sIT|K?G84>Sed4uaRH1K%)II&8vy z8dZ7d+w{xKfD--qo1*Y`2% zf|XR?G&W#75DqB++XZaE<+6lv{(GND)5qu$^Ih>P1P26AX+f_xBRPou|79Xljo>uw%o(5!C`(A_KugkU;ias z|5f;o<%s?T<-76B^%|slnVyfD_5q&Sfv9P(KEqB#O?&hicEtQa{+?MBHNnpL^MNLPPE{Emr*pD^uh{#(s zPs?fNQXpq*=+1bopmtS8_l518N?upkZI*B5^BQ`^ z`LB7B=vRWhWqR|6A-a7*`Eq=3^l7K6*NruuLFo5AoJRR`(baZ>mGfSC4tr3a zkl^xFRy{n9_$KAhYreNE)pC$MD7{zfbD!2{vwTi=Xg~B&Y?ltob7@txWQdyg>3i7s zsQCc!U4rl1#v6X!k`QiDIxNL|>p!qRQt(sxY+0-LsXRsZC_GXi{H74x0eG9WzqYj~ z&!t}A)w%JL(*8Ra{1fi;(0?}nPt-gp>CuWl+$Z+Ro!S%dZ|>1&)UUI7qdtQloy{Bc z8GPw%Ua!xfPt@G4&q|Nx)$$xIhCVet8k#*&{Ym|Pl;3m&->aS=dmzt#yB5Dv6YM1G zE2c}-l(v^iy~*vs@7J&%E#EKX3mzh+!lJ|NqxGjj(5~aNMvBpK(=x=McrUx3ws2$vy*6S;^T`~q-{#ksdem!3d_k7Zu);`FtL$7Gekkk1J2UbdY z;~41oU6juH<2t%C!q!h@c#FTz`6mlK8^-`Z*bh5p<#4_>&X=P{{C@vj?ne>PxE#|b z_0uCClA0D|^h5AFxwdrggC4MU&ir3P>10swrKo>pZSW=>;tD~e~I>@`kd$>@(`Ye{58W>eOu~8J)(Jgr9GB9wLbGy z-zguWd1&8ZM^OqQ`-%J=svqa6{(P6}sqMfkQoJ1g-v$1wM@SE|3n{vMP2fh0cSEl% z*dzB)<1^t5rH|rc_U<7{X8N}vd=v09U(t#|)X(h2CeS6+j#0F@2k>t%BLCt(c`n~B zk3s1=&?RgGqS4}Bd2eyFHY%0NEdVUaWXr-ghoQJi4>#5a>4XpwjOE?(_EJ-n>ulCiMN&(TKMrLbS+rKwl*LEfUK9({&JwSUc#r6PtAdKySwx^UmXafFqw+E91F7!} zyRD(vz^cKAXZre)-y5F3?x~`$cfQQm*S$IVx~FD+{nh=xzJ5mNlQpjR66GrdPsscB zfp>tO+ttrBQ{!F(*P@-ygrW=w-mK4vCxioU)MqI64%Hu7bo&#JZbR9(?ke=^uAtZY z9C~%vOs@wj==EI@5b`t2edPWUZ6_ybl)vOw!L$DU60|GNk1u?7{t~p?aFy!4 zW^HFnq}rZ6Tnzl`<}XlaSK#r##S_C#Iv(3xl=o3H?2E+{O6`(dG0)lTLEAr&ozVVe+xXd%(dGk$ zy8y@h`{u7;{|=W_hWjvR=>&c}Zj|&60YiQi^oO~>JE5r|m`3GHUNr$P=`Z!mrM_Gr z{;oyio954()Q+svm*LLk&!C?pDgRezV4iW2zHcd=BmfO=vOMnZw^ELBr(_FSRuO`9 zak;H@H@q32OX->G_Y}cDXWX5^8~A-c?2yH2`Tdwflv zmgmrANzHUwS3#FgC|y1-_q_JW`iXmx$v9>>U~+gmm9?=Ib0t%-7kIi1)pWVpt5H?Ls-8A5av!xcLFlxAFXdUY#GX zHSOnS`(XNu@#hv&eLbe>)@P*vB7lu>GO@@aeF9II`jE!bBG=ZIM#nM|KOyv0WZAiQuz^GtNpc` zUZc+hh_3J^AP`;40?5xAKe<*OWqn$aen!oT?}bR8uJF$}aa>h=Kjq`A^FHJHvy!9B z;oC0H4qqsi=vu?~Dt&MGUa8M=OW|8uezUx|VdglwC+S*Nzm@eXn7;QjzDYdq27Jrc zc4C7h@H1bNX5ikb{Iq_n(aq+!8lOXzpKv+8JEx%#FosF|7(UmO@!HIIsoWTTR&KNg zaJXE~Z{=G2l=T{?XUXYF|LV)>+XPTJpmO?v@?GmUeG|$#r(s+szU9q$@8cZ_-j(oZ z9gq20ME}|RgRp&tmXCH8={S3m!j0#{P<;rj_|1(z@BKHTkIi2Z?a6lUJ;EVg-^BTN zo(m_?x*e38nEylLI>C$aXZTF_Zc>J{UP$trp08#8&+JzdKEs^Ps;bX{0ASSd~1NW#WQM-r{8^^0J8aorF&<~b9fKn+x(oc5B9Qc%tWCR z&1*nDl~*?}0P@3p)A-+VnUFn>i`u*li)WNpDSbi#LwwwW_OziW3DLHF@?6@W{`&Rm zx7xT@(xX;<=i;p0k`Uge^`DRTWu<>S4~gW6F>8TX#Pi0Y8)_Sa*e9u9(E;XP`9 z?k!5j(t7pV+kBsSI^U;xkJ!a{zR!w5JTK_OJ)ZA_`bO%%>fC1Ye9-T5ek-&G=eGh~ z+&mwpN3P!rd^5j>wSSuLDEL_aZ#3hkEIKTv|NJB8e|LVXzZJpp+o|7}+Y1L83&1XHD8n->%IK_0EWN85D#qw_Gc z=6wnN@q8c1pN)e|k8`~iP`$$2#-qH;lnyg+XL~R0)Z)2gkzTr8>#-8`h_wIJHa2IT z&mB|{U10~luX#SsVjK6M{l)7OcAEaS`5ihh{XJTbYld0QMAdWaP_JlSAN1Zjt>3&s z=tY%>XrAiH&Y~3L<_SR`Me}we|DCEY8-b6T@ADnB`);KR*%!WQrb|~Z^smmNj{wG- z5A{{RU#9dZDSYKqY$xco@b^;wOY)8EL8)E&do${9<6F{qsMmnD`1E|_ z>0GrJXKDSL*8|@-Np>&Jp>fg+l@6EVeR(eK@w`w{R)Xg`#gmm6UD4gRJG$;hz0F>% zReQ0nC>fo-&^T|C&iC1NNWP=~5AMwea9^+=cU=!n>%~xyRGb&`;^MrJ7Z>LReO#PZ z>0xo+iE5V?_eyzTKjh2J^MO3M`0ioB!_D*Ar_by4`@M>1w?3=9#PQuj`X2rAu;2VE z%QgQIeZNGXwSV{m+AD4%tgoJWG|OIX5y9~Fx7n+sB*M;K9h7=m|2}+RzdR3Rx8_u_ zTi=`N+pW1`57Tj%Ig(zBKY470-C88|Dg@V}e%g-Xc|W9&`Gwh~mXc(XXBPO}c|Ys; zEzxC{+Lavp7d1l;nC@rQ)lQh+o(K6Fv3*cEUIF>fw+}5SXTSuQ1 zyrR5_wyg&p&P&>dZb^?)_TgFdFY9I>p49%Tjwfoh4=ZZ552$xM4``ds1A@Fb`v7@y z_5pNp_Ce{9Yad__oPB^iIs0%(=;`dkUVS$E0C_Y&uA9fY8gilYRc-xOHT&S}-B$L$ z4?qssk0kxj?fOhgT>OwUPNkos&tLhd)8}mslXK_)T;c0+_0QCzzk90a?{g~jcW;jV z?x|USzlHo@Zrt$$p?g-`{7TA4`$oz8(THn3IV)`khq8Os<^%nf)^^%Biq_5N(5<^> zy3MMf+vh}J%#S|e`9LXu${!0p(Khs-EY1?GP&+tMzl!!Z%|4XYsy^HRxsSG?{e@vs z5~6KrpQTXspxJ@0eIgHOze=0n9p0_|+V-Uebasw(B1h}jzBNP z>!&~$=T}jB>w-=*drT2$UuQ|U;uQ1Nnm)1{RozXsr(@$MkMbE9TXs?Te|LK0} zLP@WspZfP-_VpZVb9&BLNA*$8caO?#JMK&mz6!dIljCS)HjYM9EMHOHpSh_Zck@H@ zdeK9P`0*nXUHmv~$9T`y-}-*#p2mhC)bh=*5tlb`K;+Q;M7G}4^c(ko@1uG!o;-xk zkEg#u;JA4muajrffM+!H{yQ_|YAC&5ZT`#~D&%N>jvTetEJw?0l%o#G zcR=AnE*zar{)+P6=*)b32fkDOo+S4y{$5A691z!ep_|jK1 zUoNWP3;ZC3;9sSGI2!c%*16oyjtIWtu7k?IQ$!zx8S6-^&Br-J?cdrn#ZhzUv!rJF zoKiubj|yE1!Jyn(Ps|}qd0fuzo#k-yLHWIa%jLZGQP%SqCyeI)8m}P!Eh99F^xw^&QF(~x&uD+Z z`gb}HJlvr3W!BhynQ1~FvRAlI0pXZ$4BzM5*S}ObZzlQvn?H5*=kJ+b|3A%}DO3IG zIdA4cq9@ZSYu=2-PdQFVTL(x!&=Yz;(l~oOf4&HNZ~M_iMG{cDLft(e z{LRmp7xzlVyL6p!9FN~RTL6bWfNycHa1ia$`SJUZ?|p;-UGy{7dH{P>2y6U}A8}C6MyYU|A@8am7 zPwnG9@Xd|)w7tB5aS788|9LQLy!SC_XMVf4@!luNH{tp>XvfwL!Ur%;9;% zy<&0nJ5-;nMEf#*(l%y$WgK10O~uhy3^$GrzGTJG+o?X`%7i|d0laLynOYaE`%Kt8 zoH&jF1oc<>syU9nQTvPd+>4)E+_w+q&sTb^QTWL? zy2jyJERIgke1*F}-%<(muyy0sJ|c~ahntI%pUzX#Yy>S?T@2t8-f-em+m*Bf1}Yv?38d z-?$HO``4o$7C&#c_z2|0#Yc8aJ{KPWU0i%b>5&^BfgN`75y+8?j~r0=woeA^id!EI zIdt(6$Uzjx&sA=8f4s0Ca&PnAZGW^ElbzzG!Tq_y!7Mw~n`@`0X4)x?n})JabE?>< zXK7C#Hy)pxW1r^KY@epH-KoJoHE}+j-`d!4tJJ$dI}~w?F~3k8U#DizFU(HW9A7tk zQ#HO0xnsUuTvz*H@%2lj-Pyhr@%-qz+l^+l?-AP#)%&sCKznm`1NtG1?FQPjvm1M* zJv+Mr{gH1sP6xhqw;K~cZ=IhN9yhzuE%kMF1NyL(vK#9qU)pZ`QrcDh?8f7Ociij- z>Kn(^W4i%4adrc8;_QamiQV9LY=7XVi-tY#3VPnf)y5>O>X_l4skTpS(kFYQ-BI~~0^y7rgr z?pIO$kXoMrdON?$VUc&|R{>p|Uq$Ira~%DMz^DD)#BT8D(E$sL$AJ?>2-Yty~YVW3IX<;h}ZW~KZ`Gxvv%rF<;k<#PhnR= zZts_8iwlniy`MSD>A#`mvs%1-Oa;A{=g@me&Gdd{1-)%wkB>;dxx5H;wm4DwHTs-9 z7sBG!_f(HtpFkjNe`Ds~P0YV~$E`EsXS>yo6sdeJ_f4l{#jPhv1x=sD>j7)1> z2D?S;9uM;e;rje@Ab#^mWt@5r<@e**!A~mnIg9p-K2E*uu*jEh=ab_gv-^+#nCMf- z{T;qZ^sE-AerSTO1K)N)@U-}JS-eRke;NnjegpG^<)J*8)`4$3DEW>5L&cw2j`_P~ zv#5Tmq*l z&S%i}@gj&fpZvY7aZ&!d?I&jtKVm&+8MUzz{j^hwS0SE}j}Td#eF$hY~YT}|4rjj?$w%~c+6KS-c0S6uhLTJMLYkY zv;_JwvbZWa7P);hd>-%FJzPc!blE=FdGXb72jnVsUc*%R+>5XNLi&B-rNE#34B~GX z_Ws_zBN^k0$O${mg!> z0bRoP@LPIs=QZ4~`e0!Z=@a|#-P<${ojk9B`XYQe`-Xit!nH~dwSVPnkk9s+d59hv z!EEy zzhVa4g(HHm?PC)T!p}UE{hCw7ew|Zczvc@3wEdbR>9yFew|s%|oGkQh9D}%WA-D?l zYKNT1@n!2*X*+IdmuzCMIA`wqZPhp7FwSjQ@qNO}&hxnpc$A5zeC67U?1Havll~Ryk8W2zLCTx;v44I;=XabQ zZ)^C4`1O5wroaEX=;?3u8w{nld#dQ|TPOMBj@}%--BYvP-uii8Z{vK1tof~*DPJLY zOyqqu{J9r-bQ_9Z)#A(ZE9kX8hhE(^)2mcLuaAj<6oQY)Jshz=Mcaw`LG#bMMBKUl z{uH!JH?QW9@Y(rO_Cqhm{uJ$>Es<&m&MsajbgZ90<&OX_=}$@Se>d#&E>#cJe15|b zslSUegFY_Ktn|o@GwZk~KJW6y<4^e^t&2&YclmB%Y?eOz+;mT$={dEv^hXy~(QDs$ zsjt@-<+RgD9KK(k!;EtUmQ(qK;C=GGp7U2GKj-|I$0NRcBDFK~ z%d$RuKkKs>Aif;EWH|9<^snOmoRab74KBXiO7-*O$LABD{PP2n?=SqJqc_V3tNQ<+ z;>)j~`qeYOJb~!RbQ)?MH1EgBau#ibejh5n%=}U*337+P}58q2kL7pTGOS zOsZei_;Mg{C#nCL_d(|#LhbQo^dIB(&F%CtT`Xr!1c>ptf!dM9Ic(qO@*3ph_dokO zmA9=3{igfJ`0t;h_bp@J&S>TCH_rZYEAQ&>QofPyH-0bT4yAk4uigzj({biLc`@RB z!Mn6yt?Rn;$3<`qRz25F`PPz*Guye&x?a!XYjGTTZBgoBapclkjSs~8f@6G?jxTqk z{#%HFblG_Y<$L8ZNX3^|3;QJA%sJBWWdxkV2OtM@9*O`8dy8^+>(sEmEEQ+o2!Bn~ zrGAa(KB+m*Tvd;Jm}Wk6KM4+V+h;Vi^){P<2ip_Y zYc9?Vx>w&H9QpkI%ok}q9KM$f5MAMAfL}FUutoJ@5A)PUr`7W%~Su-eb9q(JmEg*qxf76i?5Hd`7z%I zz8kduP}{YyTh@IhqE!6&8v-}7__4-+qXm25x3Yb5rYc{D8BY%Tpl?ejDxVwF?u~_f zL@Rnw&OJ&WJ!iUfPts2GLch+!cP@^s>zT(WT>w5PuS3369C@y&qu?RD&WI!Hdgej3 z6Bak<27amiz?1Rhi3dT?VaJnUKU_R{ztnfQ@#HAp4_xhkeBLwcjEf@=D*U`SGUU|7 zk2D zu423JGT=L6yP)klWfvevaU6Lf^hLB_x75eRiQ#dx3+qu%Y!`Y#$CO=w{fJU_LECHH z?84J%|HsWPpuXvNGUUhE1;~%H3!saeXQcG7eJ*sKk+Tc?g^q5Y3&@wV3y0*riz5%} z^Lofx{{j78$1DAP`fPSVR!;K?9_-&`hhl(SA;pLwGPK+~# z8ede4C+|4P*WbN4`n&dc@>lly`ul02Q&!w%ALT0qkIVbfh$r9T(QhbvRf{M8c?G@J z=g_NL(rcMFwX1?&e<%905IiXNk^4;`|JCQ`V_)$4`%Tb3!`N?v_LBCSXggdY)%D`Y z*F#U$&2REnz_W3A-Tfx2k5YaU)kDqNKOHzM^6va5sz;ht59xl)bdH4Rsc7*^+?$rG z-ZH)P;^~i$A=YvK=nPMfx%JBL7RLJe(dNbc>Sdlj8%BS$S{!*|Mf+To(>`mDBme$h zU!QUBo1Qb`$gkpjb&MkyW)2-keiilqUkq{NpL={9O0QOnBY%VTGk4>NV~-<0U#^XB z&q=-ms;{4Up84zI$WO`hXvUHE)kx23apVUo=y~jMS{(VF3c4J7 z9Qk7vbg5Sy`9ldg{GdGBJa%p;?8#!i`(Y}-5cJCXdd898^b5e}c`xpK`pMEx%9n5} zA%AOfo$?mlSF$&~zK8X`?dQw*OC0%bz~OrAC;L(NIPxmM_wCPa^=B066_@*QTD!N5 ze)IF4dT$Fz`O+1t-!MLZwqNbfQd^m1-9=RC8ouHHH=UJ4-F1^NviGaIQ zZt=N;yq<+n2|^SbOqz@LoX+2kBeRC1J z4gaylz00BEIqulv-?mSrt@Go0{28@>7ym}P^5fg5e3j$h=s!0G9~MOX_b;LMEn}CE zWK+G?0#Co)AEtI6ZpZgr-YV`t9ryS*1a8FRI9*TX;sg*BI)7c{AX=g0hl$Wj;dX8B zb4W2T9Y}xhRX!K@c)j%mU5{pQaC+vebRps!rr*>1w(ga3-M9|pp7gkGAMjfuU<0>4 z`YuU``^n4kzPtfgn$o^xt(?ylX?v)i;^N_^wX(dBDL z`8it92faO@_TgN$5AFPx?1R!XH6O{&)g`^mSLtk((-|tK+Fy<4tq1&dMadV<>y_uy zx@7#j2l%G;&G@w78O}ll;`WB(g4iw)+N^k5HjDa+`_B=~qIbUb#{tjmg05Rh&y&ho zPrdOV=w|0(ckRdXihY0^@29#~o;&B+e%^beej|=^r1oW1I}*pg_bL31iig^rCX0VV z4%|9w?I$#;f3bfM^pE#tRr!hI9FP+i=YW2AG4AL67yq7Rm-6@X{u_!7I=h7Ni=8t# zlwF!r#V);@4(xGuX>N{Pnp3k~y8knbXLY;O$NBmX3qKnh{!|)7A$XhI%k9z(gJWKA zy$*0JeqKwQ{L>?`8&%`vb0O~|wHJ%gPSW$Ij`e(Ov@d5j(4JhJ9Qwe;$6Bz_?aIkKgRR1bzTz9|CDl~T)Qz*=p8NS1wO~kZgc~FY&Ux3Ic+!A1K*V0_-|=f z^|KpK0N!!48>nv_ACK(@ASgDx&UuJo|@c*<@-&Rl#Pa^>RV2Zf$4J`Oo{ zb^~(h=1uj1{;}Oq`HAfYpeB=^~XQ$>-GF~)<33vqq)wSr?4B{hN4%s zxcCPu=(RqFUfng*>+==#;$5VeE}xZq{r2(x6Tyf4XOQp2I)l3TQ|1cVf!PJ~PsQsC zRuv^fyuM(S_M7eeA3aYkS^_xEpQ7hu+d0F_@qXm~ls^=D96x`G>ZMeiT=h{LCqD%J z6rYa`{p9>9s-J!b{V5lE`po%L-Y1On^`!YzPWRepxU2Sl>%uDf?VO7Cx=8q*_NOeA z^jiEWZ>eanq{!*Y@~2$M`Qm;nRgUwS{2s@By`Or<#V^<&Pi7`}J$JZ$vecXXAp2%; zT;y%Qv&y>A4jo6keUZnA9J_dOAkSgOdeC!;E`{Lv=eeNKm=EyJLMj zIX_2^T5Fc00?S7{{>k6ZI}m!oK`YFhiH^ z=WXXY`TGw%M*7F%k{nN@e?h#j!N376_ah>QPHrEN=h58H`}P{?T`k_fzJlJ%bLhRK zW_tg91-)$^gzo1JH9`KiqQGO{%|_Yn*&p+CR&Bzr0r1DE&{?q;~Ei>!T-_ ze|1}LjefeVcl7PgZnYmpDxb^!N+Byweu^L(+WH!ekH_n*yAGpYwJi{OgzXlmJ_0>> zv#z`5bu=^~fc3K6$)C+Xx!g5GZ$B=be1A91%jbNo&wpp)(Zkr^`&M3eP{;kfuP1t1 zJUSeJJa(KaY$UxgAckA`KuM8~@1hl$e;7@)d54hi64)R3=QCNqWy^9a=yL6cT#E`tmlHs`!fWC9jxJY!`L!&SM3>9uCi5?f{Jc@|pNaJ8R*tSy zJm-W7HP_=eFQ;-1KdX<{BQ!cC>vQdEq+nN%^Yz*40XymHF+<-2U!F%&q@Pxg(%UYT z7dK>_-_7*5aWT{Vv0CuG5#`u-Z6|_`{LI&+HMn;IZJ{gYFnp$~K0Ig4xPUF(Q1ZZ> zV!Zy{$4luJUUiui6b?WxB8`7dQuvX!gRo!ay$RzIZVz+lOMkx1)1PF$gnAT$yQL;f zM=t*%(r27N=Yfje8*2XohRgVVhiF3ae97Or?HRfI_1w?;nDipU<@|TQjO1jP^EWK6 zUi-cUun)Fxf$iUH_KEShg6xsS4YST=|IaTmA2EJw)OqdxzWLvx_bp?W3n8=Y&|#{# zA7}jo^84F<)^WU5*Hx7-C*sg$>m^g?Cs*CqdZKW&5PVeNm_Bjqq#-vZ$6Wu9ksR3k zFPq=S>7V>M_rs15$LRe?_k~N%|9HRPW#_BgytHT{`WK=3X^Sj{RIZdx{5e}5gK=bI znb0hsd~dl7^2^VB*}fCz&n~TfK+gP{^TRs7MgBaH z-!zgurRISsf9i0~`%9=lYVEKd`yyP-?KmEHiaO8qU!2eR^5%owC*mgh`E=5Yv3?rv ze2}W=yeH;^Xt}9#-Z$zvL;Wq)_d|gEX3YoLLHcai^FeasddIfkeriAE#X8QQF(Y4Y z{)6tfKjQOw(Z1cj%7dcM+`h`Yp%0b*@wx6DMZqK9SD^#`+-RQa&v!vTrPslJ5AA%U z=kr>8Z-MF&vO|11dgy!*JEyl_+v60q7wyPz>!V|PL9fMLT&ng0*{T15?@Q;Se_48s z+KUSShy1mm&w!5qW)_fpQ#?PUPu{!p z-h1^KRpfd zA#7S(i>~kc&7C(FYKlyeF^F0c|)u>lHu3NyWs1MR`zcXK%emXCK=yv*Jo1R;$Nb1 zs_F52XkCZxPu+c>(uSI`9u*cWmKM?$~;-ot$Um^IOydRDD)|-6#?K)JIZq??4Twg)A^*MCw zu9FS4sI(HVE3Zo(b*Do$HQvnf9ZgeMYVL z&iPSvzx}(lUpyc0%lF_OulLdQS}kz1x%D(RDm)4VatERi=zjaA|LX2XQN5D#qZ}4_ z%lD&zE^hvZ(&Kl~kMhfZbNbBrQF?_DzMiyx>A#=m={0Sawe(9DR?%xerm>LgmoCa_ zp9^blpD(RwpRBzJ?~HvCCUCygd=KfqlKg#GzGHto$MfR2bbC?K!|l-LXPyrQUDk2t zG%D^;39%Z^$a?#%=Wu5@6nB*G?Oa-Z{}ipL$&Z5{RQ-o~SRCEx#or%(i0lO6$*$*Q z9L>%Dm@DPFIQqr%Y<@h3#~P&&pdzE8=RchxPea+qYV$unSRqIAbL6PCW;yx-(X|#o z++NPN6MS;?hFmy$n;c>sYV>CQ?V;}*$CAOP%lK>ld!Nt$K=}~0q;@;-4)nvf&zAah z%%mU_UE#pBk{-=OAR-)ivp%1!@877;D6fNfz*km#Uq4L#RGV+Iyn;W2IsECXnLnE< z`14h%S0VVa+(&~x7Yvg=)#iu1v4TF!bLg|AX8Qa|1${6tq!8>9`eels|M*)@PaVtt z4f_-NZ_*PU+<0Efc&Uf^&7x-Y6WY9#W$G`!IcHwVD#)$1kMeu*%v{9-wtoWr zS7g4#kp8@-^`I+T=F}15WzOL&UEFZsr`VrnI>cf=Veb4Dn zP`d4tUCX%uR^D6p(|5;xUxYrvw|@H~Y!P@->bwBxx77Z2XG`{~@o@9+l{U`?zFYB~ z#l6FOi;`gbF_i9Azg6;FfL46x#% z5ZSmbj*r|S?~UK#mT7qIEy_K0Eu%g;VZ>@+`MgLX&c%4XRdR<6*%i?jSPwICrKqCIV z4&|oe-(ACvf5Q)v761M`joZT|Xn?W*X9mi(dDJbZYCF}TsGU1sS_b`L_NZ+_cKqAs zqlGuCUbs)`Z1ds>JeOc}O~t|0UWPl+Z*g(op9>$u5$*?V{ws@b+d3wTZ@cxaXzwo0 z0sY|O9BBXfaSn}tuh;r3Uu!-eVZ|QU)orRrpawJI--F1f=LCdTC|}!^-WbL?`#}6; zy0=*TTlpJq2c6^icPh@&Bjtn^|1K7#fM{Z$q?d}xI7ct=x&nB(bzV8~@7Ew-ygvdd zE5Q?CPLUJN5otf&$%Dob;&U|AUffp{fX-ed;@>sLIZ*F7&N0#A-+QHgF3thF;^G{j zi(BWa^sqR`MxB=xpAP_eb8!yHmy2_#J&N~70N-7l1M=zO94bF?oWtyq#W{9^KXLr~ zus*+d>=k=FSpP2j*DQPWcPt(idfWQ(Aq|;gd$kMWqoMplbE^0kuO~@#_Gzw+C(?0~ zIg(yW++^+l_3cxYxHmOtu4t?$+ojrZd*C<^U)&z}viUByzhX!}2EO8b{CI##m*1}! zd#B@JruW|r$38&a1f`Di1a4_*!al_PI>f*2{FT@~EFYnMRDBrk0Dql6copo!|5818 zji6Qgxhy)rw{$t`6U{?ADP6AhvUyLJ18!_LI*O8D=La}D0X>m#C#C`4`6Hymiah)9 z5`k;_+4e~Yw7g_rt-2Y{#&)XVa zmKz7(OHCry&yw?ts-=SR`~5V}BbcYXlmzW#m`v@hpJ zL3>R5QM8}eiuU3BC>sB+n;%8v-=_EK?nhC5V)5_TkD_`f-v8jRvGD{qmuWqd7k)sB!hPQU7U57nDNZoqoFfG{1nY zADn&)v>#K8O4V-%^yE2X|3vCh z2;L)jjE3EM*lQ<4*{y2v`~l*dv-9&sKGNg1R!OgA-1cP>IpshKWo zE9g>Gy5PJ8TPK&)19AJlkrW7B<@s_Wd4yiD_H6B&_1224cCG#XmiChbK&)qUzXL0m z^-3$3(}8kgy-7-q(@p=e-kd?tT;4mVymQ8$6ug1oYaH62r&J<)8LGW7KXYXEA>Oa! z?a$Na-nk{$%X1-^$jQ0ivmRzmnm>POVFK=3}2J~$CVtr1YLvgSA{Wnyf#~}Lty@12~xQppsxBWF>pTnhq@Aq$ZC+0D< zlN_*{sYw6t)Vn)}0(LdpX8m%=FR$BuJ>?D6?u3_81?ZYZd|gO)+pj;=^OYJKII2$h zFO!?B1Lj{WkFz;_CekM4Mi9 z+wTMY*>H``t0+plXZdTT@2$VV^gn^*$e&k{d_VTvQG@^XUuJ((T-d&aV9Z3b=i7{##F@ z@~h6LKzp(CCgS-XBb--Z`;3*B5)z8X9BSXzAGUe4{(Oqhe~#x@SG@lJHwb3o7SZg#F6bn&Vh#m!r9klUO5qX zK23@)?f-<`jK@X0()xI16~Dnz(sw2&Bc5+j67i9G%_hC<#zkmAS>vLaoG(w`+~?qp zCA}8w8J)jXKYg=9JQaoD49Gv4RS+i6pIBk@EwrCf>-iJ6p&q7}S$}T%64iU9>K7IU zx@>j$UiTdYEZjhfLOO1G&#LGzFIRmz)x5&LJ9uI68`@{GQD^DbOGP0yoHK2W=X z{vsPF^-#T5748DnbL+HT7FS!R^|H8{@*|F`brz+ZIIh--c?LFrBh-Cm?L4GN@pAZo zSM*J|R`urD0xl?DihGPVi7hw8meUh@v#U?)8*LlJUC$@7{gs?P#r*N`dgb#bEl2r9 z?jY!A`XS}0zl`Tg@>RM9bSYg6dW2UYJ!)E?uou1ZTw0^^E#mokJ-}}QzH{da>3I|j zwf;aauzk$pb24bTf#9`T>rc;oMJsV{qdiLaO(D?pD9moW2lmSR-l_ct=IMR|3()_j zd5y3Six1#FaX;?c_JL2^QD5S(Ja;yk{n;(`bN0vV(H?x)54yPd7D^ABZ_(VR`5?bh zQ?EYn1Kr|%2h6VJ#nm9kZr;Uy{T}uyOr5{2aue?_uH&EBULDf!mnc3*^!bQBkG{QP z4bFON?!GL0^#Ku(EPJ&e!(I(#r{+|#Q_U52YOaj4(*CDUxgFzM?me2U&MOU&X-aBo;xqY?9DF7LEip5ruUf-w;YrGfV}404{O(# zK;F!+f6R76&!aeIyMgxQ=Ix<9xp{lLrMJHARwA9%uB(bJ}jK2c9Xrq32Q5&2H#<6vxeOpuTCl0eNwD z1M*_ymN1@of$>WipNFL5m|VL7Idk(dAXjd_9@?Foj{!M$b^~(h=Ig1v#Pju3ZgTC$ zLGY~(=TdZj(dqfNhC=RqjK8KOfXVU5Q2M>6ihjTKfBbPsZ;pQNsad~o-Rz z;+LB#Um*bfMk5Y!kw>?fUOUs{wrcY*=2y^beGa|4ho)D%r~|R@r3!jIBQFZU!*Z{` zALbUp%lsXY&C57$ei*b*=Z8UibAA}K$8b$i>Kp0)sMY;2S4%zW=ZBdOc%~Pt`e9Hn zr_WF?(`VKFFsQfbt$aVsA!$F(4`ccU{oJ%42KvsOn{&8AKiPh(QM~?T^!v5uhxy(k zPTx5{3<4)v{o2o*G(5exu!`RM>aTshw@CP(?$<7q^jiA0M?U83J?_2JbB5mg1?6iT ztK+rQz6DfCy6PG4>U|XB2#$BL-=6Po9|Xl?X;I4cHTWB9h~#aO>xP zL!$>jj`%tvj2;R!rZ^!Pjo2+&&m7Ium|^h@-&n^s5Zaho(egF9!bkl>(FxK z*@KT&$WaUEpCLyN3ccX37!7*eRU^Hs&2LyzL9fA_cGp)ky*5&^vKn#Uc?`7f;vu z;!$2a{hsRabY`8cpJV>LkNH=(czRLlowZN+ZnYmpDxb@}^H*8%^hr|TFmYam?epaJ z34p$%eWVZb2jO}>r-Jlxk)GLqVS2EI={R~Lw$RpZr!GU$l*Z~NFi-mSw|e#P^-w277OhCMgGn#Jj&W*sMOE(##?OO`fk z9Hv>vReCP9o%$S zev<>>OFT}}eFSQs-#!iPLH#(kZqJRA(B58%c=g;bWQ~*Z_X(Ibk@#Wz1lYN=yN<{> zaHxLnN^O_Sz^r{M&m;SH%<<}W5f9NXSN|R3Ia&BV)cyc}#Q8SkJKyfG9w~P^cymZ! zSscLhNzL)Tn18 zGpV@sRQcSSFQfbAUkd!GJ&7FJde}VpDY!aM(X9tnzf!y&RQ2EGC_kD9KS-_n287#z zS2}L}9g)xQN~MePy=J_-RIgx~gGU#Qx2_n3e`fI>(B)p`v&Ol~r=mWoc||jrduWe* zk96OG*nX@5zr*+NTYA5^2k`ILe(1s?(rw>>w?SWrZQ9>i+zY(aF1YwQ^mrV{SNm7K zM!?1Aht_X@G1xC2U$9@_S4MKa!wRE+(nh(an^NoXN0Yv z%=PN}TgG#;@S|}|o7ATeT!nhI%jZEHrzXA3FU&r*v`aR5=A5~4YO^yt!T+pz-)u*0 z9Y5o>h3&A`ynrRcEQ)Tt)$od^_|im-HvvjwO_!8|JmvBwuWEGIv*dN>F-Zc zlaBSbjz5Od+dWnE_O|DIz1^Fmw|i>V+yDGgUvEDF`OomLf0ptUg2&|jX!zILJ-Q7= zuWIq>+bZa_K8If2HPh>FD(FSdG`b4GN8~^7Vq6x!MFK2d~2;) zzy6F=sT)V+^X*B=cR=ADO2j9BqVdUv!iUkI=Vxl9XSI0nhbrhfm_yILn(6t)3VK?6 z@|&WEMuRTPYotrHxNTHHm*qKhSyD4yc2v*>>)hjY1S6i`u{9xw?~~^+V?FnKsr*8) zN#56Ue#>kB%lR?O*NONC;D$Dya)d~E6xmk9c_dij{Q3t zj|x|7T)AZHp<%yiAM?XplFj#Hz0T$M@#c3DUxtb|Fa46EFMrQ;$%;4cXFr6V`^fqD zvT+GNvu3k#N$v6GLqb2FPfRbGCn)LZcr)~4v|@kiyX1Js#w%~8`qeYudr2Zp zNUuZQI@FIFuaA!DxJU3L|E=6Z>u*}Td9(7};?25lIgU4PW-1e1i*h6S?gbq62X;1n zHARQr+%F*}ntXrZB*Jq$zB9k}GQy8NVBrApvi@-#ZzdldWeKwOr~fMR$NbjBbjdeQ z`-}5Xj-3x~>!BGRzPP>JL+#Dh?S+Hrms&o4-}EW&Z~Tqq_tU3Rdds-$xwy>rjVzxW zzv7GGyqo$Z=8v;=)iuY9Y(4co@Rx<%0ybVx9csMIt$+KlWEk;$UiGIqKRhHU+O`k< z@)hXMM-v0^Ke^8FY~UB4zf18YCRFmg_EM+%0at0gLao=f-BM1tp(qJ<&X~n{!+8DM z9^li8@7%s>cS%Bc8{|2hkM|=#SL}Ac8&o}4_jAQi-}L$Hptl<*f$nacv={Y{$4N?$ z+;I~4<^1;APHdc{=W|6}hsA#Qdhjs!&o$1-`bOGW#`@T#-s5(Vw7=#1!4LLBn_js2 zVdw90_)JYsQh!???e-Z)dk;G_ zjyg}_jkr6OU)iF68>rG_Gvtu-iVv zwk|q(4!f<3j?c-}xbi%UD?@JFdJxzTTMy#av+WlC*gi6m#g%RTQ@jto+L1V(47qag zWVJhSJQ@6UaRb;X>yO9dg*cwv2lD|H+rzkNz;)?P-!6gv)UE=_dUHZRbqyfBhWcc{3GES3D1E2EH>r z74{twxbglO$e!Mh-t>07AN^~gujZ+|+C0Z&-j5#jbp7vFquq^gKYBOs2<^u0LyvYJ zUJiOhwtq%PQ4->~bO-cdY)`7%2aPjdK@6ZP9Ik!X2z?N3({`P*6S^;b*Lujq1m*8= z?L!0XLzx>VU8U4{B`X2n>_o9B`J##4lAb=VWVNKH?ZojqmmP8&&tF{!{8Ia8n4PG0 zUP){xQ13X-9G_PL`Ehmv^5g6T=;GqcN{?JSu?O^u?Zj?*c6I{o%Eg!W>wByh2>bWy z_v)YOxABO@mwWU*{9R$ZzsGX5V~`&kzxaBjmT?F7`%SNZqwMthQ1Rub>6>_*q5grP z^!mywdi~#i;p_F)IeL9%&3gU0LB`L<8BYuSvc?%dr+kIrad~fk>5k^PpzC%$|8?FR zJnzu+Ul+{A^Zk1M>*6Aw`_#`=d^y_J9CYxa)|2tPkcdWC2h>UC_-&I%*P-ZH&2PP< zf}YEB=((h3dVZyXp7cOhA=n}J`km9R>!LTJeMBn`K<>?-GN5|G)_IJP;)C+pxX1nI z9KTAa{ZZRLqqKH5@ZW&%&7b1VZAZIJpWA*Ic(vj?=U=%-=o!}S-1aL0&-&4I_phkl zv3={e*}Q($Pw~F>;Dht8fG%!cztZD((7*D!veS3Yzw&NjtglC{AA4qv?Q>2QeK)6~ zea_8kpL1$%pVxcs)AeJ~A;{8u*HC`;SFwib(0)lcut&>#naKAtYF|{{pmEF@@>~e8 z4)(>MCtpz`ABt7@aP;TC-I<-khhoiqnC}f^PG3=+;^@-M(5uw+EGOJLPWc)XJ(iSdXxWiO0hxr(dA& z+eCXn&m`aPdj#^#^IO6aIz-WA9cQT@H}Bl%ayu19S6S`q`_CvW@$tx-lc z!Ha)JGmv2EjMJlclnB!x_|H=wJ=xM9LbmvOK0}W$hWn|%aBwZXr0*LWsN+FbW5Y!8 zgV}uVX@uvtt0u@h{=@B=a~1-m`S~79r3RDNckAQXCHO=mCvO_y27cr z8{IhH2|r@~Ft><~N>5HdQPPQ_bQSEq>LGu>jc;r@kPg3WA^U{u56* zJdKWA{@-r*(hcvOQjDzIJVf$h_zK^BI*?6Zo-&+ghz?QL5y^^RW*@7LdP^)P>ntxGHq0soE!{H7fEPZNAz_sJq%3*J2mxXgdXd)mfI zydPz}J^tSKU5~yhx1rhpsZ>$A{C*G9o9q80qUS8akLlYuj)K*6(fWGOw_hG*zj)!# zfId@YnBL5%MV*y+E%_eynP+%hZ~m@r+<#}nN7V{pDVaN%0J#GpValywz2v3d1FR>OpnmMV?sc` zy{}m4=*Rkl`JJT~iWgVrGkx4i^)>npr5Cy>UzT22Bk4?~q4mP)RrJD-9v@mS%+1gX zMwg-V>n9TJfmlKG0WEwweld}cSd~e~&m{7heqG?v(U-%&_S0+7TVL_vlU_3TiwI6E zhePO<-d9)hnLtSU?@h>Mhw7CI`5pr9w|%@$2m)3StXGn77bWz{f6%kZmrs}CMlZbv zy8M+d=Ts@$hC%fCMK#jpgZ}q~Kl4}g`E8C~-2Ph`f3-`j&x@3=7JWXDfX`5~?8Svj z_ZbYg20QeT1YFjzS#Zxw(EY(2x_@s^n(ig7Z=3d0{C4sA40&QYJ^4d!A21ZA%6+`;KNy-;M2zv^*zD(T^V!rjG9F~(j`<84UcN3mgZ>ATKYe;*r*00yOC@;2O?RaK- z{wwh#OFw@_(wWN4FYVVUzx{sOKZ*Wj?das+f4^SdpOE{0%adukGG2GCPp8+?ulNtb zdlsRykV+g$zhYWK-?cH_iQWv4=`ZKk4AHN+#-qE*Pc3rtIl|le53{Jev#7k`$jj;k z-mh1AVK|Kc_p8XuYdyT)^F_ip*&b@Kt4A(!dei(6S$6eXZ>h{j zRmilfUrXfUo(|*p&J6rG{r2~Ic-LS*Zu9l1XFvXg;QRW14wYMrzF+6Vqh`T&I?JBi z@t+?5cTgs}*dLu7Z;a3ApE11N4UT?X?>{DZEWg}8j^%0yxVwG*OL$Vzg6EzD+;)O% z`j*T2Aw8R14An1u9nmjK@4Q~ptLvS$RrJm^RrJnOPw&(s?>k73TfO{t@U{akJ%*EE zKR)@em+xZcCedxS-c=6m9HYju;GNOc<^?c)cid0kDQnv%FjpM?{d_w=k9NRz!uD~p z^K9(gIfl3C8IlKG{~axZo{zQyFRQQdv25+dvmYns@Uc)MA6tLQ?K-d|5HBLI?=WU$c5uqx;-b` z#caaEZx{CwpJ*P2lwLdYs&aMEcD+e6|#I``(AnW@&2^rJDA8vMx8D{-$Rto z=)wAd@hY#DY{4W{EAF3iKa1braIfkIr33AYFL*nB_G>(=-1y}^AoP3|^gIUrn4~A8 z>eKV)EPA%1UOqjyChE^{?A+W`{mD-7`y1}j`m0_~>qo7>R~~Bw=HCXd{-%H0#=yUN zJoQVLSI=0#D1IevAJ)&~{WM68A7#5kEDu^PdKVCb#mfnX-AMSq^sXSk97G}~D^*Mg+VUfT;e(mAS0>AaR@uOAXAHVi+p};?W?P0dSKYs1u%neLGR$@2?yDWP3g`!1n)0-QXwje^TI!nDapvbz<}!~1^ZjgpOZm*t7M?yH`A6(8 zlg~5#WqlsK&3|wH%HjA~lYRtgCm80+czucRKjD|LaUs!{YslltzxMEn{V2 zP%j?8vK+}c_5#3*W^k>^H$dO>FB{*+?JEYf&Bv4*1vK(U$I|Y@nQc7ziMmvJ$WDYBaYG70DoiD zv`66BzECWeuOT_HXN#}V{yC_}1QcZcf7*{#(&f8{9sezV97nVBFt!RBft^Qw=3F>P zeY$Y_GQ2FGKR@OGy|=i9#qqfOZ&Ue32U>3-ctxkee`5Rf#PPqSiU-k~>CE4sLUB;T zoBftt({V&ce$VUlS*~uF`?SCf`*#Dr&aXB(W;o+~I_SIsPG3R*A0ilhS$>Nj3@5(y zJjJDadR2=rJ?zJ!FGl$mZ?$V&pV~R|hs%GopXdQL)4ruIVQ?Y` z$$UTF>*RABeN19>)bwBJLisF+G+v$551m(VX@JZ3LV)(n_}qRQot-_ErGsRIo|hN@ z^j-YBc=N3*Bc1ol={Mb2{9{hP>DFbpMN>(j=;HLYTW?y;zgOPWLFxPp zK3RXXCAS-=p1IynM;WE@D;8+N+vqb;#(#^cl7&wCxw}lZ|B}hx{MaTdI-Ov z_;p_bFP7J1;nyh{{EBMe7l|0{zvB4C{&nNm%^CdS{Kl_auHYx|hwnr2>((0iwQ}zZ z!>`3v_;o`9uVdxccRrhLU$@l2FP3zlU(b8|YR}*o=Qn*NahzKYqAspnqm)gwGxvIV6} zaqn!}CH)Y#S0n~UBaLI(dhO^kxa^t>9jb924<$F^?-ryo2BT5&<~yup4cR@S}j;(9esvGA)$DgccJHKqoA%$$?!^7t$>0f{(*r&dUVJfKtMwaNy>dJ6z;|)`fH{xHN!G7i zMsSOi^-jHWJL#t9mQykBiJ$rEXntPsk!M2D_Twqgj+uNJyz2bnm8nXA|aY z+)46DL$lybbl=PAT?&t$xrjpWYWhobS&9mW?V!UAr&0r>%f=ndr!Q6Hlh?td8Mt?r zaOd$Zp%6sp0$w42f;K#}>djxYoQi<$b%dAHgYMk~r?U%VVvC30N$@%6o9KR+-z$Cm z_gvrW=)J(9d$;8KtuE=eS)fUziWyW;oh@3IX;lOs;FT_tw77JXPn%%|N+% z_&h{-(!U@&ZTNV7z5*}I^C}x(&qKN9-{Eq&gvPO~g)vTJz0AMqHp#}b?^HUOelq-S z=wK|NFZmw(Wr*ht_d2adTLTzm^M`oaG4r8uywYP0e@*pm#=J+SZ=sLmAK+;{G=3DQ zh4N+dX6QTz!IkrmEjznn{Eq!HD#uozWz-0{d>iNU_fP+n%GY_(#&1r4ob){3nJ(oV zxwCqNmr_Q$8XKV3!pp$FwlSz@<2Xz#HN9xA>B;ZyFG>=ol^`Ci*) zq~}x^U9JD<&#U5+t)49x01tlV%gNE1@@(zN)A3D8$2TF}_P1nuGUb?_eD~?X{nB_paE~4gf&IK^@!g9bEFwMs5EaiQ znZGvHA3%%zzwpQI(tM2*popU8KB0qO{%+>OW-g83Qa$CKQSOyoE{QkF-6L?~av}DF z5Bh`7Zwa}G`;96uy9~|%@X1=wo+&TufFJYm_6j)xfsD`Lfc8sQfgtAJwRV&xFV}i< zVQ{#drC$2T+uv+Kd^qjTmls|iK-CqR(`}OVPu@8b^k6yR%i7-!ohrX*4l!TjcmVO4 zDP!$#8RcUTjk^9lypf^NISd4b)8lr&K-)Pb^7qjK*b!fzviQbyd;=j~k9IxXu0qF`;umqVNZX7>J5ck`O=v|0gJYMnjZxWC9 z6CM@^tX0plzLs{Hv0q45J1yS_`f_{y7jpEv_Im94bwY zOi%WFSbvl4#j}4y_KC(fe6@|E1iG^F9r4PgVNvjF>VH^VJ)9w*1!eV{aNL4SSR9|a z`Bc>RmUCf`+I9X!#}qKs?C}c`fBzQMf2erwe|Ysax|m;mB=Ps_K1FmHX8fJ`$1Jk) zeg1v6f`9q*B=&msVEzp+e*ePrslN)Jc6jwOIvoq2&Ke<~-jKtm4HbMs128;&e*T45 z59Sm58RB*}Q`_13xbyo~`f1~2i(_y)bF6#;@^Sx^^KpCs)5jo3{N{ydZ_BIj@fNTC zMxSHh<4-?1vi5ct(Z|a7`LnP_K3?tBgZa^2g^%4-UM+m&e9Xs-Utm7Ix(XjJ@ak`L zJQhCgu7!{4_m7$@$JZr2C)AG@u^*G^_+}z#TR_0+3U{gB>jC|K1>)g0e&aX^w_F~d z73p5?r9X7FY~j{M=`?67(mnP!uj5qkDVe0@gon*fwYaDG<&ykw*>ZCQUgj^h{xR>H&ljijW%9!E zQKIK8I{ZDAZ~V=ZyT-AL1>W>~ZGVt9ogW;RyEEM`*oBr=et!lZ8YjG23NpM* z?)-MvNjaGQ^e?lWNjg`W-+S%szKrsW{w-5pC;8)Y*T`e+=ZpP7WH0$D>%J({U!%{f zai26-pEceSs(hDD3FSpw0~loVVEe%r>ze_>&*BeB{x^<2Px4tj%>SM_&);v$sGrF} zcJy)*#*Dgbe={fU>4qocw~g~z`JVsk?Mxr#tHs@|y-ezrVgfo(Sp0bp;gRBAV*<9< zN&GBskhBNUJjie9e9X`C^@-Vq4Fu4Qi>{ZF!a=nUJ7FLE`tS@BqldMdmUg8#)xSvZ zv+Dag=I6LdJCLd;f#L64+UL_>+UrL7$^J_&A=V4@%$JYXTj@Eg+*eV#jbmRg`K>&I zYw~>aDZeN0Z!vvHg|R4S)lbp~B)hB!5xu+y&%S?hI+e?G;`}Y`pnqQZ?WfEZ03BZW zJd(^RU(#zRf0CBZ`CHmwA@G_0+TUY@G0I$!~Ox`wR3jYyK?xlyr}tdF|sW(Si5O-v=}3*f?R2lxy~3 z`pwAC?OE!l_9A6(NKW{@wJX;DS1}%I@V&)Fx!ey>xmItR*HTU1ZC=JXV|E;6kxcTx z5cCV)HZLe?4@x@0+NX=zfqj3@Ltz~?05#=07KmFZIZ~8X7pMHy!ANN}}$fM|4 z4mpmbyj!!%i~H#}WR}-{${a~g>EmAD6ZbEO*_nDx^_JgXyMg(wdS$xGL#)^C1>C%T zYpDHDmOs(wo34-#l6*A1$@2AhH}msS$(Q7($sNn*?UaM*+DiAVafqa6)aUXny6XOX zEnDD_$>QVx)$)ot>dfU7W)_Il(;$Iwo8!A`VnfgVZL!}{A?pC>kP z`*;`Xlj!f-yc3q6bzBc>cf_)wtn~K#HIlwYzy!X2|1YkG+KuTtPKdUlKb_KlDpzdZ z8D7iMYXqRp>%IAuCGvbrlg{_1Oq4YqU&VeIV!EUcNOqAcnJ=7y-81U^Bwl7u8z(?77lJdS zARi8~NcuD1U^wl-BU*v}RX)6PB_s2BBmLrf7U^#L0k+sYC2Fjaj%Hsm4j-WMCTYD5 z|LH6=bmf)H@>HbvEhPZtd`eRE%V#a36#Aa>RrJSoJ!Uv#zPyi`wEu1E04V>7^d_Fq z`WngR#={x*O5~#*`FwkIFV!oF|2gCzVLVNbSiMc(#`<+DAwrkYF z(uvz+m{DHKR?Kq_cjEhGc}&M{E~l4EBYN7npX%97&n7p_-v{a0!U9cRKh!jC+XL+ zY!{;+kNZofTq+fc`}DQa5+KzRm z-H2LKeQ^Kfem9Z7U9>-i<2yBfVb*zs>v+PMz>5hjxsb+{z~|${k{?%H_y+hM@O?+% ztD@WNmurTqex~TP(#zYCG%oK4gz@_|k}=^^Fplz%HQPH!>j}%hQOY~roL-RkTJ6_r z=kwA|UA>y!rtQIgz%+R~-fv!dlfG8{()N7Z-|(%~-p8c9q@MLG?{HW1nej&z-ECit z?{|ny{;Ts9v;jOnj!n@&+rEb?|GbFnC?kvG6aQ@M8zDzcQjfGV zSisl&YVftnFK=W$PL~xTrz_==`{87tiS0XpnCp9sC+f;`0LN|MyX}KO`2!ND_&(a1 z@+V7g&=f z5--R@eO~5sx95??9X<{b_CxT!D<8k|e#%nA&+V#@`^1|_k9y;UZR=l3x(g71$n9t{ z?+f7Y+{Wtw-#W?Yd=BCIdx0w}CthEn;S6oZ%lUrggkR<#91kBy@cHHh9+3}RZpT~> zqA}u`%!}AKiI20n9C-Vo9DGgScDc;LUzlAqIp8>g_eY||?FvU&ALs{p*jIxNh1v6` z%7bK9zPo+~^P;un!R5~V0ovIi?YRCq{7dgwu&Vd~zlD0+`g7#B=~<7*txng7<&*jS zElgMGS3=)anxUrwyWxe7mOrHLLjtGATTZXo_W3v;ovu~%pY@~vM!osmQrtxD7^g*x zIyD`(CnzfYL6_=!zNhv0{ye8gt?__b^go(Dt_2_NQgEuq2Ymjpo<2H0S$IJ|<<~u5 zQn;h}tF?h-yx9G3zqN}Bo;o2iOXZCr>9CgiJn@#@9Q|S@=+xR!cLWg!MhbMw~JMDUQ4<-oyYHHdalJ42|a9l z_-Ny+?E-K7fXz2=WIb893di4U^gh|>YkE0v zmCgo7+f7H8Zy%ov<@=}K6Z#uH+@CJpLcDxFJ<(6YJBx4IO;=2%f3v~icJofw=l;n1 zZF6nhA*KHY&FFIO@PaIJ31$1h5~)%DG*P4C%8 zZ`0!>K6E>urS}$XKIsply?0A{Nq@SZ@0S`}zW>+hUALdL{_)?SWMXHs@qyXjM9%Bl znPCMWp}WBw(!C<^`gtH#bei>Jg(IKK(tU^4o6tR|w?W=$TqN~Y*Y`cGugbniA(eBd zyT@Vm=cOxl0Kc5#owo9L&(8S3W?1kU<)@n(~YtRLE|^*X(s zPoZ2amwJ7iDNFal?CWdGhY%ekcE6a+tGnFPvyZ_z(|;Wl`PiZ0C3sEWU+PtOobFZq zr5W18{`rTs;iJV}4WNt1U8V9f=QRBf!%Jb zx>h6z^MSLu-qZ4j^8QtUH{QhY&&bwMRnfnBiP8V%icn}@(E#kwKB=d=++ChP3H-|77xp=YPy;r-}@9s%8Y0M`!5 zBv-tR{@vrfy8iB_zfm|qKXWCVzgo0k>#3f<5C>F@PMOD6RBKz1I>@fZa4$%k5Y z#N{!R-*XOD%P;n=1I~QzA%)w^)s=?E%#{~zEM#s1O&gghtjdmT+wwwNh?b^e&LEydsTyzL&- zD|x8TGx$4xp?}^lcthXAb)QLpWc!H^yCeFEj%+wt*2U+?AL|8>5O+qg)w zA4Kp`dr$+PT6Q8Xa=a}JeA0+jYHL1hjyM+k>z)?4lR*a zj=On%gQgFmyiST?0~}x62zk9!0gHB7+_anJ9e#`tfufMB7P%*Q2kYSph6jc-mLXl%$GYy-@wxMzz-N`d2=iZGC;w*6|3b}wH2h&R z08c0CarqAL*XK3xe?txV@_O2~pDMM9pZ7TUZcQd~1G@iG9yuLqwc8@^U0*}Gzp75V z$ltboq5Q3G7wtStp4Vyz&mq@~B~Q}cRj5VMfn2}z3Gh3y!?J!ICwye(+Si@pyus!{ z3qmDd+}eHw?c#YZ*k>NMuGHtDT&%-7mDV--9D0i)aciHZ{P|yhj#4r!)MH(1f%T zwmXJ&zgCx9a$GLAGoSPNU9Iv`y(Gs+a2oDY%;#HmF>?Hgyf1!!E{B*t?NjSZAP~TDDUwm%6Hsq z^ed8X-hN!%!*azjz2mvIU))K&cWJY^S)v+>ciGYc=T6YU>}D-Feq%GnM?oa-be zN#QCQ9Z(+i-X`@r96hr*&kK3U=DQ=H2ke)AH|7SZM6Q0i&76Oi3VsrnAzq=cbA{vH zsz2guDbJ|?jq=3f`L;6vjld`N2G8RT;(wZ~N5vaF$KCsvE5ux^M0&gYkt^iudgbdf zeeUn``qe?=f2_XOv1S_idVN4or}tAix8{+L2;DO0eM!Gb=@4H_eZV{;uJ{4kg?J9- zE}ldC5!ypN|I_#jIoY=*9Ut-aM?DQMVSSrux5fjza!~Xge8c7K=5<$`@U6t>kR!Ac zm02F`e7a^k?OGrjG`m|gy|?e@`S)NVlXutqbR975h1&(!w<}L1fFV3PV9)L$e1K>0 z=YWs&iFT82E>|lAe#oK6A#)e7Tzo60I4i<5TDJ|=JwKR^Eq@`%gNiSl#q@f@$x z`ZQZEzO`9@^vvcxuTd-Y4Nu(PCG{>cJ}x31;*1@0{f>4~K7D=4+;_7**Jt=I(ErM{ zh=u_d@hUXhcS=k8Sib{=I12U@SFP`3e&ky%&D_N2ITv zAD-klzZu%?M}qu`eJ1)jm)E1&=YN#)seOi3CS9}k`Ky1G##>L^K5t0s)qPslZw>7- zp2r=OlcU*Xpyv7!+U1W69zEJiOy4^nAs5HWE{`f4Y1|5ULpa9*Isz`x`Kj3D(_xpJ zsTZz4`P?N^t31DULgmQqWBdT^T0Dnx9M9RS??d|pyXtW&1km9 zJl-^{&tr=pL;H;Wxu3J-?bou;XfGENr z?C)EChW1H^$l`dHFW6u3&%axc*x#!Z9I>x#*X^2*6US!vQu|7}<2$WVWwPF~+P+f$ z+ZOzb;lpxnH&XjbJiVRN?x%792vhq?KLq(ej(ABX-x3;(c!@AT-|H>e2O5oSRd`&! zVrI|9>sXJk_jdlmz9LJsi*j}}`-*(2eI;In#z}22luPt~L;H$y;W_DfwXb7ZuF!bM z=*RX$`}zlJFMq)IGqA61nxFRA`-SOww6p5Qz00LsYF8P@xW4=nvS z=Wp}5srZKNHcX)l`@6|_=5~YE@b!H&fcMdFOS?Bw@cg?p@w=zWaX$C^S^?;MtnB@N zh%M>SSvUA?^5GB=Z?uJcI$9j^ zS;1r6;`yHA>-Q5U0(=tvF?mV)iDuuDexm7D;W$nx#+#Z||G}p}5Q*`5jU*nCxDU_c zjwPB8^Olf%-#6*@4Eyf7QNCaP$QAne5#`G=eeUn8;t`8eF>W#CyUZ51;`x;CGTXQg zo=^EMv&FZ-NA05MIVcXk-#d+bygQ&L%GZoX`Vo4t_o^&eMD|=_l&= zs>u=B`C!d$dQpR^N|tsRNuS4$3*f4$hNs6>3D3h}EIkF1vRVSn(aKb86_q(iiu z^zrvAgszPU92e<9-Tqfh&zqxDUnUC9Ti$nV+uP|682Oo7QXJJNNIK$BS8yk7FS| z0Ue_;qoesr)ok9gJU|E)Coq9yeIP%ey5;J>2sN~K%UpDVHbFg{r- z`kM6rtlwK`oR4aA(VcpmGQP1Y)9xvfC2aTm(k|);$)i%Iwx3;p7?oEUT=XOOE|64v z(L_6u_T41q7YwM79bG+Laxg?`!FLB8V^51ucV^h+7G$af`;UsgZh1$+fxFD_|Z z9#^7XT)ywf*D-ti@9WZhAKBmq%-_>!aj)nNuJJ2)2YhpcE*|H{#(zIg&%a+3#w|^f zKlv`9aMd|%p= z#vlIO_Q5k*Zm5gjhaP_s)3Zzt;!BzK?@{47qbFyZ(J?p%X;S_n*U09}4FgixXNup8vML zD_s#f10L`?j6?1fJbP3MU{^4!2RpD=;qY;XWE}A+d{?>fmx8y&h4D?=jI?*Q{(wLF zrO+)pQ+~+hegNOsKq%nfe~&K~#gq$pAgA-w>HKuW_tz=?Xtf_Agtp&u-L zPVMtx`SW@o!pFGf8d?OaXmTxgj}sGpTt@$RG{5~-q3=xm_SeOpLoY- z7gO#K*Z75>J}#8cy+9uW&to+%ccaqp>GRuHYy0)>*xEq9T+W}09sA*js{QuBB68!& z`0ZEL&@+cK)W<&z@Obim`#6pF{5%S@gDaoATJN>|b)!reK5>8jdadt&qQ72I$4)F( zIa{W9Jstjf)--ZHCy)=9pQj?{TWiR9>aUk79ex-6n#f4peE;ul|xUX#TE zqAMQXCVI|pUM?AjH#^|-JMg1(cEZ1KJ*cmH@o`p+x3oz8$k+TWIonTuBYm^olXay1 z@<1*hZ-ia=Los=I_1+R^)Oi0Yd5?O(`98wmAm!apIQ-E@$skv>h4;+&$KTerpn4ta zu=pwXpJ%>+v_W~mgZ?nqvF^>RV_g}nF9tjVf1AcTz(?U);&7mrblfX$-KzYFi<|Wx z+9$vfj=OG_H0mFDkCflFL-YH()PnE#?$_!QI)?M_f3d5YPEHrVDb*kGdE0!>#@kA1 zeJvSyc1jxj?UO8k>&{1n{+pH%E~9t0-VnbfQXb_t2tHZe9JzwQ{ z>wg2{dU_J#w^iyxxl^B@Jfj@sd5^Vw@)MEgD*&D7PaQj5XnL-`FEp)GJ5*>|q2r2$ zrqk837Mf1e9&({+x#)=06X^RPSvU)PzQ0?Zk7zZySz`Yt<+*&1=5ahJG>GAl%j1RU zd?_GTbOGb|=t51(Jky3>;aA+ck@waX_&z$H zb~P?`{~GN?7Z8rPbv4r$5}vrDlj)0)OW^5RrRmt$`JHa%&a(U$Ghbe*MmvL%;;f$u z@mM7tow(SpaLas%-j%;XD&XUH;aX&j$jP!k6+@$xAFMT4)l2Ag|-2s9o?d zeUB=X58(UhugUm`t&4>0Zi5URMi*(U%34K0r`bmmld=|%D;)^-2AHR-v(8nV} zKEaLxpVE(^x81axje@XTQE9cNq3=Q(wZrGU6MR@_`7S10rM{|sXGy+%?gD*3R3sn9 z$F$lU=JnN{25}AG@bz<{JwHY4OLT((C>P=%{0iaklycxtdxk%|fKRDYMA`_xx1D5K#vt?!CoCy_*1!JTJDu~nQ?&fC;%hy)q@S#C zB=HWzn`EDKq3J|LywJ2n`CMpPZ1K(_i+2hd?}T)3{te}3hwwBi(LTh*HMEB%p7#u zH;aecPxt@e|K$?v^p_kiw=3oswrxHPg86=T$aA}-qZ^fsQ{)qLO6tFj?@|B9Um)cJ z`JX5GqNF|YBlTlOr_-dMTyd|_(dPf+4x{sO)*p9~9!|gbbu8!O!2RXrX0NQ?%1Pu$ zht)f>km)X~cl4P|_p;uZ+L^rU{sBaxzwVQ??1LozN_flhi!~bmt<&ew|4Df+aj&L9 zuhKWC>iyosuvb&_Bj1CPFS=c;t;>g~!uFB>p>rX>&S#I?*lrph8=aE)*yxnR$3`cS z8C+HLuNxnKkn|B9!UZ`39o!DeexHOMd&IT?-pv_0jH#bBdYb(T?dPUUewD|HwI_5Y z9a%mapza3 zDmgTI1oZcKw;S}7z8x;C-xnAM73WI52^^LN#vztJPyhx|`3uSM@a(RKz)JO{kc zAPx}iiY!Q&bY!T==b>L!{swkM;oG9c`28)DqZbQY(G5HGMJ>NNCi(@xx;o=mKl3Bl zsWFwyD!;mWk3P@RGwdf_sQm!ik<_nVuW&?0$HcGF4C*))JnvBP|7e^Ml_;muZ)Mye zWD&G9AMP?PsBlO>R^K0uKF}Z6w@`0RQ2K08xN6a7hta1mL!TW=pB;7RvvXSdERiYI ze)DH3eXdYA>d_~v9Av#`XtqQ?FrJ62?F{|^ez@We(kH6$-g6wNCUR}@aNKJ31$HSb zSFjr)-6o|x^!q3O47ut=bv5I)twy(v8M+NB-L}@I+pghh>DDWOdNtiHR5)hito&oBCy+zXuN`zKZ&0~S_lq;$2LHe*tXdfQRRBZQ5};^k6g`k*CD1y-@tS) z3l^G}shkv=TNuYTFJ&Cx{2Y#3HlHjqA>(7sC+YVv3(e2gb()3dqV_}!%_nkQVC&YO zp+fg>u*(PKUtAp4=hD9?TqSK*@jE2`9`bpCj5CM*_(^##UuzoW3XS(#dA6Hfw+%Y6(nwl@43l=vK;6kBjX0O8jMMqkF;^;vxGcl>Sa%83(X5 z>E!)tKM%skPxCqMOAqCxMKG8B8Emh0qsh$%y@NjMC8SK}t-vM8e_yxKE3}W0E3tQ4 zE?lSGDl(DE6{K3yBcx|O_ffSs;rK6nc|P}9eICNuF6E?u%KA%Mjmq;Xjj#LkxtuGY zci7=}fe`RNOZ;63XQ!Sg!2Dsp+3<_^vEDF$h*wl$`>6N7+Csdj=#JO#T5n`Ou*zGZ zk>7EWbA2=&`k%+%4m!TOijLr%^!w}3aZME+Cxs-y_lN&9m5v*J0e&+-+Vy+~C0}$E z=?MQV|4ToS`3my=L&=)VYYr9H{t`K5ynyYRz0A@-?1zJYq1{?53#S3!_<5LDaQihE z)uJC`dUQGMRoV2c_0>#QOb$wCg<6r=#1iln?8b&iUL|Nbh^K`5gLReF_KT zVv%3N_fgaT4VM0ur8io-VT%4syll@Yf6+qLUqvSyhsAz?bwU@{$G9Vv+c$KCaw~)b ze5Q}bPHrzWdX14@CE^4BMSWgfC5PU>zAqz(TLn+)XIOrggFJfvcV_ZKpTqOLD90>6 zel_8UMrj8jSO59@h+AE*e4L4db~^_?Pk@dt#|73?#h(#A$9&_c>d#h%JMLinXm9r` zL;m=92kqMLnm_s6{R&`ccPHhEoX@6khWLVJ>oA@JN8V4^Qqdge2()E$-L5H ztycWQ75XFWe}k`~z5PGXmo3Z>ew}9gJvGCx2^k;txYNfI!u%&oei#}dC` z@mk_HjvnVa9{Jo?tL$7B57@Es0pbNX-}k~=a=u72$auQa=Nj493yJo0p@D(5oU^3< zq9<9$Fr<_g{m|#GAL75Xp1I4|Zhbv@+q8OeAfqS0_?uKuWd2S4nasbL-+i3^uEXd% z@-wEpjJ~5kVY-*}9awRa0vNw|A@7$^FXGF^kjgb+@*LVH&=Yj*I0Qe~t>Y7Ee|@#4 zA)lZh@_l2Q*o9e4M>cL<4ZGk^st_{)BJPIUzw+O?3cb;9)#uI@lC0(a+v%WA$;TKqm+z0*f?XN&kNb_ zbH2De3j1B%LYRE+T(whik@Dy3RK?FJf0KB=Nc-Y`&Ep=o-y!~p&wZUi_?-Ttdffr+ z^-S!(+RF;@Mf|09Kd|%X$oyS2#(4gBW#7|%(HoR*PKUbjdD-9b{cE*9zWzeS?JdoI%24r;rk^T4 zu&WDOA@^B6%*o)9BmELQ4zvBl&rWJOpWCJPP;OtQa{EJl9?I7tT^Cg?UzA6#hlxrX zRex&9TQ&|-c{BM6=Y`H`2Y=|N3UbaT`Ljmp92f62yllLt^{q@-Y`mu9CZ{Amn!{2II?uRO6E&p|2}Nxzb)m%{FA~b znMc)nkk8xsrsR`xF4{M@w`Px#uf^(H@{L;SmCuy7Q`^bLTWDA8TvfaKv|Yo?+J)W2 zRcI7plS}5ev>f~i`T;{lt}6@i>cu>9pzokdNQY0OoqKj_eYNJV4v8PY{9f}-lqqBc z{X73d=v6wT?N`n3jZNzF5DxIu>5KATln}AMv`*zLoxkG267KI3Kh1DJ{6f8c=w`}q zGVi{T>115k?BYd=rp&vuUD>B@^3CrDRnMF9c{H-)7bxj|&FSra4DD-UXqx9~mcnUtTP*PY6zPJK~}PX~-oEg3#NL-}-|HlIod^?5D*0l&Qe zg!X^Bq87hCr|`IbM$0sr##gQ{rP*8;Qfww)N)47adt3UI_FrY)q4FatJ!)y%+pu4l zrI+@*0(!MHkY0UCul;rDwa@6aDnqXy{yXG)UmbewuS+krH@6ah(Ca#tZ@0%jUh}pY z(d%gVs{Ie}_3@<(6yFVX@!f0qc4zSYqT;)^4!#qHFYQyP&slsgmRPUf{Ey31Ps6p` z*S(!|f!=JEe?IPubrFEy?LvL|Sx5L>o|dt`$ksJQ%Z1=_MWn%|(V_)}MqTI$sTNm7K?F?AESBoN}{cH4=`-I%kGaQ=3 z`HW~Me&ikf63~xeQiS;B*OyLOi+U2xS=kXj@KDSrlgg)0>*FKRM z_jvoK>1Pplj;~@p$@yU%9?W5#FfObUma65xNXI=wICZ_y4VrDr_iDa&ro>yj`5b;? z>bh4^K)Ir1|Ano)yob-_dl|ph_xI8+C+lAC(_&9x-6iAf#O@hh?_xDm`VU-}x>@zr z*D)e~bN~E@Uz^$wz&ak0W6dAtd%5I`M)&G-vES5x+s`#vV!wF&G6Jwd)ODr&#D08) zoIXAdKhQ2|=~ob*&61D{?Cz6)9>;q7g$B|IJu4T z3ED>&NXB_oZowbCii=#Io7Yt-Q|TSbSyUlBXm72=Y4znygix;EwVXvGMyFBIt&qnm zMrn7K$0M}Cpcz9w+hP4ayr^~V{nsFOqH< zc%Hegiyo9ra)o->A_Y5|1;&NE?LR3V+lZ`bD4F8*I};r$8zK3-AnM?gQXCmetN%}ZdlwL^=`Q2T=sTG1C0}N`J~^Lz zl=2?XcNqLFPEf9b=kPD`y`d_3Tchg{_VBs+4cMi2$q)PRjEp~8iFE|q$(N|ia$){F z?3nQ_DzQC@d!P*e&*vsSC0jxHr%qsxqsTUbBzVpx94IRVQ5!mJDE&u5*l{=6`&Q~h>f z)_K~aaDRe%boFB$UhW+2yT)C6C`TP*ytnQ!x!S4sP%k!!K0-duDoyqC8{xl78&nUg z{k+M2GLO_vIZyojYNiuE->K=R?&l91K8$C?o>NX|oy6}0IR65=VqC%Ln#DV{^HIPWAJf`TPdr7y9jI z?H4)R#pj57VIN)ZWE@7zh54H$f9mJiUM)X=NbG;==Lv5uKd<~Wd+PmMUpEZCzO$p2 zT>Pm59Qyh8I&_)T=Y%u${~Hyr)c>15PyGL1E5H04`?&ZaOOsA3YWwSgs*ha(##jOyAS@~X47m|kvnylX$xr|4^m^GW~251wV^?7U(B-gUUHL)a|mA+mfvce?)QFF!SV zpT=`M?`EKNf^b&8t@pTNFViF6V7hA$)1zNzx_3RQ@|@sjy(=!g6-c8z*0->0B{)aZ{+ryonF=*KsY z!0w`c-2I%K6yIN~9rb;}$vD&s$t;)0wU}?hRcIOf%7FLeXa9$8wF9& zVe$h~K6t)ao=d!~^uzjET#ynB0 zt;Dm|y1;IuZ^!-QEB((QEeHSe%om6KPt%*y8sbwt%=+y+U2&0g4*T^pxk=`x<_NBTIf%SY0mwD=_LPg?(``4w7Gp}C9t+5B?q zXY*>+&#HdqAlpU1azcKJ-J$(!zJUG7=JVN~Z0^+lWTE*y?Kg(!&}^2nafg>XNBdWC z*8$qC4vTkMJsKb@c^k|xNk+M3exK>vEFS5wc=UF{H+{eI z7>^$Z^qmC!K297wXMdjlGo(Am#~5dOoEr8MFZ_z|ag2EDJ`?mSw=f-*SuV`~63OrJ z?a}=8)bV4+o9^dB_>`aCuQdA~_ACE(75t0y)#c)P1s$eUjtK8~YTFr#!A)(rPr006k=%3gNT)7SJCd6y*H(g#Pdcm`Z#qC>O7HLm;|kUQsg3*(f-l9u(tici|F zWXCAFp%2-0o>Rv&w=vF;@7hk{c^2*@z8IO%`T)mQwSPgn^~iZBwc}zR*B($momXiS zy?cuDWNCluamEWz^1M;+PdPoZct-)g@6mn$@hvobU;6QJ zQTD%LUspK8I42!f?@)YejjQjx4gIOJ^!@nR;G*!+*9Bb8cynM=(_wvnzP`>SaS((> zuDQZjT=ATFnos0d@6qdQzGRJ!r@zMJ#m;LeNWTSFp{YURB|oPT_5>?-Vuxd`W=qbi z>1kk`6=iDo6Iz0MUXyCSUIqVA<~b0BMo1&*L4>A< ze@fFGDbf36jNMalPBiI|T=AfJ#<^Id~{Mjx*) z>Q``+bA3=>pXBrPf8c|3kp+J_ghj6D@jqAdc{?c|eoT2P>1*{P!_(k@lHx!7OOz-y z{+pJU^Sks8c>~|ZBi1*U;grBB43!Jx&v<|3{eWKZHhIbC*k6c}bzP5XeLjvF((62- zLq7M5r`X0{*%+t|0fSa4 zoQ2E3LjpZ|^}ouvirJxj?(JIs$J+44Nn{Qlepklil>jq`MLWG%)k1%{5C%C z>l|ggy^4?RQjvT|op7|a>w7uhAi?WP(&w%|_iRE5o8@~{raXoHueZy*UWyl_PSPWU zBcJ2{xIJ<$>;m}>){zy*goog&GHaW#wCvDv6Azs%yUu;jaSh=lz4tY=r`A> zJ@{XwXBFL+RMBlx=nVWW&d_aG*3GAMW;wLu`8$<<6H6D z558-Fb{|@X{=4gi_uq@G_ujOgVfi^7zfj-G3qwAgq7^)Sd}>oZ&SN%nC>!rGWr9id(GbLq}~j)Fs_c)}2h_7_dBJ!I=$y;Q%VwRAr9MXGR9-y)WBO9966zQ)0j7) z?DpH#4o79P>#a94T`{}g@g}B6%rA7UWqO8wE9K82wa@w79Z$2IeAD2#QQ`3TDr>J( zxW8)od7eYH{E)BVyzuvg{;(r{zSbu)a)JHUGT&o%isi%nACde~iFVod`(Rz9R4MTe z`?cwM71mR0Tv6>*neu^oNXTz!x0=Oogz*jRn2(=8ZuW_sMx*3=l*o_8J&F8S9FWM5 z>2)GMrq?5Vif_Ddi2@Yce&hH|i*qg`oGIPQM)&im&w-tv4ll)H#PAk#0Xq+TULyEZ z+u^Tj#=+8~I$i|*lK+$Qxi1&G0f6-THT3`R_x1Mq?Z~V*c<0AxPh|Q_&X-_2p&S99 z#6D&C1-Wqh@+Xjsdv+?kwbncAmwpGekO34ekO34ewNo6Jl;OnS*PufsXj)=-?+&2Tj~1oeSE*g^tm`;X@{5Vy=9!2 z{=P_mBywqKw=)MUP5%?}0Kfp;^J&eAGGrGElobgMXo0q+O|xe4{W-~ z-n0KE=X5BZQOWx&E3G~9FD@qIr|NIx;tQ=j`4<;kElvK#MSlP2x^4Up)OFid>-%`y z60KLh3ubrguWf6$bf?|B?cQg1uJ4VvZPqmCDx?;=c4@r>+YVU1VY~0wdvs5qS z`GsW`{FID*(EPtH**aB+ja!Z%-{t20k2Pa?;aBtg!zf9}BQIl2Y z359Yqkr}tkeedV_aNPcN8kg-;x$$`_w5#%c+#cbB&(kCS zgED?2^X#OjkL!)?)pS^HC(21)TqyT0`5kXFdA9K~_p7jHz)a?G)t*6LAN+k|ram{h zE{$2chc%y{$C|94DxozQAC&T;or*Vc+%ap{vi2*4A9kx&9KR=H&k&b+oSxb<`fuR< z48{#;Far#4ZZxxt`gyFR%;1 zBVK0ZW-xE~$lHQ>!`Z()0+U{t{fi@@WVoJSLeerHVD0|b5$OU-zDI?IxKDEaVD^7< z{-Dd&b95Zk{$Jec>ngau&ewaQzlHvU&yPaiH_JbX<5;d}^eIUra^XGpi^Q#5CkOd_ z_%B4ig7>>8$%b+O${Cvp60rbh{PZ0C5zFOr7kieF}S zoy#XhFL;i1R3>~f{-bz!f2MkUEceIBIZH~{xOKDMogTpNJAW3Av)ejfTQ3t82#0?c zw5N$_$a9C#cKlKWQ|%D^DEhIvA3Q@x1;FRFQ#t-81{@Kz%A^$T?$Gtnq&n{cfGss%N&p!F-`*R&{JRjEQT)z@NpVa3E zw7&3pia9`|4 zwLI77#Ko;6JJ{xrW zYn47v_s6WXH0dSdA(nQ1w0$s}xIQG^k4<|6K0;(_`A_WA2>S!!KCY-ty^kv7ALx9? zMes+|r__IT0*$2K8C7UE2G3wTRA{(D-^0$qbM?r_&!KT{uYF!Sl!JpR2jsi#BUbuF zgRm;VgYfuzy^yc%CJ*@bm-HWv?p*H_?OvtnFn^26L5klEQZ9bL`Ok8)k4yRJ@XCDN zH2hy_?K=NkEd9IXf4YymHs52DkI*0N5sHTNn29_<4lbG^2Xk#-3fD;uw9ccwt=KxL zj%KDuF4KG5l{0&6`&4=lD}AD!X1``Qzmd;zUc>SB@!)j4XD91T#(Q>H+U$MnFw^rP zRgkN#nuh;{p!q&1_hT;C?zg<%leavi_7V23UF)H|V*TEUk`C#s`c;;Pa=~x*nY^~0 zjd=+3cggn*=#awk0_9Ioeo*|Vj~^f|eTCEu{(O1g)ON?D9gqLRd|#A&ju+rPNy^Uz z-o;bk^>J^?cU)Xc{+6jnaqAy3U7;Su9hWmbLOqJRUTyL~{!c&OUwz)fOzE;4bQuHn zh5pUC++omV3)8jeQvrPLXvXO^0+{54#)i5&Q}H za-Xyt=KmP--^%*Je19hSV3(dDuZD`W%VD`AQm)px;Gal-$jP5)+R=T(_plwj-#^Uy z5n+UO?~b#>{vhQxDlJj{N&V+MOOx;EzSHV`GxU45J~3IpOFI_gqj96{2MeF;{+SWN zjrAxh56QTe`?13sM*y#9|6{H7w{O-8B8xjxJ90qv+vC5umHn|O88_a?_lX^0zbS-o zC;F*ZrF32NevzxecDA>G&y%=vp#UgXG@t%68l_!|d$+6K5qrdVtZR~Y`S=I&%lA?V zM~QYVF1|d9%lLq+#{JCy$JPi4Ho(q;!9pd3M-<$tM%0??7yrf5GH0c}{`JGn5L!V2W zYW0m-dcx9sEWMBEenC#I=qmEr_xbs_Ng8Lc-Rd~g`RwuFlh-HcO|7_a0`eN@Q?0nr z;|TD7&PSn7=t}U!2Fy zD}-q6lGXi0x*v{u_T-gA@O+hvTG0P;{C&L?6{=o6;eOo9&J=x0$|E|JbaJkR(eDN! zyj&9JlAg)=Dn`E>^|i?7H&y=Uaj+0c1S%wuP5s_wf$Q582XTm7aM#&-UvPU z{u#C8qTcx`)pVH@RGcopKR<3=sqm!x;Qm4Wrq zmACMDa=ywPmUcbI4dR2JOqrjd{>Ztu*6tGOTWO=Et$$uxC=w##VtwzTh=c@o8hdZ^u-P#`D{N}5mU!?0y&R1C{ z^usvq!OVR2&EJCmTBr3^pRclkbSf!YT%Rd$q5UPh1irF87o^Z{mHn3LzpBqy8CH5m z$@wZIsEawYMS`ETflRFUXM zl-QZ-e)n|xF%;0Tr=i~YDvs|=&sVW|u_i!Cd#>Z}nK+}+^f>3cntrYGU4^E{IIq?8 zE1lO0y0HAC2r(%~MKgS?`nBIjzU zKTYlar7U+h^WnP;ee%=WL%AE@5zeFaGXECKFKnBTp9wy}^GSWaO7TqNn|7v?b%wUi zZ5aSWJ^Wr^y3Wtm$t}~@^8OKpKYpN-_1rB;$%VNGT)xgNT{pt@ZZ1!8@wv2L+nw)c zFuiqH%ctiC*!sFH4wtR3GyIbEc*%MfuDA1e=ei=-2@e#{sp9`tup{D6aDk7T-}^+_omQvn)YuCP0M-SOG&HKxTRV61iIcM=Q@P^m?zKWyPl+TVrOkW{Cvu{@7IgF zY`yMex-|tMu5BNQ; zC>cLEsO#&}eToM(J-ywffkxb;7ot}J1?<3E@lna6b3 zcV|eSFOeUm*(_J=q<<^TxAbaDpJ?fBOE0sut^c@PtC4koprX*D%ryE1o$zz5)(@z0 zew@lpkYB&^;C93OJ?Qhm3*fh$K0f}!j4p4ON5j0T_y0q_gz|~{_R4rnN^dD7m#;qw z%Z2<8@tQ6C1Al!#&8sr}?Nk45a$Zj5!Si2|$*=HLjBZk|(qY8XVhlh>mp{P&Wr<^| z>2aGD2<5s@p7^*V_%R`AIcJIbd#fbm!t>2Sg1FV!Z4+*^vs~n|N4*jBIDP(ReeQI- zOY8CT)+C3M*SKgTxj>nt%x@R{()b>qIWq*koQfrD>6P{a$7yGGc4;{llZ5`xD5E8#6hK$Pp}`M zAD$}zCilU2tA;*-aT)rzLc<1I-|;iG=W_0-#y3&rC$#S!j1QxcA28iz^Kzr#X1bU0 zVtTINa>aL`)%x+JW4lo}pE+_pVQU2P&j|SswnvaIa!G~D+_Nj zPGR_*MmXbM!#A-LMvvuaUF4^Wa66vy>sT(IV+LPm@AFxZyLOZ-a=$>lX#?@trPb;A zP8%?9;d(84GKu`HTQwi#`|-b>iuZomr{?2e(Js~peMC9r|AplDar=7oiYkN$`SD4} zls>lpY=rHn=W!UFlK!00De2D{oh~9?RdlL5j`n%g6P$C^Cq?5;>yAnv`QD(u2fpYR z0R97lZ;0mv_O0ANIKq5i2VF|UJA(4d6_$g3xI9G_!h!mqFJ1emk3Q!U&N}iE(xXpu z0^W~j=y5>f7~&n$#q;mUw@Id~7=hwvKrF?k_nw4<~%E#|oZv8vGpO8Tu zK}p8J2!Ekb0u{N|ihpX7d%7OS@I5X)@9rIu^c!FxTcy3Iywmc%R_QG3*)$D30VJpoYc%t@SL=IOcc6BD zpw;xhawh#ihw1;w^O^24{U2S`C)qtWTR#=nQbzY6Ihc7X7fq(Zr% zN2@H~Un5_M`jYN*{8P;rm1&>j)=uS9RHj{vTUSxu1O9Xif8y45^7Go&yg#r~?|#0e zw}bY(r3H~ceSh+Tw`qI+-Sfnc%ohU5<@>N@Ka1usG%z6c`jUOi5App9vD2qWIiI)i z{uAi^$VPcCdXEeHX>fVIeC`5)jPk5^;R`O06MS8uuOIUBJ)-5z7k6z{_@Z>Z0MjkR zWBd;0i&ietALCauJ$U*u{V{k-i{6J$wfg{{k6)~hbMb9fZjGgnW4+F|*y32XEAgq! z2l)bGpgZVt<)R;|Jji|>g%9I3crWKZYC5`#?L_NI=fZ3f%=@L@9|`ID;f*Ps#-%=7 zJR_pt8zW1YAp{$=$ds}Fn&-5Q5uZjgo?HK# z7EMEc(EhlRXE)LI^W_Y`dH!s%9*SKO!_IH%TRHp%8l$N(C0^^2jbR{ z9(__C@HBxQ_iWIHYSCfX=&&I}hr5*y!*%GeV_G`=d_^rfT%vH)qXXi$spDc}ihuon z4dV##AMyx%AC({_DzBNQT(`at%l$~pby~S`wPR~VZlKSF#=p_D*x9Ob|0d<~xlihQ z`7W8-je%D47nR#N?$lxaV&oR4yUbsV-pF(>{l!fCD|P87aRx5$ALet<({u{gVTC_R z;F@GQf$I>{30wy?JyWQIsPQpR60cC}B_`P^F- zjuelliM}+aIpBdSDnD`geBTuLY*xKa!8HE+o_ACW2=kd%6(T{d{likue5CU(zRtm(mkCdtoX5=avF#(4`Ccs_+y1|(#P;I_gg>v?iarUw z=KzmoeEu%p1h18fuZ&+mjz_YNo$0G5G)ETSXpD67_yNvPuA@c|k02N+@T|{G^|M=lA^C4*dB@+&A%DB%kFMtXEWNy3IKF=3iIA6c-3ChLbI;Za zyx#;k`{aqNJ0tx4`da%N6Z(8fO}u1%fj*DQ#0PLfegWsRGkEQlbC{ws^N0Bs0iP1< zk1TGgH6E_>j!u^f;Y2&1JuSqK1I5t@;Yr68jsMAbxbZ(34>$f_M7-P<{1>!Q{&ove%c zBc`)@Rfn#=E)aeX_C)$63cuT%Q2s#=z?&EUna@3}bPnS`rEi(^MO=sVLt*^q>w>-j zI`6i8(ruo=JcIRrLwbAu&q{vR$7qav_3tC19}%AWebn^}qW87dFR0uHa4X*{2A{~+ zM%ar{rh)$sQSE3~c7EN?$w~Zx$$!E(lmCQoX8%Tv-u2Gsy^-zab6=rc-_CT%mn{6S z1K~Oy*t=TiqhGivlsk@Jq;mJ>jNJWkM((c3$laBi&gb?hoP(t~>VJl8o%5irzZ)uY z-ox#9Eq)x*`I+i*f-IiOrxD{*ldN|G-o~fUKEJ+*xIeYeuwZ$O>O~F*ti14fSbkQ~ zHK_kbzk+>TrTPImXj&E8MR5XhRog|23lqC&ad%=DE$+TZi_3f}%&!zN(-TttZzd*`|_FxkI#v1m(+dCKe1G}zrftPamIvLdO`Olh=cnMBIu7ZuX zVH{cG(=B{HROGs;5dKX9uk$;E_xTgT=c{&V!CL*-bUa?af_?vd<)i- zm8*bWYF`3+O-enG{~wJ*9y%q(@g;dQ#g42tdhN~7>rG0p)wSvMQ1`U-S|f(6S{`I_ zUaqKLZ%Pkf>g%z5Jj4CGpWl|oS2t;YE}!Fh7yV`KhfBX-cZ=Gk^!s((&yara_jfBUP3#~QnijL)EZ-Mz6uH3n z#YIJ?$m^J`BRhLoq zG+&&oi(Or%S2)10VMbVO;Q?WrFvZevNs2 zek7esEZQsAUnCy=X^oVpfc?{$Z{a(O58+07gYV`cG3B++* zn2yRU2fBOy<7&~}>h*C#)cejeYSH;+TJd1%ZnaB@hoowW>znks>yw;2O@0fE^1tZQ zfg}yh9V)VX2zM?1J079_{P?rNCp*uiRvfrW^bT?0{*2$>ApK_GzYJd3)k0Xbi zA4$Jd`HZIH4zuGUA7i@9?D*&hneJt~PiDRWbOhb5k@Mg}e!`yM`CQPYJdg6*2%t)nVfsI0#p_IwTSoVQahidmG-{S zbgI56G@YV+!FODtPlcuywL68Tr8W=!932-dG@WewSx?gatkG+@-^TrU^cs$D$apaI z;tCzsP1e!Co^%VqAsr7|TsE{*yDCPZ95hS@} zof6Zph4n++vWn@;G%0aQJLO`UbE{+=K;cg2BLr5Rk8t`um-YF1K81!^`e23R>y}^R zbnCgf1T#1OZsyP1KD=2npM`u^-f8<*EI#sc5etp?f}K<71N#HL!G(1kC?Brl_&xDA zqDKmMq4Di3Z}N+Bpa}Hs9Mz+{^nH3h+@3eebnI{~JG$qr8jvI!AGP!k4kHKJeZ}q4zg8`QJ$kkl4Cw_q z_Hka{*NSqdE|hjlhiG?;n+?uMOK;V*_yJ8vWs`UNj(2~V=co*{nmm{79F3joPd)bCcRXJ$&!h4Vt-sL7^IUu$-{lJNcb|YNug-{XrpuM@wH{P1}g__37=AMHr?dv?(%?d#>@pRxXJ{h7-FZtfHE zPm1Q^Ii%y2mx&O|h3B~ZInuzV?K0#RI_zZrLhh}azFhu-J_R|Y2|0Y-?fPY+>~ewc zc<$@mE*HA#Iy@V9KKTUtVVFOPtekJHhvn)CHS7mTN%)>zW{j+_4`7R zm+00`yw-Jj!pbRnx<>MY->Wll?30DyQE83JMOFVP-IuTLL%3jf=zy3#>lM^>sy_V>ZL3$vpC= z>Ul`WQLTB)0|H;T4_^K8sPV<*E~=z)(g(+NAH32nl|NV&(hC+SpL?OE;io{C@t0{b z=XT{vOP~C*XXuNg>GP6|9{osQgZ&h+kD#1ibA?eJ$K-Q7Hwu0f7VNqUnJb?gRJi-g zuT*}>etS(vm5VeT+qvP<$hk~+9pwAbGnwu^py}!Ct^2*1>RVpE{sRbQpEB$B^VBQ+ z4prQ-k8q6Gcc{813@)D29QW>hLU4t01Ac>^-;jQ;ug7|#rl@xS4)Al;1y^ zBEJLLu+z`SW223I`rOBnt?m2DGx?=M}X z_Hv+jufp43I^WWyudJukwD=XuUvi#^=~1cA-rM@v-Q2ek%Eu=_*FX-|i5!4#y#f*B za~zDXb52jCT4S#(3BJjK9wB z4HAv8dng(3LQmy~jgMeeg@?FDnrM*@8ej)ktxqf}$U*`9SB`JY4ZIj?L*v4doWW!n9u!#wl}_-c-HkV%_nJwLi4i~uR?Q?>_CFjyk4_Ut$QAcaDjlO! z$v24;m_~4c_jWE%GH?1iD|eRVznJ-^^*_QJT<8b2%U!+${tKi-{0{0o>X<&4?}qCg za?mbiAUA*c>8bhW>H1pc5A*%G#d-Pc(G?ml@U z-`FAFW@c_u3G0mOog9tp#BG2LipLCj7A7Y zx*pj0o{T3M-;?nq<2&7FHQ(#Zmq+EkUkaL{?>r|%`hl7b_4hW_%g>tL8vO!!7?$$& z<)NCcK5q5L8M?NMJqzjT`PPB1Zw5D}%8$}>L?7o6&%YV#i%q{m`Plx#kiIS-r?9>N zj|q8FACDbX^3h^)eOU&N)jF=@c(WYn>G}Uq<%D$f^VC9r3p&Vp2u0ZG5x4q$hs|r0 z3~zxUO9$wc&u1j`*lqfHFUvvhKCR<&!;j-hq2by3;#kRDXg7c_;JIJN-42_-6N1U* z{xp=wGlXa9Jl`&p%jPP7@_dzBjw^@bsjyS&cxtNe8>KzKQOxjD*A1Fn0S?bskbHxs zuWI}5=fk*pk;Gfx@AGj2-@lCb4w5MIi$HUV9R)uD$4B1|{C6mSWITg*y|mNPrth|1 zLdHYv{T_R7_9F2kMQumEgQxl29|(OdEe*;gajm84A7q@{()wEa4S-wDC!qZ^JQBR* zCEjEF7?Zt`OE7R->Aaz z7vG1Qd^cW@2gTdYFuH>na`iMW(3!ELjbjXF#xcHHp&noy!{v170m^x}t|N=L>d6+i z8|ulPPYL`t?AI3<=M>URp_I7~{-}CfvRR+I9ESW*{l1lOfDeBt z_Fu-w6FK2HkgfAIe;+Mlejn$J7clMkyBvFaY1-^~rCa+E&KK09^sCF4>Ce%d%+TZg z0bgX?j_r*Z+@h{oen1YxaRSIK=3LwnyNyw2x(RZnH!MC(o0i}0Mkbe*rA$C<1bvGX`> zo$pNhFK$=s%CFE5S0c9pBd&a|OW_24(KF2FE+9TF>BK5uii|gsb^X1JYv*3deDeKt*568hEB$eU zW1~JFzkvA)$6ca7oUU^IpuWfayTZZY6_G<|JN(x4_Hisj$H&U4-@-TwL_I!{<8pG| z1KSg%I6q=(Yd@+Ge~f1y5X0?uGb$60xP$Kt$B7Y>D=HE1B)+b&KHmqC#39?+eq0>Z z_SfI4#dW=cfGBYa=}>5#o4Z=lr#0S~8<2Zw*Cxdt!=K`cMwmYw=Xvl`Q}Z8`{84#Q z+mrbby+ck=e^~CHKZEuUGT#W{^L-ynX_j?gG~}S|eC|(lxytAMx5{T||GI_X`P`?} zF3NY$Rc~NlC`Xh-KTkybm&$WCZuI_n+{!p8Igh1iajks^I;4-s%MX4@_%;SAaU3n{ z4>kVV!uO!3_b(s(q|o68G4d!UIEbs8LjV2d4<|D6whVs8_RUtsC%X?QT|+ptaY;#h zTyQnpPq2uP% z&)lc>8Pr=iw?{^j={Vv}~?aBI_UEWa7{NT`1vy)5ht;3^q zUuJPkNg|44&XRh{b1fhn`!LVcc}<*af$JD%XX9F|qrDeX2;ul@qO7BhlXaKIdCaxH zWx?4zrmkaW^O(ARo!xV$>(@SR^?PxX$2*T%W2riixfJUf@XP9l%pag#5}5VpEck^` zZ-X*FH9S4joq=@K+KA4zqL)<8E#?gi(LBk} zIKQg$3HeYtZxnug-yr>O8NP>n{OrJRz7NX$nek!!3d8h2%%!KC9B(|J!L3-#pCDFH`yWeR{+{8~E`(5VP;|BmvHQ3!IehRQs;${b)(&Z3+)e z)%fle3h$bz@S;BzxPV(3i3sPEB^=+?vwUY;KGWZ>Gc2F!Z@2CrNtUVpM%(WV^+fw7 zUo*c%d9GD^PRB(nwLOR4pf=Il!Ph`;>AkRT*Zyj4V?(-6AYCE)bBV9k775)&o97Ar zB^^&8+F|KV6TaCVa2)OZ&m~C11UK6FJlUc8o;Dc^mv~0U)b8WlUi~M+c-%j-pppg&dzyOpjewL!G+_HUz!@%SF3&_91`VRS^+-M(v{CVz=(0ff9+vV8} z{zT6omL(kf^HcqJyZq~iVQ+yxdG5&lpYO*E+vWem^fjfA{z~lF^cfFm`K0spo%Abi zx85$#mW)H|E&n*(XWgt_9#%i@*7U@CRY#~V652avIsP`XT?*{g(|t9Uj`aFDneZIu0~?yjLHj4T-%#kQ*1jzMrEBszpaSh1%wln_ z9r?GNSv&UoK9^UB9y0&>8JXw#L!SSmys3w;V%$`S-Y;~_f|_YLaebl4tJ%J7w(n17 z-}cI!ygwMooAU+KOuBD7uqUz8IwJ8fo%pv+3Wxsft+1Do`VW5Ybz_c>Nnd3DVV>~a zF#oW3zS?(9%VT}apL^W~m*(d{v;Kpw%Z+wE-uEs2PoF;w{f^to+r&d!!FQ|VO?#aK8)E&NoAYmx?E5*Uc39VZ zVfs0=@7qPZQCyuPKjL*;Fm%BgD&Z zr7!aJx|tl$IX=6uqP9`=l$2hga<8vfxbqr?2i7Xw{d|RYtyFl?rNi~ovYp?n^j761 z{d`IW`&b+5uj=Knh6jG70(+vo{eHLhoPP9szN#1B4;ZF@q`-Hc{>c!OjJ_0Wru__gG2bowY^svY-tiad*Lx_>d=rS_QhzpTEb{V%I8 zY5&XWOWOa^`cjC#q<$fg`$5o!eHJ6iJ+5csp&6 zIGgX!?IYm0yA4Tt+HaJENy+lpG#}d+(viw9uusZE_(B@;^;eX`2=nd7ZM?ia*WNt` z{@mAb8``_t3E|uCqX_lEdK22~$E5$Mc96Au3xp9rx5)N-4no3yH1(L;-&Mvp^o8Ik zxme+NV5!W1B;D#K$Tuw)=X}ME*?${$uBKbbQGTKXCF4!c7CqLfDcQl0FV*901kFZZj z@MZmh*9pJbxxw4jFQ(@PZ&f%wH+ZwcqdYh0`@}OkW*QwTN6MXgAz!O+<-F245?`$z z6MlNywEq~+Kb=5^Y@SxnyM*z}An+_+*Y&dVI=bIKJFjEwj_G+FJueWa=XH(>J)@nc zbH5XJ2>A`?rfenYrId2K?c22ZiAD0GB=@hHdh!F=B|9L){; zsk}E7^;+7AVw*Nt**Pe^*E~B16-m16J2WR`o;OzVasK_dz-d3#&rvj-gHpNl&4ps| zK3*3Uu{Bv zkNXEOGu$5)nLYA)(QMvuzsc)+ok&-ggDTqow5+}iYJE6Y<(72sR5&{~ zsBl_ewyIoCa&GVeEq<7tZw>66c3B3G)bAT$m!Tc3MSso5t6{ngNSFEdr%MU^W*?t0 z|EKc#5zlfCAb(@OwJ74^&hq0NWAwiL1>r@bAn&yi5JVwL*U6^FhV&<`>4RUC{RO}0Q`!ABvFpmN!)D)F4|>|3tL5Ed>jn2swQ_Ym0p}7G z-Y`+#;l0FLSbkNqi@narPnQ4KN1?CURN)`{vm{?!D;qpp@zgXQ{pv*G3G87u+Zl-G zLc{k<;H&PrLFF0bTbXNLmRY_%mhb1t7s^ZaDX-IViGRMO`!Uk-yE2zR7sXR2NdoM< zQ+p_BzXbaw4L)M>TWhe(bEUy5*RWjbDXyzrrJh>3WzibX$!f0(b)`X2An`rkE~)MyezGF_5c2Zz^^4fP3zT#&)%s!I1xh*>8?5yJ`%M*AH-mYV z`2zcQt@;*yN&HJ+ccULUOgpKod^vAK`wHvDV$r|K9rvJ!zl_aK;J(5J|5=8=4DqoZ zh4p3u@bz!F&hRLmN$I5qD<4To&mrJm1mPno-DL49hop2%L%Hj6<g8twSzXs#dgqxV|7#rA{s0gsP6;t|F-`Syo)M7#OGblQ!!2U$PH{Beu% zgpY5$KKT9a**TAU#83Bi?$q{Y;C1S^ySFR6>vn|~ZB=;ptqL#OqVP_wpQHVrg!da8 z$2|*0pOyL#1TVf%C*{Ng-xe72kqYn9{zkG$+sSyh+I6x_^@bMSNMc7?O=l^xW1#c|dj8;68=8vA2wBpl!O(0S96?mNrhw~Tv4 zB;MDZ@I4`c^Zfw#FSv(M;%P6t%J74!pIIQ~p}(Q!?U=84YnndUVDq=P=)CBvn%=L! zy7X3&f2H;l)l13rUi%N#OKG0G+nx^!N5Q_V*^{`Um;`-hSk()RgZ&TQ^u$ zQ@N}zeMacy_x9M&OE%0Cx{71f5oi4!@9)`u%98i@rfPjEd4F%B!G{EI$e*?+sz3TQ zs8{+2-v@mxzj=SJL-d}u({+_&vEBCD+V|v$4=zgZy>}JcLAJi++x31_+QZB)exUt< zT|ZWR4IEQ_?Q}kszsepPAM92BD!Ua=-?Af$Z@1!Ez3kfp$Gf#2^k03Jl;7|Dz5)yy zPulNWZvDR3N-*eDe0{}|1gxqlzSaDQ2p;bjuBxfNR+qHgO6{P~-B(h&updESoTFEI zYV!>~V6fUV#`gv9CZys%G*nnLJ8glkj-2*7s`F`*UTA3F|XzUubu=zMZ9VkI&G4 zM!ZM$(=$fL3v6GyVfQ|7!Ttl=Ij$2$KX}T^iIZK5F59=)YCl-K&+Kyi7t9ZTnptK3 z^fDkQjz1yc^rL*7zUm|$7Zlqrm+<1ar%8E5_+OIX_Xm4_($_z-^8VJ!L+1cbV?R>) zP5YlIoquilJ}CKG^}>tGK3i zhjl`O)h?6Nf2iH!{wj-~ulTM19NH88N$5vzfc>lhO=bMg)@#*IgmRe&9mMrka=G95 zy$@K1%X8#>Z?SxLOTOe5qq}bQXm&Srk3>WN7C)fv=d=r-Arb!FM~=tlAY|ISvV9U*0YzKgLcH)Ro55xABen@lHH3~SA8X&dVgX( zp!!O>^`6Gq=1Y=AdXHneuFztiMP{$BHaWdY_-bu;dJj<{y5S`0UTOHGs$yT^9Fa$| zW464*@om1H{5;1En*_bg)A;_4FMN2o-;#EDb7Q*CB3-riCpvENdet^w+M%p|KV34i zzYCS2KI?pbXpgUiJ$k(^j@SLug{WKd#e?d{Tz{MoXAR5iIrOUs;Ag4lap#75_V)7k ztLNhQPSXdBjCAgmm)vXCRQ@(^zDdo?yo{ReSCP)-NWhUxIV6HJ5X$&r{$#c2|5oKpALeEw_E$A-p(hBv|sA?`(T_e z{Zj9rB{Q_$O)jzgSHqBqrzkIc-@aG)D2~^DUm-eV`ZK>hdA=lMe}Nc6eg;wh*nc>Y z8&7}nv*c$`@Wvfh&N*6cyl20JhwGE{J0fp0NC?cj$j{XXTp6@Kq$rSm%KcjHMWPaE&0=dmqae7fU$*VA|)t7m_CfcNRD-DdM8 z%Or!hFK*x7uUy?}{Ve;w3igkx9IYRcbgDgj|Ef~ces*8!`;u-|P5alYOFuOEuM|GB z@0@!7Ovg<)$87yO9ZzTdI~`AF{XZQ~yZ`ffH|#GoIqJB$QqyrpU+Jl0cQ~gY`1?va z{toq#pQqz^gzdwHkPz#|S3X3)HP7hR`MNOwOVQ5{+X;?OnBT`EpO^e@f2`%YkDR|k zJX@^3Pu!5%o779z_u3XIzhS@Jo~;rd;>ovTAwFIm6O0G(dHvw5?* zqSs3Onc@%oIuEFx2hI~X>E5sKuCo~3cc#*Rvil{I z&h@`$O0@Gv*G7T!{J5X;`8x7=ls2TE&i8RN+XqfLIbQ6$lyZr8A*xe$ zzM8#W!rJa9rL`s}lVhjJEj{0>a*5OPy)GAP_ida~h-L`hKiqjmyT_|vij63jUg1mm zZnh3HTs|vP`CJW~4E-1VMw3;VyD$4JA=t+U?2m0l zNN9HlnXjhji;Hbqky($?1mpe#{NdZ^Kbib#mp7bCd~WZTSbn$5CwlIDmf#7;g_FUH ze?Numi=;QdzUbq|yc|jAjh_*DN;{L?53KDu^#GAdJNc_uga7m#`CZn}RsSBQ`vuY! zqFCbndr4urVyC-=4cX5r_a(sh@gY6y;Y&07Tqfc1F13s7Jb~5g^gMytX?mW(?DPea z9p`47*Xzc6DZZuteNgjp+$iU{>jp#Cs?~+Ru|XAOGAAwhOACtX;TD_-u79zFK>V_$8+2h)cY$%eA_%VA^Cg9M-cL&(8X5#CHMkaojdPCx`dHOYMO3 z!mZ|i{eFc|e_~&o$OY?H=Ksnln|5^<^ft6lgC+mC4-lost$ZHM&?rh|H>c8K*!lW$qhjx>%_iPtK zzvS)bC9sEh-CB~<^xmv3c8+Ih&YnO1_pH}jgwBR>$=*^j`nGZEfZtc4rL@C?~l!w@c4dY z#FKRD`hEO%>$i8$(fD^rG}^h@0vGUwEIzb5u5fz$|A2(T9=0jI_z|;w3yWB$7|{l_m)=D_-18C5{)pS{ZOyk3T)@PT)j?7+} z@3*fF=UZ_p1|E;k=2aDMe*ZI$e^O8Bc{`K4j|<4}<$uNbHPu&7+toH-qV`p6e-)^we$}q9-$>w)PQkxfg46K^ z@xC66XZ0S8BiObfjw}J%4csav9We z*$?JC6VA(uJ~F%1`VrdYI@l%VPt~rcfMxM+KA&G5_+ynzx5_czrS}pgX}hKOAS92s-Kx7i>ixhj?@%w# zhh7TN^Oeq%@&f_m@qJYxp1HuodON(GRz6y{kIxW%{5~|Y;{4m$(mwJY2bRS94adm) zEb%iuAIF|TwQA!Y-!D)@ARhX&#lgB&SYN;Ybkv8srGp-qA|2+zW&O3-cDh7l=Y8f$ zKOs9GH%H<0yw7Zf&ry6yXIbF1y=r+rP7R21YS#YJ&-rr#zYEcCMK7UWo`VEoy)I+k z+Rsf>AAZlnum5UzI-bk+bEsju|IDQm`I$eVonMWiWi^$P->a}zA|I=!HIqwO5QO%85FzpHTO~YRC$C}l&2`+A&Y*mj$8!GR+~IZ} z%G2)~iS6DA-k(f=!hE;R814_`UYC7-p5OMHr+PhG>FdyT3jH=$BWF*?0&hz%hb<|dfZZsg`S ze#6c5Gq)-I-3J@SZ|l(?aQQP|#pJgJ_ED{U-s;<-hJ1Ou`~vKf`H@ZJzdUDO6H$)a zPgqVb($Qc32LF5fd>4LS4p)lxeJR)b9r^hcKUW{t!(Nmh_J5B9j_bNkhka7Q5BlFa zzV1|eU_Vy;wVgv?|7h4f5Plw^uJTJdbN4>nr|ZGw16k3pZS0rQZkw(9QvU9D(63NA zn_r_H&wMuPnc81APsZ6O$W6@;`^G{!5(JpQlLuC`9j+ccuOgd1v=zzSZi_ae2qP?ol|sC-Zd*+dY|u=*g(wj^e7`^T<4b=y>F(8c=Td!_*2+87|1t5)gOZvcFncu%j$Ej zKC?5QPYU<%(OyD%a6ZBPF!8N4e06Lo4$m)cWIiiD)Ptvg57J}bw%WxurIYfb0O$`n zYvA9FcKP0k_%gzM-}apl68Y)x>=C)$iAK!_t+gDmD;k0Xz3cH>ta9AIxZ}{~z z9g-p4389PmXi@mim%y~^qr>Wf+BL(E+>Jl>c>M{>St{jdy<_@0!_w<`FHC>Eq~9)d zG5wa!A%3;PFny1tSGx?uX}_WVs88yD^JdmFtq1Wwtp}K=Qu&xZm=4(=D~|0D&I+>Y z67sJpqa3#pKjsy4@>9AgKm2RzPYw^0qtZ=2kG&I}J$rC&Na?9*0L!D_z&?P6@VuS6 zKUpq(s{Z1As;{`N`gOa?_&mA)Sd4m8-K}=Jyl|R)w|;qHri^cw7oMl%;KJvG;9}u> z!hgI={c}8^{@LqYTwf}7#quYEFJDhuUKlUq@#Tf9#GZ?V??z7p#*^VG7LLk}LE`(* zW5oAHk<;?R%OlqR<%K;FSHg>h@5qdDT+s;|pI?nD$cV?=gSf)lMOf`Et_TR&>}Yy6Y03($WkMC**M%cPzc3tyEJ+LRYdtkzPg zSA4V4x5(&2pO{awNa;(uZ9m_DhI2e8^}XBrdG@`>wEt%OjE0YGKPMl0E^B$=LY?m@ zd{h1ZUMmmon&r8_9J)!v={INNC*|?mzs&rw+e2P%LzoNZ!}J@!#c~&=dS%m5EF6j0 zvQ!6EZlV7^S@}Oj`N;-tKht^F$03J_|4Mr189moVTrnsXzApXlli4fz`Tp0Ke~#t9 zA!3VqvV6tDVc8FleZ6V@S@%ognI(9Ng@2TJr;6E8wSJe{&%l0p<6byP7Y_^?+-vYo zgO?h7$YAx0vEAQ?bDb7{z~a>(#REqTR{s*G=O@hn3>>z2^Fsp<8m#_59{4kZ&AtcT zWU$%y!0Qb*`|d0shq#8#kBNPE&Ta^oeqTDiY24?ke!OvfqwSX3M>?LdenTsJrCy)< zUFzePLT|C~ml0>`MpLh%e`7v9$5||VIN}Q0|Ae1v|2paTj?jN{dmNB2ACvFbVjNS5 zzCOx)?~9%e{+MsTMS;U8ZAee(5D<;&{pXzbvvKV-fSYQ9m}+ZTVr^m`>e<$3#Y z!n*~o?pD7znsP6|cQFgm`>fn;@=n{w+Pwx_{j6;=*y^YGn=!Iw{Y==Omv*EMW5vU9O&s*^*`9SEoO16NO?$Rn&`A0i-}x#;YekMvr2RVmNw!~a zmG-oGzbxMllfMuBAJV%_=p}sg+k}@sVfugj7f-JJz5F{Yf1#BBc-sA+q1=ABH)wCt77E2G8=gg7l|2e+Scw zx+b&t%W>gp0y90^6Ti=d>DmC_X5;83fH6-c-!nvTFrL)@J@a$D%lBClX4ZmW!PpqT zi};_8hi3u6Go;%{<(|Ob1nb(gf99`NvFL(ldD~d&|158NN{$ajP;7gK@WJ~AzZu{u zNNd3SrwKlecOZ6Ik4INBl|w;#@u0`}Wqrgnp3LKs!>)5VdM4jbvvD+~NW7;CU&XfL zk5PV-$YQ4#IZ@HC?)|Ug=Dx=s1IX^2zVN8M;QphvwOProAa- zJk?cd7e3yk95H+ly^6jjXZTsfZNYrVk7&o~zDQliBOTORpW!b=I#J~N#as^Q`fVSn zPy zMR;uA(Pp~&madL;EAYFF|99HEr-{A&HR8hgi~VNj%*XQH)dWvbMnigz`|$Z{!$_Wv zV^clayr-`VxgGnw1Lq^kNtl0aQ+aS*VNQ^abiMH%N*~A_Hve*%aD~+9y7xcfO}Wql znePov`00s$DCNeL7cm?7&~yB8$9p7yvO(){a-Y`6P_M^`FPL{)@&f2xw--h| zr(P;_gz4Xl^zmNB6Yo>JEVqo5L)#^J)U^!(c(|TY#ycH{-_1~!_ftUcRFpGuU8ZNp z)3r_gL|E=8QSO8{YyRo?>f6&lo^l`gfXb;16kXdm3V@Gnf|ucarAI`5EQkK0SveA3 zXKL-AVHlFlI|Tgx8_IP#Pv4~JF~2GJz5HZ@%GJy3vU%zT{Ribyf3)A%EdYMgTk%v< zML%qQ3#`^@qmK3XHDY^(amaSH)uq%NXOGda}^$%W#J_q_k`aqqK9?=C-~7n zU4k$oJon|^h>s80$fHXju7IgxU-@s8WOkMnuI;Lm`U<$VKH1?TmI z{%k#OI$}XrOZV_S?`bIC-Z+CdWl!y2Ohs~s@XlI$H5o<(rEAZTA1@os{_A8 z{er#L_j?8UCEamN3#=gB+i7PVlW=WK-+**JIi z84546aqdnnZ?xwP-JX11%6_3C_m^}a-ua`Ql>w8VkC@+KIeEUk+@erJ{Mz5h%GZ84 z%byN>w4a;W(Z4Z!F5>&)0MmR-cOGEJ+nC<(PeejIeW$CxU^+g24up6*05|6U^Uu-H94aRNiFG4xcP8#K) z<+A=f1NnTs9JWW|FHmd;;+?;cpRT6-sQe1izl(hkKP@!5L+N+@HjIL7ONS)(pLwbrtiT&(sy0Ib6nZy=U=rQh-*GRHn}#8pB1m$W&a&oq59{}6h8ak zG(+Dr=`B#F9xTh->Cf9w(tS|(p>`gUcU+sH{FSz=JZoJB?=<)lg9i=1+~EBJS8I0v zLFt&_tEA`i4;y|zzrR)BYR&GwDjhI*isLu9==cq``x8n#4L;rCw;Md!;G+glGWdwW zdLID#=K{yI8!djT@zZ1Q7K2}8@J55LHh8_jq20)R%ykjB%;zr0zD(Bp^$4OJt=xyb zptbKv{?(;NjGpfb++TXs=rR444p@2G9^sxrgUvolhqQcaN3j1-^AD&#<6VOa?^Zd* zJ5@eCZQoaWfPdkG`X%YuzvhE|g7W76P*g>^@B1{qH5&aa)nhupF-MYP|BuQW^+NC^ z_bFcQA3lu!6Q5$+SMB{psZVJ+2xWQr&Z)$Qe&!y`hb24Io_b_86m*Z^Z#F^BD}bep z|99HE7-_>8>dWi7`Wv>A@Sin#$+*Jf-485o>IaUhUQ$1B#9;RWhXt;V(hu~s%@YFh z_40qZo`iDQ$#sgr&ZnB4)AP{Ip91;EHTMfzPvV-_8?Q%Rue_dlz4Lmga>KbNm1j-m zn$-i9JMQ1HcwLvm`kcYK&V_X*ga6vvkwJq$Y4Co5L;mF6YZ@aS^lQbQo6XBj0-ssE z*edA?(c83Ls2P2>4;p@5%1P3BQ01=>EztDqAviof-r@Wgh8+@z*BiPfzfj`Se&I>e zKSk1q=XuxKFu{EHGlzhvXKcypP_ zAvf2T@)^pPbcFVE80|jszxZnKzgOFD%o~e-{JUIXe%4E$k7d5E-;v3Ubdf%%s}Sip zIn1B8-=m<1e)^f9oA^F5$bOOCV^b4$#2*}moriS)5z1k{PguUcL_XJFo{n%lG<=?# zQl#J0_B*8W1o;f=8R-t`d>_i|-(l_ThT{!(JR?Uh=@03B5c%DH3(*fm-Y3`V39(6^ z-wNr?>-9L~Bl5hanO@bN!~A)@zI#NyzF6oW{j}1)lJZ}Oz94)&j4(=ewCz${Q$OP8 zmT>=8uD%{HcpR{TpPIHu{ZszfVD%GyQ`CRQHT4I{lsOiEK>S1hlxGXvzu;LGzTd*T zH2iv6A@q9c1@gvvi^X>utnF+6l=BTfZt=4P9&LXxuI)E|dJK>H#bnBh3|7CHOhKi@ zgY$Bh{&IuY8+@a|8x3A=@D_v7XySo941TS^;e7pF2np@nzdPXlrYizFt=6@lv}!>6 zPu`zhJ@=P_w}0lZ zTGe~nC+(2!2j92Bhw@nhSk|H18Or((M}mjx#GdUtD23=3V$UHxdA~ruSg)Orr-PpU z9d_?n6TdL6gBjr!xH} z#Y6g!<0tiS3d#@polSZ-H>P`Z@9=atGTpi?UD@zGANU&kgSyZcj`yDf+55Q4zw?-# zgPbFJ$j(8|RyaKeSyuQQEg$Dz1Ww1FbJ@xQ{{k?`_sntfcKdKUPUlT360P#Z&(Llu zk5FFUfgCbFZtIWmxqO<<2e`gY08jQEB^_tSwX*qln?JU5-I&jp@X9`&Pp%A36d3mq z$-Adb84vYV&e_8pv(v+%i+cVC(A~FVjL50)zDVVlj`znItaMY?)?xrEbkJQ z*F^u1Q9df}h~p6Ic?D=F<9{|jXamH0sPj9ayvGr5O`=5~-rqfjAoB4+;zxFwFSYvN z_l;-s7j}PUbcA(57_-!-SgF-x?TA>J6l)pdk`Hu zJbiDHSGq2gu3yjA@YFtR97%q@4wu~{yDi|?Mi^&(4SYAsajYPA|4x6V<175Y6NdY^ zYWM13-Re#dfXCNC8vDVG{aW@j9#6k^X|7-U9Lx!lZ=lKgwP!jVT5scZWuYtSJZAOd zsJuhFARVFI90g3g-+mt2mD+Jh&v`~Zm^ae=6#=FEyU;W`-)aBR=qN;b?^d;D^PKCH zKF*tx?qrt2X*)An@iw+IY8S-cydP@qP=h^xaTvWUhx=6u(dRV$QY|mFr<%enhjJKV zSA8w z6qB3NeabmTcR}Jad@}@Y#CNvgn=bK<_@*|;cY9g!K^HqzVti2z$4%3Jw;a}$e(-J)+M2()m%{T`#V z-E%t{!9QIo{z?77Nd9SlQ~zZCqr%d4zX+QK(m!k-s7bv0s|oN|t=jE4)_Umo2aU#m zZH3|FZ2D&?TvDBxupKh=qyCv5WLmF16Iy{c_*c^!Gi|RF?grJ zv*jJ~F)zo*#{jdxbPebuT@UX8KekSkr-R=MVGqFDZ|a$FzwK{}Yf6vz>(YCR(s>@G z$LD!`{U($XM{c2x_^mynVx(P zyps4nAo!}~E2ISO4+F|5F8AVZ*6!0DTixr|o7?}e>(4X$qrLlcI)39Ei-7U0mGZ94 z({-nZ0g(Xm!-wB3BD}`VQ~+yH<3s&(Zz1fbPnr z+RnSYynLr~%^kzb_3xriz#IjiH8)v2ANSJa0cdU$)+>_}0u&LMeagw{~cLPal@^Dx^s)-u-lZMz3V(8KeD~ zk@(Bo%c}zZ;)!M#GtDm0Jdi@Sf36P@UQ^*;gllse4JjB+s7P?MW}?Mw^AbIDwTAZ; zPA>nvT`UUdtCYWR;bPSD_J%~=+2_4=VcrN8Ht$FIjp0ezMEE$TPMgF@G-RxV&Z-jAJNbforY zbU$SKpL)ihoUXhcAN{k;U&b$!X%DgYGohcm=IXpedfu|r+TH7PpIz1Z^~HAmL4End z{xZJDpzYy+hO(c@{x{Pt&dvK@fFzvvpL)A7O&E4OnDa+}9>}rpOf_uRYoFN{zLzQm zRwpSzNol3hVf2RW^I>c6m;v99mvr>I0^2^{XEQ*isY4A5t!zo2-^b&?L}*d*PAO#&jF(Pj7Z`Muqrpxhc@BivQL-(mLoO+~x zIf8sej05?^SIaA{AJb;wumv8sheBj}t*te>m3}{uK{|*j-lP2V&(!uRuJjU36z{b9 z;P)&HZV^15-_I+@H?NfRl{Z>@1iZqxNC)(QZvI?jcIEzO=nBaeP0;ERtvN$8kS;zC zovZI2?4M%{<_o0!${S5DhS$^6e@HnmH9Ua%xO^wPRN*ylzsS$$p^Nq1gZ_n<^Bk2| zZKb^Xr>qu)lq;Y9DYwY4i0YFPq`_B}b52mH43W$jbgj{XV) zOYHnmA^I1|&--FJ@XPn_qTWgVusy<6GwJ*@`Dgl&?`MJUMm|xP;MI96mUAoMxUTrC z6=LDO8Qs7iSGooE`%~h|MF#7>xVWP0gz0ygD(6`I5uq3Rg7kfr1V`}|D!*x`vsCdX z%GZS&&vteW!?hX>Yk%|e1xGMXPW?Xi1+=I8_NzVytbN(5e!NnDkAzpOe*1hvPn%YR z$=l>&lNxIMRze{XA$-+k+ZDuwBCAi_Cu^KcAwlOM3qzw(q+QshXl$ zC}Xyy8@=9zT zzHjnV1!3P!TA$p{`1fM{-eV6>@l94b7|t2B%T;i^w>A4_HXxya6A-# zuQ<$q?OxWu1Crj?t$ke^_q;0}vw!N759eL@#8;I0isJdIhas!4-p?+ca=pfzoa2{U zJ;Lk^G4MRXe7=!S>yaX0`0OCOc#8JV;>8HW(>2EQMZWO3zObJ|={^0pgm+z}bPlN+ zBA?%KKJxaOn4PEnhN}ckG(m^2Y5%Y5V#VutdfI;R7(+(t7az~{i>JOV7%w~Bla=mx zm$nltz+V}7@tp|a>m_E_UT!>K^}^`${i|K)8QB^_k_R?Q6gRE@~^fhe7l@`+P*6K^L4+G z^mrtv$M3#1)8mkxM{GQYctZKzZs!Ug(0-=x2TsTLW^X=E!2134fLVSn~_ zH7_*ob=f=-<^95-URJME{zCtH8123L<7C-(wKr|nhRw&^xNEpyK8SqrzQbwr$8e{w+ZcFnVJ z8UdbZrf2s9K0h7X_dTlTXu6*E3G(A%{H0x1*ZH{pxnfW8I`#iO?YjQ$_x<;@Un=yV zKP%-|&A-I`Wx?n7M#uJD-lEOV7sqHjQiz^y>5j|W%kS#Y_LMNST!_&5!V~W^y=iwb zny$@M#QQh-`1qFdEh47}O&;oYq8_ZL@fl)+kEiQ8&B*>XYf{&1S!=WU({-KJFOPTp zU6)Lebn))tb~HWb=Sde!WPYLN3`s9M9;L3_S&nAIbmb*Ik|+_}_4Sr-%ZQ4nYgOYri+1xl#fum#To-526IzzmYD& zYu52E!sRdIb(8*>uuk7=>|CJtqaHGTN3$-LUza&Epub}Kp6FkME-T;ZT+?fGnLdZg zMpv)C*Vy>R{nJC2X!vN>i}LgNV*!^Z+XTiFBU zO?_4EJVQ@(e$Fn`(T?P|@^-O3C^!CpQ2+M?^pSt+?XLN1|AeXE%no$DuzHbJAle0@ zVHet9hWft<5t(1scCqg|G&p$N59j@d+erbN=$X#vWtNYrh#rb#KoG;v(f&oT{ZA!4 zEcaTJTZk%}&i0kY7i;=y3$$MOK3TSZe0<%(>tXR!ou`bSqkOG^9Wv*T`Pm7}C0jZ^ zy2jekC3ut5;+RuKE{@O3@%y|&dS5N{{)r&;bk#YEzbCp#epLA}7(7L3we?)QtlywK zp=*IeOMPMZjRxPi;7p0=iLQ`!M2^3yuW4yJ{|l{$njLb}{>&1m$Q& z#GB8JcFx218&&6Oc+vb*L2hq_eCHbdr#@8@P)@_>zee*dLG@zzv}^Pn`AGF_WzLUX z5ZG}epE^Ii1k8(m+SR@@`+dqVy1c&`>S>keN&9hO_zDTvfsga$`xX6sy@&UV(RvW( zzeVy}`JjUGE#g+6oAD0Qt(J5uc;W{r^(btIo3-1EkY2%v?N%@{Gt{fED`jUzG>%bzuCBZ&ragzgTBd{j4K3&};i|6s`)Gu2-`B51{;l z-7^Bh8!Gi|tyk1<{Y4BEy-)^wZ z1ICrD2J3oHT-jo<&39Hd8m#kYab>;1gNARd!3PaqY48DqdksEp@KS>h8NArwBL*)t z_^80u%1u(St2g!Od-*DT_v(C5b%o9k#Vd6qRC3=|mD5VySd-kh#b7uRJjs0<4OWNY z-{FW?c38ZQm*bVX(ImNVr=`Ep;s*`Z36A7Go%cv~OqB5c9S1D_N=yGSgBKb6DT8%^ zJGt-k1~0StuL#_~;XC?1?c4fZrso;@JO5c>yT2(}bX?%1`DvxG6YdqX(eyX#oBpVbpD7);g8@98FDc{QtlV=)EO)Y$>-ggV)zcD$az<%6 z_F>S|EI&o>J@S5H@f3Bigh_#a|8_a{)v-k^o^qPVmGOkVKTZdfp#|ZlT@y^EbXvbyb>#81UD3|vK zHIxhdEUAItZ3x5@+U>V?0`8aKX!_myPP(;T-$8C?FXd%>6-;D)^Em1dVDWN^^D@E+H}2mmZs}c_a<~md|ks? zpIhnuz|KZJI33gn@pN_U5qeVjr*uWb>4F_JrR&^GKBJ{;_o(Q4dkeZwNV~Gy>;9c1%ZqrrIyUl^*3V3j$A52hyzt!Y8mvELhAw~mUgWi9B^ z{y}Q@zeD@Fp$T27y;m0wqsPAk75Y0`wC{sV{SWBl_d5t3seF-H z>Sqijc)F^@2ET@8t7*O6B+-%YD`vUR+6lYgZsFEXpKkupzl-JfWaR0}L6sWH_IAugWKtv(Yo*LXG$DZN=&RZrc9(K7~-;-8-R&^_nkFmzQ5`)!xNk`LKHn4O zX9VSaisWz6j*t7Y$ zpOcT%8_M~AgI@PndAhv(V%t8Gx6apvcwFB91U#+t*G%5qpOn1aj=cP^A6F0L?sn{a zO}|&zZ=f%e``d=ey+?S(*wchweCJy7bN+Yu z_Z)P-h;rrQ=ZgIMOAKd}pC4!bjlnvCf9D~bpXK}tdpTQ!bo3v8vPJy}qUC(rlci%Y zz&{cl2ZD5@qx*ME$Ke3~NOT+x(vgnyf5&v32=I?Y$GF@)|J2_x9pwQ3NOa5z(or5` z13E%Gr~NVhd+(#2x9AUz{UFU3^?qgZcEsAh^m`VVbQ*{Bd4J&jUY}24xeuY-3F`%Y z+W(kdRrsX+p=~=Pq5FZB?T3v6rlA083U>m`5x4xPVo|CjnX;N_E-v+FmM^X8`IxZhQQhj_jN zKa$6jms7k~^LxLiI9?rZas27(*Q{MFMCS;dKL3@Ddub$iM(Ve%2Hj7#T`P|5k#c+< z_KDE3Y&3M(cS=sy&KAe2UC@54sgiX&`hWUwA(nEfuYHuiyX^dhf7h(f+he5X{Bc}2 zd!EhIoJXQ{>AWK2L%ni7FV*Yal1%FV^G2|b8EtJsXF+cDq#tO}J{uiAZ{_o5PPgA* z?DWNh%Ae!&ecNGw;ew`gnOv&cA3nJpdrgj99c@j&&tE$IaZU5(? z#k%qTLB9B=qsYbeUE|NzPecBGjy;EAs%|8JG&DAtpYqC8(uZnUT7^~TRHxV`1= zDo(%4ZT;Z-RH29R``mk*wL@m_)xS}??cTv+8?6&^GrMtn3gvZ(a;?o#y`|~3Jh!JX z{il(h{aDtlxUP2FH(82lVpo485!wEOFG)FJ|CZFjBn#24 z;2+_h#E0J7j4zc($QR|D@r45Lgz?U|-$VBL3hg&~gz4gaCzP*2y$=}QaZ|o#mKlxj zGAfN&esi@GzfUzCH|qAU)W4nl zzBIKnUoVbNdhdCM@EhKHPJY-=d7}58|NEP=aq3v$!M`YJdB55TsfRxApO)lMB%&g#M78iO^#xzeB7q@Sht|4(WR2 zJ+xEpXZbxiaqW&rNl{X=?>*KQ8a!L;OKq{ia|~W;@I-^PUBW$d2K#t&s=(Dj`>u1K zr?t>)Naq{uTI+e;aryU*_*G?RkXx(SH&; zaUYDq$_M6i3|2ldpJTAf0poOoRZh5fMqqr$(ByE`>|E~!k83L5r1U;X7t*~qcaJ^g zL%LlapM8(gO?sg>!C#18K``?>CD(`fozgf-7nYN^k0U0ZLExc%96&kQ`p8b`>#AJTm^r`J!Jy*y-e*GRYB zd%^k)@ulB4$oio=uP_wUzcTVSvlo}ggCY;(vu^wks9e~OVgI&&fga$BcbQ!*IEGNr zv&-yi!BK;i|75`tgH=Asg2M)z9W6LyuAen=2bVTNJ}FPym&-2>>x&Ia1%xdJpCKIm^G&%Kx&#YYqN}!RrnFuE84(K4$PjgO3}$ z*x(ZeFEu#QepjhiVA8{Ed4}-PcwL`!Q%}s8$8b7*#f8S zb?0`G&uwHL&k`8@=V03Dyq?vAqm*8}Lwb?lE;Coo_=P4a_e!~3)_2_c?`E_i=PZfmm zW`=UUK))LqZxV2r-#I4ff1-YEkIEyJQ(fiO%nyAJ`7k~L6( zjT-4L)k{0fUbje9++I0<(PSpUt#(wZ2pMN@gCk^n(T;FnGVg`wc!| z@Swp54c=++A%nLYeAwWv1|Knai@`??-e~YKgV!5;+~BnapD=i(!IAOTYp~i=GIOcG z$%Bja{ifOScDqS@TI_IrP3>i+q7l4QeuXu2T+>qAQal=ETP^yh00*8TBuZN0&|KOXI?!B<%N?IMr< zDc2gj(BgG}d|X>>ul+0Pk-w#~Gb0x|T{l&50 zAl>H1beHGSjVHc!S-LWQ65s2QZUuf5&gPdc2ZZ@ZlD(@GI}?;f4~m;QfZ z{||zn(b)fI7E^ztxBtJB^#AYM|31(;8vEZR{5*d9zrUINtNWJw$bO0b`NOCi|Alv# z-8)sinzaS>7Wb~hjBqYU@13b$O$hzyOD4;^dbM`AZnS#^t1nOo++*J*nT2S29-c4a z!}G{I{}rD%QDLBy`1HOFJuj)dsU=Bt4eeOnYC7M{c8=>leHQNLi)fv)&c$s@@#B>G+*8?kUS3o%c zha|4+JXT(g)Xz)N2K)HX<5Q&@JO- z^a~9>Ch*W+ljm5xb9`(eZ1%(UhOS!LY5MU&%ZJ8kJ^1y0QRvS-{WEfY|53I(n>Bxk z_bjAq#V@{3CiHUsj$Ib-r>v?epR1?nIJ9E(>U~pSn0P`tvqpw`A{}A*<5_-9iQ7w7sB>E4B^i)8DT7DCa#N z;raCEOTo@ZxNqU9u$TCqn%?E+_chM~`-_R+`o$A;IEs0Ym4Yw6ABw}%?40^U=$&%m z!~Pucgy+=%mU6036h6J*6WR$elm4H)B-uYJKiJB=2JTJjoxM zyu$ju81g{-CFw%BoP!*pT;2t_`2Hu1pF}?CypxJM-KVw$T#+%#g9XR?7EAiQNXLNU zc)hnG-EVL8g>wBQ@eh%N6RX(Itlslk&`F)zS z8}fzkB1<~-TjV`$GFu~U-yn|1;$4bof(A#`o5~W8@6Jj3YHx?Y@k)6`@hTNSd=m)5 z6EC;^y4@d|SbLegL(?Vj&3yXD7@oS~?LV(9;T*@2PTsf7ch4!-53>8{;`Os7U2&YX z8=C~o?h6Hm(0qe$w-7{PgopZm;3K ztJl2?@pkb``u&5d+8@3PE_M)C=L@WR; z;;Be5=HWkQu*tXdWrI~8NlCwJ<@av*`F)&M6Md%V_v0D zd;RLwa_k=SzRrUNYdu}vsryWl(sv~s-xJaD79CJ{nc82nY`?!|}!z<(M zb`qYudp`6`?KC}?UwH>&F#g^yuV}j2Pi*JV(sQyX2BzAyTnVph{;>eK|F9Vy&uT#j z^LJJ576grS>=!vU?9Xe$KbnYP?P@DJrhyJ`$EKT~^8E*1eyj75lt0Vqs;m)uL;u`M zz5_W>&(v@AO6pf9I_S5lv3Q^Av*DbP$$$D>LC=1G=zmD7SCpPNGJn|9&JGjwPa)!A zdFPS8n-$LMy*U1Qi6}_#Me~s!=A&F1(=V3vEzcJ<(F5%|ltU{${0uhd@^*Tst2s8% z;r^tn@;s%-?)zT?z9CZSuQG!7%<5ae>&1K&O?p29VDj7V`)f@f{@oUSKZ1|9udVo? zyuJqd8{~Crr{s5kgn2Kq-(ov5;0f(zKJ3HGVgKeF#E0$pPUs`Gm)b(HgR~td(|F?g zdczfgJFx_X6&fAlC&!FU|9NEPB_b1c- zjP1+lX}gBx;J#q>>&5o3NWPF?jz>a%7bAVh?`H6e`8|`@=jC09J}d9o&S{4I&QHFY z=?`iA2y&it5;^w|lk>b5a-K74IlpI=a(*Y$dB2$LHRa)Q5AQ!>_>C*Hg1g)ck+v_{ z{>4d1h5YN~HO$V+C*l8P!}y=wg8%Y}{JX!W{k)F$v#u%@3eQ(zt=H{06bj3SR2esWb;&KOT2%lBPqQ}{aAgA z(3f=TKDl^6<(_owzPxys_IHy-uaWeHNb!X9zd-0OEB+Do*A7`mH?OWuyC(SD;+qkC)P|>y&x@lg_^Zoq2m{O}C$~*lzOFecf5TJ!QHR_^^j*u>Vfi*A zUn@SiPnI>M5M3<@LcH5^cu8MK&z-FZiQeSdpN$HC}liX6~BS-i>t`(zFF z^9Jh$PByHScSy%Ka&(Yi(&7BQ+UOtyXzwI{AzCQ>V4leIu+{XWegpg83^u<~d!NBG zm9D+2w@hEkM|E(Iqzma=nWJy7$>~B+K)t>6B=YAxYav=H^u{$UKbi6@gO$Ey%4~y& z`#s8^`TM8nz%aREs--izr{@Sv&bE&$wEs(yBeWm#L-{)W-GO`y(e=W=>lNRZ5c&GN zVsf9#pLAjBA@X^D%+pD_X5*b>HqTAMn~itc(H{BydOFUb(cy{fIv-waF9^)}Nr?Zk zC3u5`wEYg}w=Q@Q!ta;l!MeE0i+nR5^){2~1~r|x*M1JVr%nA)xIQtJc2L#yKEFwP ziw)l-+JW6~gZ_%ywO<)Nm3Nq5{3I7W z@Pu?d`k>Zh(#iImq9y-h$iGe_;J!RG0*r@n^65^+`9!9t+}$pij&e+_-A(Pm_Yn@7 zJ@6t|JhSj3-l2O1j3&hT_WOc-J%!1c?#6dMO%h-p&+KYUL%lqavn!!n%|z&ZnEI%n zu>6mxyfyz0T_9Y44)UFZEC$5i^ z@K)n@ufLT0S3qAjuF`uuynpKDFx{7g51mI1>$}*6*==YSpD??i9NfRGe$&N5U*Cgs z*4)nl7V)`>ftuEdoPFSUJ=y8INcYvSnb~T z({?XZINcXEUtuzVC+VCga60~ZocqGue~7;VzR=ETpP~JB!`@hr`K0HY=PB&xmD7EU zCJ*B6Lz2+W%Ye!M9Zl_5<&=#F|3mprzf=2TgJ})mzw|wW1qA#}fveTB1n|5wNe=77 zuMptvQF>l8sNcLVmhDRi@_9Q>IS?c1{?n#(vlPn3zFz<^oDWUMo7#M4_lZuCY*FUqk-zD~`#T{&S2yKng5Zgr zj*{uY#&1c<^x$;39*mAu51Yz@r`VU$$1H=S>=$#GMM!0G%&-Y!5cQ-uD#448Itc2hZm za6E7>7HoYaeeI35qjt*4vHf~VMaO4E8; zh}6M^e(5W$pCjnurx3~tU?pa67klhG_hGxRK4@2|zn|U+y{;5;@SWWCs;|8|zZT|O z$$Ta+=KBHi;T)%=Pi|2?)1J9AA}Jk_aN6&X#XZ_KMZ!e{GP#z7k*3O>-0OB_%5m9y+P|q^}>54VbVQO!i$(E1`FU? zbsOsEn`l2duXi8feg9M_zXzMj?;jQaEpwFbnt(EIE&WC72ZrnSZ-=3IKQ1X9RQhYj z<&ATV2A?ok$CZ^mKM=UG@2JIV|F5TQv6jDKTtoRh_aE}dfgbsx0BCn}!B5{U?~!p- z-;V9_&c?Yr4OV)R(xAag5B5h19NOJJl!yCCgpN>dx1k)`4Ij1x|Bc`I`kw7KdY+^U z>E1~`_DXQX_HixGH<+JgIka8!b2iEe=~;?>;J8OotC`*zHecU)8ZtxlRPgcaLLN_WlZ1Woq>U$c7nBH(M}|Cy4pTKkaTFSdapJaO#{ z0{i~Zxb|s-Z5&YhxWR50A2wL+Ba}ye{89#f%I&#L=_#@JVSeG);0fpD6u)_P$Q-`^w^hwUQ3)pqyX8x`@Jy^n6gfd!xe3R%-lCqhql; zki@<#o!Iw&`^vg5-lt+r_dmyj<{$1RRiJB=`jvQ(;+u9ly<1lQ+3wB(oS2`=%M;^$ zkw?7O{NC-7UF3QJNT}NV-^DiFFNX6oR<9q{`ef_lN#{cf52#*~?!5}zez;`O`vopU zGo%1-ul&2^;dpj?uHMtHh5ery;E8(wn|FZEeM;|GxI?K|)*lS**3<7tdX|eSjCRue z_y+U4JFH()Gki!V_Et9-ndY%R>{d7)Fg@&@DDoQ$ao-1sdu>Esjq)>pl*-Ti zRVqLAXNldr}rO5ByB^ z+--F3QvZ!}LaNu@-`4nLN@w59v!#G!?iu=C@Kk+YZ+5KRH?&(ij~zGoA3Ao`4>9<@ zjzXmUiLia23teR6srP9AVWDJ?hJ3s;%U~lRByvHjEX_Wc3g&u~7nbf1)TzHhM*eN13)4_IG6fDo>S ze>dpA(eH0WIQ92l*m2(f_C%i(JaILVcT)O@$R)0-;*-)}7`)ozbw74o?KAk@D#yV7 zWnL+0cPL_(e+|m7RMi3Xl|CW)R#o3DcvhEmUCrl@xc`nln9x2yW$k!};kz98;_6b# z?{bR!RiT{6zk#VFx|V64)-t#9^W6wd}X8@+AhhX^!`z}VF|Z(J)HON0Do?0(>H0pbbp_UE$z?K zO*h>ax$QNQF_fd|r>^)YXYxgUPQQZutkm>D{3pnd@87ije&mN1K4kM)DL-Q^+~^JK z#aQsuj85X|+IEAK>-Vcpj|EKoPpeChh&)*?NN!rLga>q^yOjF>kdFU)dviLNziXS? zPXisOM<_aK*ym{cPrp>@_4X#ae{_z}U9IW&veNtOO+M@w@}c}srM}JI=H-;$b2t8C zN$=mqNH)wC{9Z2ckxt@!1blivzdt;Ww>Z92@cF)5zh}?K<6U|@I{VI1Am2|@zFM8r z?;f(;FQ8oaOB0OG6z{oGT>5>YJUw0KGeq?Rk;`)i{>FQC{73(WVufc$cFocbS#0Nk zun$Ax`Zk!oAU$1y`}d?<_0e?^rG$0^?Z3nae2LwF2R^=Em3%!!zKowd-RK`mxii|w z%Q&~0-#=IZAGR;X&w2QIE&VhpVmTkYHaq7r{eB@Mn&ABtlV7TzS;~joO}x+S!SWH` zcF>)tx9iPzZ(xod_ctLu?*=`rchrNoOMWhv?d$M;UOK*KdOkj%lav;Ud>GECq%>b( z=06n7izTIb5}x;0)ccVj9r^n7>r`H}hjiRMTZ+xrNzAV@{m0>Adi>r_o8R*GoBWoM zmFW&ZUMujMu+Pi*_hVhJtY>;o4?pmP;l3~D-X)nH<2!*EPi*sOp&f(#H*`(besZ|a z<~SlKpV6MjTUv!N+e1FiyepFr`v>?JC1*MvTF-nP4(Cin?tXt-D1Xuswr@uP6aPWD zj%w|=tKhfuO*)YMF{h&t>AFL;X7jdou88fDq?@Jmx?j6Zt9!Hr z@&EnUqft*gx#GNrdW%pGFG0mFME@xCG}^D-=jnbsZ#OlipY%?}ID&j^c`f(hO_ly@ zb`R!R0%!9p(nB~J&Q5U$?UHz@wkUq`_-jaYd^a_ zN8!#_DLgP+;qL1d-c?q3(TfF6*JU2>zO?;*XP2EA!}XXDA%^gqx*&wi92%5OI0$#x3l zNIUgjwDGv7M(c4&$GfX)8wFln8Wen}4;HWYqhA(}NPomere!M>YFQfN7mODay0!!eBQW(xZ!$WzI zKgwY~!YPNdfOl2R=&mb2jAy?7xvKAY!0OxFr3eKb16JSWE*9ALJtZ@H1ztTx?IP3z zEhD6Z{IVS9Zyf0G@jxNc{eE7rsXz8w`#P;&*Oi`P`>7&t;(_T3Kc}H0pr2=YP&%2P z@ySg5!IR>%dxqi^-;c%aLVVnETZn!r;l3X2>vf^O;JzHn^W%7jd>#hu^Zh+-v!wj6 z{>yyyCJ7e%oC89M=Z7%#5dTW9>uhdJ_q|-YFEZV_EL|Bt|1W!Q0$@i~<&9UpP$V6f zgyn_Mpm_~RXj)r4ETL%;Iv~)rERE14#4SzJWI-{Hhomdzl1^AcL`?u8#{cK!b!X}L zeKTfeoG~sl9UUFxIBHx*<2Do5$*3biMWW*5e|~4Fx>fJ>5_m4(|8I%8eO{e=&bjBF zd+xbwf!-OU-^%eyGb38ON&8Q@oEC@2>xZ_EUoYp};&uFbIk#3+|C{$uWj!OVu;(fI zd({0}gL~L-=X0|~j`D7XUH$LB68bO5`*>f`Zt-jJz9OARj`tO5zi@^~LHA8bzc54S zMC0r$s0LchPFdZ^SdA<`3g@_lo+JxrnBT{}VjqTE*hJBXgO z2b+(kr6_(zXsnHAq*YTft7JT@c7pLyFYt&K9?&mP3V9D!l~?z@#rq(h?LL{~N3jP; z1HI%qwf#wf-jn0%nfEV|vKk1}wf_RaD92~2mc#Te<4(|j1K}5OIGLVm`>1XvU74N( zo;?)(yYm^f)c@|PazBsdtKB}O=Tz0dodYwyn_l1-=|B2DkLm9OmIrp|>LG3)Wq!^5 z?0EI`P}TApADL&$)>9(Sw1wB+HQH^CvCmh>gAcVhrX)v zo1UdTXZ39Rl`89*90onEoQtaIeYE+JqSy!8>2)-|oya{{*Ho2X=e>G_p2exKkBQ!c zb$Yk7XJ{h3-)#KzZOVU0`IA}>P=5fuOmyBYJANKsE&hv!6%)7zYmf9_RrZxY4!0lK zO>q_Uy{6q=U!Tf?)42kPV={UK{u8gO)Q|1cguWrCeb*wn2kVRP{vj2$oJ;=TUJ)ckKnHYA*PkS@ttwSi6+7J3IY#D@{|Fn_%fnlu&>KEMmLEX5= z@c#k$WyL2Nt7+eh+m9ID9>N=~yms#^=I>w$wqJaCS<0E*gC%k4MDD?Y9B#RW!9Tul z7SVy!2lyTHJy;Yo;fdpevlZ6)1zVqhKEHhv+9kYuT2E|O6f^Sg>m&vKTC#&=-$oa| zNcL@fQR1?A-@#`Dj`tmm2psR*kbNHG%`4jX9^86dhI-UE7jk``h9>Y|*clMjOM5~4 zy!S$k9OSWmSyrF4pG@R2z1Qz$*yU5LeWBjS^>`zX2wm|1G_@Z(&&Bpn^Ac?T$v!rj zH>7h!`d;kB_HV@B+gK~~T>k4bapta#m2qabo{LW6c-aq>#PPCUD2(Iyl_H)e#QoNO z%>JN{0!avcyqWNq(%*nrX7^upc3c#AZ=oDyM+3U=rz`xV!c#ac?#gR>e~ISv6mPD=N0@I|exbsL6`rB+A%S;Zz;LlVUw;>S zb?pi5$F;*tbiTvd&5voSYh;bpr<9l0c}3nC_56b7nG`-zVXdzj+Mk!T9`)YEu-u{e zXDWV|!Y@*Ik;3OHyhP!bDXe-O6n%w5s>f}r-(hLrrTe5|M_0U!^F{OTmUOP{BPkt! zhR_=nJ1Nb*Oy1A9Pkt{qD&JQq+@kQ+3b!hJqr&Y9zeZuPhtiB&6&Cv`&3GfjrAObz zX>?PczV|f$PKBkOqZxmpu+(!j<1vM$o+F))jPBm8ze_!rW_*xgcRas`esSxY{iow6 z{}0u-`L}HRY5S1$db;>LS6=T04`o}U7ZxNgctLQ1@bBWpgPUxj|3~VtLyC3rgtq^4 z>H(P#>k@xL_w6Yx^rETz1lD}f;=K&RU!$grn3SL=mPe**5_ygj0Y};ytx}##<@a#5 z__e6>i14%f2Rmh)9>()Gvd$ce8BzapP~xI(!NR!V%OF$mKvm-QG?iZX@L}= zbiL>=-oHoe@r&UjKO~GAq(0*D>{&vusBum{*TMU#x^u7a5X#xTg;D1)>nCd4%BgFI zTPa?H-2or{)0RfEQ|)iN>+WX;woVf65IWYcVg3kmTK{I}Nt%15JUAa;p!c@F$M(yC z&$VRlGl@^t{boJ=%6B8nYx{p@iF=6GAHcr>{HflV&oa*DHQzcu|BJP~AzyRP3eITv zSQww;oeTJPln)fa2dV8Buy$$kl{&>9x{p`>ln+nTCgpJTj{S1(zMvPAJo)2k@tdAl z4pa&~b{-Yu@=FOG>E)l}eMHbR{pU5yHL_eEfUTaO?*h?pUUm&<4D}ue*cH#)Gzh)G z6aQ*<6Y6|ex8EuGil=f)@iW&;SUf@D-3p80(0ZD}q6dn16&6NxZbRX-HUB<^=PA5j zVcEA}=ZcDYaM0|iRIlw#{X^6y`p@ba_I*52h8`|%B)z~P($hVe0D9tmi4(n7a*(s} zIv(0j9PiPd1U%sLbLwJd5})e!EqZk2+)H%q{=Zp|3LVH@pg-*#@w13*L;DOz7NLi&E`kV&fN23hp3A- z|Alxxz3)rx0`lXb@fX_xjmtR2?|5bQh5Uz|{aj{eZk&bs!9FSPZR*tMPn2U4xfrBe zKItwi&Z)X|8VM2j(~B72HnKe3ex9gd9!1XYWBd<0vwf8|KY@I|pil+v4f{DJ@;%$b zs7J!b{MAyTS)l*hc%j>SAwg8HArVHpNz%&wVD0=q@Xq6u;y=~rKk_&;9Bdc3>F)&| zY8ANcuLR!KB5>yph67LfQMX(Ns9do;W9--Y8kHwoj=bI1)x+Xd?AL+bcD)MvoW=-l zeGJq558iL5_sRL0Ra&k+oJLJ=5_o90z->zf-Zm_7=j$b%QDFL`eZSZ2E*qD*@g4lF z)i30Fh~<{}Vf=cM{>R;a1ABvgKhyccf@9y9pQHcAxF1X7oGRxqA&2V^4r@C&_)^%t zwS(oXzn*dv+e@#u*X8AxFnoLchd8x%Li=W<9`w80H2!DUo$urMJ;%@TesgEO4-pvj zd^y>bJO17Sc?VdWxc`HHGyF?{UzYdKOF!_}3hd&w5uUZH?EGe^-+fKmyD(f{mU7-+ zFYTqLEPkuEeo)Hi@ZFu6mxUZI|0eK{zc(xP3Oj^JbjNS6>^I|jN)-;kG^ly_ctqi zj>6X~+@$bT3ZKES-D_03?^1^2{$a*t2~3K)UE`&|dk5zq-|nTqv3SO{i>%$luAsj& zFHYpG#^mumg~Mwq@Ry;!9uj(}r=JqO-RB*x zKFIjtPT>o=(Sj}BM*s8sJjZYMTtlw!z8ZSA_PAB#(tStqctriF#s72v1t6we9EAaU=)n_&i=_bp;6PA~V{%&C~K1YLmA0xZ4?`lFX_8g_Z!}z>Eq5!A8 zi+hOUT{~}K`-6(}Wc<-h_qO11>EgU_vfto^{64feb$~&Rm#(KjE$)Wh76^vC!&S&AGdKrw0NJ?%TzOApTrxh%4>T31?vIlkzt8;|480H zp2s4$+{M3$@WVl=mnhQ? zte)+C_8yFQA6+Yp=Via!gYs3a-%Wz=+TE2^^`-S&vwcjX)$b`RklQ}StKWGfFZ6>N z%KE9io=>rRm+X7Kd4CGmZ?k;Xlj?&U0X=Sgyv(UT(|>Xfs}djeZT`pF;m9H;>)H1K z;`35x%kQ)v^fdm8w#d3dTu-;i`?wuesizaE+~Ha|4g7?bg-fQ&cgLeit_2)6#OU zbpuhdacb15>nu&OF5%YyRpcLWzdi8n9tYQ6pLnoZy~7$nU-v;#vED#1jo(?{;Wpt{ z9AGrszb5`U9FTdYsJ>tD21IZ1Jre_Hy;L4u-wg+Z55*mVUlMw@F8qR%sFHx6E#ExB zL%iLB_hR;`_^t!}!l2@jZ7rd7QuyD~=zCiBU8bmB<{PXZwsU;6?}7c6o%ie6c_YI; z!(E)(yhgV#hBmT8`H-Ho@#{*+(IfAn_l@)?Qpndnz9^?eZxopT8qM9~QUE?fhcGt+a2chk$PzO!p6a5syDa#OQJD<^!Nh z*)FL**KQE)QzlTcF>ekF83ty$ZeLzL|@du3N9`A)llF16Xf&^gXQf zuO<5K{TVI5+r;Ej?ZWUofM1sPurpqdcl2O*mk}P-Bik?4qu8A^lx?jODe?J8|oc^|U}^t*mPjN)Tn*G=s7pu%RShZr7d5P4UTyaoDm7_o_~(xW&1trkMTRkDS>w_w?DT%Eg+pV-zkpUelHGsEEn#xL_7A1_`i>ijUicL|f}_J1keUqgF?sJK^&)_#l`TN&m=oK7h%L8T66Rqyxe9fhdJXQEd#Gm{Eve=!C=b;aH+Og_~-w%r1h|`aZQa=mFkqdO18^TfK68rys z$n}a*?1tqjF0H7qJ#KxO-B9~N&6vG(!;#Tr`wz4BYWL2fot!s@-Q*`Ntl<9<@K?UG z%wCkg?aS?^cp$}J+=l12mpQ19b&OWgZt|1Fj@|b1(Q15;)BASJPFsbZYo`cVZQj@T zo1ReqlOf0b)#ZRcLH_3AeAa`->u!5RNk{r6f2?=1TRe7eNpWy5=kLye8r2J&6g}X7 zR+akCPibU)i-UmAd@hiDBd1D={IekcT7k3eEuWjkbY_X0j_>J@_qUv>^wjTJKiJ%; z^+)9>5Qjm zna+B+^_yFY^O`OlTQ7XU4dhq#o{xC{$F3ui zzszFud?wEyYCVA84CEU=$ar=imP>y>$zk(az@N^1_6z>t0Zya2V$jiy7G@OP-6-jO z1xX)84M0AzFT1ZF`sDd=ov(-9QuE=NdCGV`M93%S?VR%Mqwx{socu=YBiP5|#^fFl zIWLKIMN&P*S2{na?H>7l+%>WN1Bb}2mJ*Eu{eP9FdG9j%i|o*mhtK;GGdU;oLVlm@ zOaChwKk2!UsA-45LkC#ysO|j%Z`&_$=c5ddzh9pgk0FOst}k-A>V^Lp`v^W?wOlU| zdZU)>#8Kbd{TldAA+0Bf{5BslxLe?+l~T^3&5~~0D!!54vYA$1}KB1ai3k*!R}J&Z3dYg?}z&?=@s$jyXhzB4igB=LZ8N2 zV!x}!?qRRME7gnLyL#D$^A-+&$m8<&iGR{B%DfNlOB4E9o^Y4&bN8R%ytPYr7_j;) z&~MQ4J^28Yul!l1=W!aAzohUKg}qKZoJo`U4ERdfc5kk8pzO(aL#%%IV_6 z{>=Vy-v{c))ytPzFAG%e0;gg5Duo*rzFy%Lg>P24l~b2ri*w!xeAcM`4-p^wJ{LhW zZ}TkdbsE_i?Db=idz5wzdxZxK_?C0AE5K%#;VAa&mSZ$~HU9sb_*dF%wtx6*)syy1 z<&P-b&uLixgu-hSezx{my}cB7N_z}-zRc_~tgzRtJ*VwGYnNHOEvh|d?cCMtc=o%7 z^y=cnp4|3*j@tVgs!!O#YQpa+%e_Cn^^M$KmY4rt+tZ5~j{Dj8yphyLRB!ez^+D?z zS`Shmw64Lh&D$)c##11^t2DLo9Oi@Z7@qap@$Uot+AH0y@#~QKPmMq9-sW&n_(gN) zaR%C7B=#})Y=uSMXl{eT(q5yvGC&FkXDa^n`hL2?S1CM2;ROnN3d?|!&J~NkhSZ;J zQ$My{{8wp)u2+@Cf0bs0OeeajDCrf;C7s_R>D-$+U0xQycKeLCGfekNGoRiW5yLib ziGFv0esSv?_Tu`hi>SU`d~_);KKmcX@60EBYp2Tx#U6Tw#7=D8w0Hg)#F_S`&7I3> z;C-3nWaO)(-+Svfvz`KP_b9)AoPVFlxZ(hfgGMd|Hp3(-&MykGo1 zjzcm&(tXx+{#0QZ2hsUch4*k;ZGR2sQJ}{Hu>zl)NiW%PhwZO1{n|L&?i)ou>=&!H zkKnhYtL!;Q({H>keWjGM+W7MT(FOghGw~kQyX<^zH+`=MPih}2;+g@W%jF|EK?9w>^n}$ceM7iUkc;1vtewQ)(W2NB53M8r z2I*M!mgjmp#O+|h-}~65-}~4p=c$u=reK+#XhXa3Ei=gT4%zz!u%QC=gaHQ1v4_gh zyJefiPph|zKI88;3@a?-`Q#kAj*IoYxobCnP4*QIO8H%Tc*4;a=Bvj3-bW)Bz}5dS z?A9q4)=6odfy)a%uql-1{lv$$_m$`m2SgvPT!z0H_zvAgneTHL-ou2~yX8ja*Sor_ zLeB$~FB}y8yXF2e<;(hwyq-63+riT$f6@+4Vu6$W|LfVG+PIDO2`X&$ApX|+Q;X;0 z`^wr@NM>iFiZ*+z9yODl>yLYaxYw9@M`s-t9KV76B){EBD za?(ph`?2}UMyW4rKX&hy^#iVccT~~uMEvr0vZrc(IY+i>^)PBV=ZbvATSU-&?$vzu zvpcuOho)>_=S0pY0v~pJUjyd9&LZtlf3|C@^h-m-oZ5aGtY4f>@8k6s(^o5U(LA)R zztFg)K(Ni%y8Tfb=?k^%u0vT|hVmj`^E~-bnSHl)R*8P3$CcwMf}f2XXIGIU=06|@ z4Nd-8{mkAg-m;wkz`6w#1v@|*pId}qqi33gS6<1^&D}4*chmQ=@x<#MgYrA{iuFO8 z|98(Xo?Jyv8z1I#PcVUsb*dhrYx_!}rz!MP{C&j%d2j1h&9hZ5syD{V%4PbOX36&A zSCi{up$k2NPV>C)@DJwytRBN#@z(SDj@v1Er1Im*AGeEBTTckQoeYP!tl+decPdXM#h^$vZs$9l3Mr1bizod=H=uh+P7v$W41aD|*}6kedP z#+5xXPOx%?J@fRvwCk|vY=yPG_gtm0#;HBmE4)wX%lIJv?i?-;r^oiS7nd(*xU}V< z$T@-YqhxYi&R-Sae;(ufqppLW#jojH`bMT7uY(g2%ASgspjWdy*Z+Lr{!0Ht_iQq~ zxc$$&j~TiB|6ZaOe|JLLL)QP;dE^Q|I3RMna=e%1u=Ar?e;CWr@Mg{!^VK-Fv_xp*QOxN$Gx2)>o;%c532M?KDb{} zdw2V#1y$s;dztdby^!g|c1vpuc+CFH?z?lZ1BbV`O&+hANz7(aE{+izp%6sc~qc*W;w|sM`d?qjCOT{aX zNd7s;oy2mFv_?nfwZ1X4&ygV>pzcyIz4vJY#eXv zy$o5u5qR=lEjNxuWP|p|e&{kL=Z$no+I*$ZNB!eH^z&tsFH5)i{@vV0%>K|0PA2@` z2BDMKpUEq!&GRJo_&cUEaeI7<@dHoRwGa=b_fJS1k;GRLM_4?9-yw+`XSF+Vki}VU zJcWK8@luzA2fh6AO`;#Phl$MVH4+~3`ODpV2Tovx**Q+^7oe)4`aO+*H@if>A6z}L z{Q}>k`dUi43-te0n&!Rp=`XUgGABGwg8QmbZ|VI49jxD|UhcuB@x8!Ja^GVZ-z)Gn zp2rE}dj-BA^ExvM%wV+h_wl{uMUeyL`Ye~Lo`0}&S~jl;I|N1GeWq%;@RrKe!wHuQ zcAJz-99^|?+kSyZJ29VX_w{X+at-P{RnxG*L%NQ`aURC6g|nkb_Ir`CW+hZ z9HLtvki+f&ZT3)^3)_Y>rOq37m@9a}sJJL$d={6!APMdXi~T!HsVrWeb5 zs>-Y9$HIq9Uh!|{CtQA6d54KU_+HaSe2260QYF)qwNJBe6J zox)2LmVJ4&Pet#O$4AjTZUIzcZfbpume`0ac-imt8o9LkAPh z*SnS09ZCOqtUT5p>3kE* zQF^q6-^cqQ?=A>@yu|&c$3(B9&#)YF{%8iYiFz4OSmtrU@&gJl(D$1ZzKY?6L7(gR{|iR@%WcUO#+H=!Cn(4sAUK;~vzss~6m31AP?ecj)b%Rm&+2 z#4RUHIZ!!m-b3sv?_a{>;GRwAu>igGzhyh=*(7${tMf5EkF@gpo`){twD@orr=_;T zj2}MS!LZ#o7e3t1uM*+`VmI;ru;A5@+?cNxg=4k7e6`@cYp2xorDShKoa@hf>?) z4EHvDOVZA-a|%D-K>v6BERP$Udc1Lh^>`ZBTi_pE&} zr^R*coW}OQPTEIo|La=#ec=6#)YBk?+`rrY4do{y}+}2;bPvl<2uW3F~&b89MEne4;+B#%? z{{nsA)F`m>r~SGD540Wz2I^rurO^AiH;|nkFZtZ_&K!qslHY;%=}X04kuR#3ek9r= z{R-yqp%L7>h{x{DasA{*totJ~Jv9DidE9yYmy;afeL^?9XC}+(=7&7APfYTmQP2aq ze)cN#(?_^n)BZjwXMB(SVTGmtpmjWjrT?Jsz%pFi<%xdFLKp4sAmkPGr|jWN_f+;{ z-QFC|7;PyC{ec#ipXObj#*1*EQDIr94<9HnOyd;&eYfI?K52Z$F#H4jNdEZOFnzQq zGFO(Bl4&;o^?LQoh}ZETAN}XO_7?mrFw$WD6Cq+dn`SLG`u_|5EvgDOIVL zpF)!u^jP~aeL(Le8W)ZTIhuc!KLS0+Uk(2*3XPBt@9pjlInMAZCq!1$R7_alODC-v-*Vpfi%GDAU&hp@Z{m3 zw0FCYCLG+%^5t_UfDG~7$go?^l~hj9!-IBu2GW2*reAk2!OD;BYv=s2ooK#raHaAQ zd9(ew%>zK*b4cEBaJS+M0XnzBu<-$2GvV31sg*xkF@^O-^)LGF6*-p@8F04tkNoxb zkR7a;F8VD?yDQbtl6+;!hj#3to^BBs`98S?akJ#J`Prppj7)!6`K}ZEX=h66*7Gdb zr~VE<3Kr3sXrDBia9M;(?Rxc#hjL_>5%w8Eq~N>Sl~Mg zoG)scB6_&9N#P^(Pw_pXm+&F{O7+pSSIRpm^&QSG$nTx| z`S;>%)l26d!8^nBvQOl@o6)_bKIOcA_?X(qUGhF_muBBt`;0Wsz&g3u$8NEYhlFqV zu*g?@MC2-UuHg5j4a+56yiD}hwnWmVMUt-8d7l+B?+^}3x#>O%ejn=h7E4WS3X2_; znl4mW?5NZv^Feffmz2M$Mc=DFni?67rWW*fvFE61rov)>QPXsV#okIyQx%qWS!$B` zH`;&B_E&0>{wy36dySf;9}D$<51KC)e>JG~(sWqhonkl9YU$TPjgRQN0sNlsnHIbq zW^a2LcK!Tb_$7_Y&|jclsDC|-nsxEezqkYCbsgdvF06AllH{XU@ZPPO-v zz-~EMPHSIR==(=B?UNL8-%I06x4ef)4qF$=``XUpd4~0(=Xjs;8iC_^28|2O5c*M* z=p)?T!u22JwcVXhjOmFk7e5fq5&Uq6^e^`P!JfefnSO6mtMD0;`<R zZ|E;jBIxyeno0{i8DB?Rw4JRG`*iD_?X8E!;r^ye^PjOUZ8rtjht?SHogYh;M)rcrrgu>oC%PoFw=o^CY$Y-27m; zZ8y_tK1mqhcRb;cwr9k{eVNd^tibw?+WO`FWu}*v^8OXt{|*WNN;yB4u@C7# z!()^)>f9~-h9rL_AHARd7PS*?ha(GE{5VdIq>g zeq8=I-h3C+rTGBiUp^#ws~aVq+9JPi-zsUB>Pg6ZBibKMR=yvm*UW!`@)vZkc(eM4 zg^esvsB%a3(}iwNfq$oSw+x#fFU}DCgeRz8^qg1J&gdTYSA$dFy;<~gqqLv!a(Qp} zY-0TYc;=s*?^XFE@uGW_UhHpg7ka~5?g6#edkc(MTrYB!HvESDW@*c>C0#A^XVK!r z4BLL}sPmw}_I;?bl-u^zmR9@=zo&INE`O>1vkHs-l;U$`q95DGoSeVjBlO#LOWHK7 z`NiI7en(-kvr_#Qg_kJ5_bR+h;mryc7KdA5;g%2y-uke0_S1P=c;ZnWC z*>*2qsb1o3`wo4{?kBVFvg!TZ7KhnAE6Kb^m(t&-{5ljqpm4jw8f^RYh14O zU#f3a{JomLMd3XPH!7_CPklk*7JWZcVQokC(-l6V{4_o@p)O}bDeJr%TuI( z(|M+_EaOL-KNS1ac);eJLY-f*c_&&o)%*t;-;GPN@ioUaL(&c`zD8V)DObc%U%a+j zTunhMJuY3uyTE_XBQk#m7g0GMBynOgA0%<2OJ~VA^Fg0ko6HM@T_7=ze8b`!&|2}yi z$NhT+u0h;?HQ7-(IKI8C8Aorpdfn=g{0x_`(q7i69>%wq52WnnW+`u3#z)2n^}Zc= z@pwwUn}gpUrK=W@!XD|I2j{napz(gjxoloEKJJqDy9CBM8#3B?CD7S%3H9@<`$dks z1aD-iq~Q*sAC?p*UEo1~h==;&!$`v(T`#GZbq&m0r}ua2ynoX&=0o!aoX>5y1<17> z)Tn(uBx%&PMDRNoaSC}~g!$L9_|3d8fnD~#y<~sYVe_w?TEA-h(r7-Ne|PW4IY@Fq z{;q24dQ`nL?}8HLnMuufzcW7%`5JCd>L<_DK##45 z9P_wgOQY}`TFGf8pZ&ro6n%sbGrNh8FH2ItQJW{_EJ-~_ZBvBrx&jl7+6wZ1o#|n^ zzSnrTZ6?Ffslq?0uaAp-cCXaBW0NmhahUyJH1&w2!p<45?q>SY;)C+O^AM-up!y$O zX9#tEVnnKg_b|fc;67ob%@l9riSHMlqjo=A?Y>yx_jcd1-2+|J`Soy>>S6VMk%QVF z9(<1vlmk!Jqr>SUKuGi2ct&)d8S{NC5B-C*c`5#N{NfS@c|8(u0&kP(b*Gk7?^g@& zE-+$om5vKmf0OY_i@zah=K;~z3bC8`dwf&(%I|G^IHh~Br9Sn$U!|rG=Z5)$zqfM_(H4u_mnfe#nqTayRKHqbX`iL~P~ld_FV*)eEOr^+ zD_owb^p@#+Z8ve;zDD0K()Y_0?ozm2>31qD?XRTY7oc@>E?=p>L*I93{&t1cUgNlZ zy}obJ_hO%PpNzt4w;H#*{TKQT*RQjm9}+u2T#Wt=aWNtU`1vTl4$-~s|QaXYgs(W3R1449U7%)HYr8yX~i(Mx9dx-u?rD7kdJ4 z)$%`s`C!xMPSPi>v#5L)Pgm+~>o|J5IHkAYQS`QT!g^bp(wkJ6-J@Xj1ADlI@N8YV z7V+P07ysWC|9$ySEdD!`iT}R4{Mp5Sr>&8GgxjN@fB$p*XK_ypx2HeHf1c>!&+#Ak zN5wzKe{2tSUh>cJ-&GPX{0YZ@FQ%=B6N&#eZTkJje{;~^)G+?Lme!d5l;gjpq|aK! zfB*A#S8vZg{yQtBx6$LjGYHS(KU=4=@6SYSjp7HIY+NP%WxVhB0hx~q?~!>scbqUC zArjEr{eD)6-2((twLv&@+(V< z{Rm4iKX#|Uu*(AdiMaP-(l@3h0V5mIZap7O@(A4((l6TlJAHRa_zcK?WZEyJu*_4^ z{3XNgJ#72Ie}IV71HQSJbNMBou3LsXM89FL;8o0r>i$bwmplxNQRhQfSI&cSJ=i?x zTA?4c>3mA3j8`Go2FwqaMb9>0o2Tz<;Yq$XbwvH3j9={>Z&H7U^u5)ej7Oi%d}zzt z>qKb!7jnLRnG+8WOMO6JIeKs3mvilK4e8&$Lzn2az;Xgc%OJfn483{|KdR68_w@eg z%~H>0!l%dVjMgXlchE`ik6thJt@H9WZ|TaJ9q*&wP~MN+K>FXIdfh4d4D~xbwhtJ1 zgno1)`=hs=C*uL^kM7m^w7}~@$y4iR(3?B|Fq7z`{d5r?_-%Zf(80{($fL+jX((y_ z_0kkIeL-9w5M|`|k-4s0$UZ+rJv(SOZN3^{zCB1+@?OWvc$oB@)Pqaek8PuPY z>Zh?T+D9h(Y4eP+ zT-(%tW%nnY!)oO7K2UUapI9;8mn8F9$-X4@msd*us8P~zyZGl(*9+qPM&fsmb)GyN zl6;l(j<4&<$br#pKJM&^@EQ}dwGnr zd*ORUAK@bcPgu^y>zPlqLF}+{okH%BiB|Lr-qbZB*S1D(Z=vo>4PT{v8zhC_hhF0S zMkfLi7-{he(Mz#i^kH#Gcvbdk z>wD1z_1!g&zE6LftM5fzu1bA(@$VDaS9N(x-%`=GK4tX^dub;;8xI3MhkQO#Y9>cV zZszKV@1ID<#|4&y#u=Q3kIFbKd`!p3kBl=uE(u-mSxr~O)NXt{Q{>WqFI=zkmnF4v zi^aXrLxEmFj>T`SHa?cXFtl~n)zgK3cAUH^Gd_My#;xvoX&x7E5;?$c7H#39a*O`p zB7>I^iN?N-0zG_p|AJfme?iqf-b%m zJ_LJ$2-xU*I4 zcZal#36Fzyio?chqmF|K4}2Dqln}Jr?-Y5L5kOCJ4qeB=1M<7=e}ml&Qu#+62Uo!# zBK;#D`#){3$1)Cn2k9psZ>ryz$T;}ihsPKPZ$Hd>9(k3N?^%z7ho?xrJpk=eJw7aS z$K4+npFffKEm=pDcrRQhbZmcBB*OtOv~k5&={H6l7Y~r)>7n^4k?$m-H_`J$;gI@& z&6kX;bX@F9d7tsPc#;%|&K+^QS)9};^4hp~T|r@qkBjmCF^P{uJ!cXQX+KgSr|zTk zO%Ga6$Eb&BgT&L}sN>-M5+`TpLFS3R<8hvit1{==qAe1CC-Wj3MIZ5bt<4OFlT05n z-Y8Dead6vKdCxbjQhn>ZTvA`UkM1hbLu{WDm9Ju7-rsO}BOT{PE7miAI*%=OR?>E$ z^hffl2MW94aO`|v^Y!e07zReMDE3giTkIfQDfyzQE2Vtx1^ywLD&v!4yN-KxKE%## zMmI>lr2PMn)X$r>{0rs1ji>EABjR>Q)O?o8C1JQ{=Sh?E?GFh(^VfIkxc9CC6HfNe z>9|+V!IV~vGVWcxTlCpx<6bFmWaHkc6CL-8UXpVz5)aWnTA^>_-VHYHJuLNBzf#Im z7CU<8eKG_pa?YwsG&jzq7XE-ksETYccM<9q~;K$GwlR zTwA%`@;PxZe@f%tzodG2CgWc0F`kIN#~b&)Jf-hNtfyx)?!7Ig@6pG-_(X?0?!BSQ ziTln{e>+3dqNIomA6kHQQ@NMVUH3eI@$x`|*Lxx9XN>PaKNwYxH}kwxTh=>;5{(n7 z4-R;=lm7h-`rYpBv~t+G4&=O@6meFAQr&+^`x$onAS(|5+$kK}#3cknR7 zwr`s3MBt|V;&1exy>Qzh`F*bRD|YW@bcOV*5$(Ce6L>#nJYIK{pS&}*B^4CE#~=(#fV;}~l9%63|kN9+Ul zoZHg?z3Th$MEMo{Eye>;gTR3&_Y&IuK(1afZwR?QOli-KgIuoe?4S0g z{YmVf3Y^dGTaGHecaK>Tiem<4Uwv=v=X76v+diSYP50I7dQiCi+akwek)wC+Y~eHi zbV;v}3BKqixp$>E^L@Qirk&9JGs5S@#1GCQO0cs6rLeQT89RHEYiB#v51zp6z3@c! z%T1!M@IvH|t&|IPVRk}|onf`7 z6B`vaJ1GcUFLA>}?4(p?XVNU&->D$TK_`l z{G}a~CC*9qeM$RI&cTYGsl_?i!aan6kNt|qX>pv9jgQI+zS+yy zX+5q->whBl(%A0W%b85@k7+N3j6PS7WiLZ&FLwX;Hno>dwU_N`FN>vJA8Y^BtNmBt zNuXcN9-uMU18Nrb(3+9|G1ne;rtP7q^=s?k`P}o_4ndDdd1l{cpZ2|-qV7-W&i#h% zvv?u}PxN%>#IB1cAUDOKdLB0Lo@6}G!P7hAI8FmkIE<>&{8M0Q&@m zr2iFvlJvh?&ba^8b`GvxCZq)ctM10|H~5gZfANzb&M4logMJ-Uz(4m3Tdb*Hhle z`o;a?c&r>QAIRmd=WeBZO9{6?|6iqPweOO@fMm4#rSq=L$L+M@IdPKeKQ_z!pd`$FbFnSU=9rGL%)Vn?Vy94;NZ&mmSg@*;cQ_7jGSGQi?ShZfn z;N5b)*eO^1z4*9(z9{^3UvSj)8G+;a84)QCFH=Q5q@8*sf2~Jjwj`TeE;j5v>)oHe6){^_1x{x z;*4}(H1myCED`?Y^_r?Yrzrm&!Uy|xF;Fmn2fOK_pTO^6e_GDnWWTnL*v0!6;i3HW zAAMh2_4kOh!wH`Qec0Cdq`bwA(k|^DkZ`+{tDDy8zz6b?*c^uwW4 zkXvLvH`!0z%JrY@CvF#e=q<1SQCpY1@3nQp4tXEnKO%Be?(0>5a5Gf|J;%IWxS~<` z3`u=QQ(G90Hi-RH?w|bx>nG|gNWPV7UoZxGtpBwA=kb17Id;JNXMtz;c$>co)qm2x z!b0~|1)z~#%w)KDgRURGO8c26vBPKyqdE8T$^PE>e(yecZ|9vV_RZS8eB{IMME6OW z*u#+6gRL9Bxxfg?x}o^PQs=K3&%Re2-^Zu(4ABbhFO&QDM9=m6C10DYKic^t=RQ8h zbME8QeA*A2pV4_BTAvnq_4_jRJ-bl9Ut{Z(wy!a{mrv?H*{3UZknGd#Qob9NzSxbe zS0?v}tkL&kA5naNhuV{_U%Gym{obJH9rMlX--Z+>KM22!^t(tTF~Z+ou5or?tCew@IIyEyHgtMhX6CGLr? zknwPIlf?U`7q@;)f4_SG>t%bi91^#LJ9abd;%^;CU;mDND%RI9=daY))(PtipBPT` z1uH>4?Bo2#2lbyLJd1NIPORM&Hj7y@z+|epdVbshEp%PyS)CugBE?-=+FlAZZ03J5Qo~it#y;H7sZG5h-WX zxnAVHwZMd;&du`vR_zx%r5%OZFWS6na&N8fBhv2{(s)Mbsr(h^NYoCSGxCMoBwtif zZdv~d8>HOv{qx62zc^d#xwA{kr}s}qdS6|L!6H3T=Q5H1k%Gegg0J5Xh&q?(d+irH zR|>pM?7vd}k4U|pO@>O(sOM`&(Mz6PZWlT9{})pjtufY+p#MtQH_cSz3D6okKy_Y=F&eL44Qx$kB& zo}KH%xdv_*)c+uDp0Dy)T%hvN>cs&T>MBcdOjhqCpD zX!Sw)UFVVMe22(yaY3iW1!5;jT(F4olDI(hk=)a(dZ>sC)Gp$Cyp}1ytzs7%CyX8! ztXIA^E*5)C_A!b5C2_%irN2h$cPQMi@E(O%D!ftYuTXec;pGZ%RapB!y>}`(&(osx zwErs~P+0muy6;ip4yD(sa67~9ybAogd!D%+HC**YuT@5`|9f&8-w&y^G9 z#P3&8e;@akS1>!z#`E^Q4*RaX``z9Hl;7Qt@de5oZSh3k`rTz)kANHnBF+4${MmV{ zZcqLGhDv?TM182KeByl@@%;jO`FB@NjN4r~KSFZ4df;*lO1Tl2?j?NF z+lcme;Jbk0(Rlr!UhF7dUx@FAJE(HCaGK1YHwwJdleEe_lHK!ZdYWBDPkG)gPV>v+ zwpi%1NM@SHV|%f4!nR)lamn$7W#_`Jp2Ls|M2~&<7yCn~*en|*Z*M+P=JDKi0X>25 zM87NEm6`uuyCj)Mu(%=8?_YjxLxc& z+$MHU@dTG8TD+B0=m9OM`TEy##-4V`@5TvuAL)5TjA!wTXgr60<7wg_wF$jG8if!^ z+TXE>@vzSWaNx-VLVi*g|2{eJyx&s3;+4{lO&;89Pp_zd6FKvfrT@!MK9T7_-U7YH zehG*I``b(S@OIL9Bj6L;qj?%n5DAj=%G5ioLpe zMm;0{;>V624LrI`jh^g#*MDwS{I-SeeCrE1Us(Q6sfYT#oQCDc72e0`^72!h-md*% zaZuvAr6hELDD;$NzV^BXCP(!n{@1?C9S;77(9`b>6$kZultaQVvi-Y5!Y^vuEqsUe z3*WXqoCe+^W-yU*zQ8GGp5k*n;a1UOz@t-wb)Qx;EUr9t&hwVE-!{3Ea(|QY zv*iv4g^$gn6}9}uoua3}yM*PLGie&{v_pF()0N-oU)1Y$XfJ9|P@k)#l;NZ^Y{?+KvOS#B%3@!$&dVg#G`5?4x+4jz6_M!v3)nC9!|0VBGgWB3HHR z%Tx9bEVQA&5WVXBl(q8`$uIA}&+oJ4t7gC7yUDfRPjkNiTkO~7-TB8Qsf^J zdym?dDLl-n%_DSAffpis&~a3@KG6@pi0VDyRc_B)J|uK+Z(F4Fgf7i%D!fGLcL@Bj zR0RAdnZeQMLV=C$!pZbI@y|~#Knz|t1s?v!KjAiM@2@`(ztA};k_Eq`onWMJ-KF>y z?TvpX{~+yu`H;wWd)u#=RyZW`MQyT<84ihjQJd_0v+v-oA~`{~)Fyst74bpObbFKB z-%!%~c2|-8!Y|+6DeW%2g#dc8c7}2m=y$ZICK`(XKAUJRrQh&7b@80$xi_G4Xg}V2 zj`SC>XFSPyw#i%`&}kw%#U4nD_1z=#JK7E|u#otwcXwZ|P-my^(t)1>etqhSpnmwldv3T|f`{ zdv;yKa3A@DI)eKqPv`!-Z}MsEAM%sWVFK`PYhDZtdC*_Zpg#lFFzH)g<)=Kr2=qM{ zPWvW5mv=b#O+JNJEc27+dsFER=)JosO%FHU1fIkVz(+ilpL`zI81Rq2D2cN)RKug}njeFgkgbg4IkPd?X!XNCOmr=WjL zhCU*az`LCO1>X7GFXSh;vi$=8QyF~hJhXl!KluU=Gl2QYZ5~Vs`0jcf^qpt?3+Z3- z=UZkVbsM}BINjpWCproKYwtHiqp$9e_bWI>E)@*m9D7bJ7n*$bKX1%6MCl^)QaT$Mho zOWyzR?6iDm(C=uM@WWwQ{idBq8dSd-&r7#+eOZ6fyG8ch^sW{^LHFs%d);Rm@3$;7 zd)_Z={%7;0AYUIvu_@r6n+(c9p%69MZypKv7WS_@^w#nK0)xW1uj=UhuTj2eH+K&cg!Ckzk8qd zZ^;FPgN>RWt&8&aaFXJGHt`R*RTF;k2;+}lPK|qYpG{>sC7y)+6^NBv&eNIC*O>mu zMv=qDiG6i--Zhk`udd0vnA3J|KBsqk=TMrjyVh^v^g4eYr#}B4c+&_XK4gEu3%pO! zU!Ze>_Zoux>Mr(f)n^(vA-rxm{-{w!^^kx2WocjEG;Qe=;A9#T`sQEASE+@FJ zZiTmi@#p)OaC(8?&Z*D82i_0k{J;ymEtKbCU+3%j zlkdd&Ht&bP^X4&&$j zshSUP;Qei!PvB*mugANJ^S#@H^6@R^V3*$ZI z^(a2zz`H-j7x*H@zn|~0%h&yaJp=SJnehi=e1YdH{(atMO!sl`Ql$?#@S+%B;1HdbE!L5Bu%%b>H%^?+@|-rua3+7g!bq z`|8$sD;V$V-g3nUOz~@sFYt4f{@dBJ=j*=WJzw$R=_!7V@dc(2rLa72^Ipk#U-UW^ zA8_EkGR7B}!+MhctseH7RUeoemt5Ai$2uQ5G=_bJ{7yz`ase5UvO7*F7TQoNns z4T^Uo;}Kzcz*pdZRJ?88DT+6f@s5k}1pbKPmAziYLw_E49L_L3fj^{p@AsxCULE6! z9f7aFA5^^ed9P5s%NbAX2zUa2K=C$va~1C_#uGaNp1|7`?>(Nccsa%sI|81-TNUpi z@8ybjG2@9H0Z-ufDc-xiS1aCY81K9MJMaX4RPi3<^R=kA0^^At0Z(9^zpi`0yItwM zf$_wSfG6;SO7A{zy5eD67kFYvz!Ug>#ariHt$5ckp4bua1YWCnYrK~z-b)!z>f7jQ%Om`@fMN{ZHVX8^3=s!}DSo{Yc=wG=_i2@-)XV`h~!IQ4B9+`0N;l zpC`W^!%G>S6T{DC_{!!q8+d-#)p z{)Y!J{Dz%J2MqrZNVm`L;RkN7e;qq+yvGySz6M=4!S8rw>niU3bC^dM8RTpn6Al9w z_r~+eTkq7#1wz62{s%qjar^6l|B&RzdwANso@a2^L6;C7ddZIFgx-fqc39p_8t)$| zCBO6cA2WQv`+V45i2L#G zC;P$k`UXi6+t8E~Kj7PZA{iDv_}w1-ZtMLcqz61UZ)2(5^8|g^gM4-laV93S*T@_E zj`>zRw!hovrDiSQpW}NPZ2h&lNALmTvF|N*!=ULgI`@M(J+GfHDchU;$@ARJJ(zu$ zdefiz_ozppW*IJeBeMlIx$M3;s|VEYhwmi5O9apKVC~Aa=fm7i4vL+MxYRDh4ii6f zNbObZ7IH6h_BGf(Ed0JX)m~-3&gCcV^|07^S>&^J@A@sYGnC^))Roe{TgDG}N_(Px zxstyq`OTgu@|}RcXiV(G*1MLUAawfZegec>ef~U|ulKK$`FcN+`Fj7yJP)7uf5`Ln zdH?Yo;xUxlT@SEx#AfGq&e+ZmCwe`=JIO9sM8Y5dY=huTuUO$vmfjo6K|i2W6hq|5Xn0Yu@)JA#SY&|0DOh{Ff^KKA9i&|6S%s{m_3M z^L;vp__!8)7Y(?47b)LcWnR_)w#=*gzs@24rgMXn5O>#t@1gr#zE>&Vx66F2|4o^X zCH*3b z^P4gWo9H=^VzzwcxiW z)eb+a{PxTIy?>E^CG-1r4&&xp@Y|R2?;lfsFY}LZyL&44RE^r*o>aU0E9KMXV_rY+ zKbgb0z82*y zPT9eQ%4eRB^_jf?{T$}EYQbkw%C29md|Lb!%;&o~%$wDM&*oJBG)wus)St$D{v(I^ zxLWY(NZGXvjQjkT_|44cJ2}kj)q>Bml)VL7o@W0d=JTx_<|k{xr$5zxj_^pi&wsK1 zO6K#89Of-+!DoHSkN$-DoTSP zFFCBM)PnwSs(oFc^go-!I!!I;A4=Khi)s|Ef3lzl#~^#3V`b+=m3 zZ%oy3`Bm&rstw&KDf`82Q*G!TN$CNzf3>08k@7znJ=TV9Yl<#b#cD&hG1XsTHm5dp zXQt?4R=zfL*Qe|OvktYPdnjeUSbeGu-QkoTFiNNm-9xE3;Ab_XyE)Y^zF#xCds2S= zK+WjxOSOy7*NpCglwbd3&FJn+*{`gi*CKwHlG3l7Kd1%W#*`k)HPgePRJ(YzW^@}< z?O4vS)ItvjQte_*&E%b#vR^rWPz!mFr0iiu&E)M!+3)LXMt3+>Z*q>M7J68gva_pd zCvVFCUR*P}i&Az*>mD`gFZxsV&{#9N>r?hC=MQR8Z<|woN6xX-f^J93&SV2yE$A*w zwTq`wZ8aHh?n}x0M9t`~Pqhm`S$aZ`DlR{#3izUo*O!Q|;o@HKRM6Y8M}^ z8QndpcJaZQ(H&0N@3xxJJ(SYJduv8_N=gs!su|sVsdllhW^|{d+Hrr)=bsG1F7~V=U8gtcN$andv(p^U7xDA1vR7Fk+L({FkK5htWWu0Imc29x~(ZY zE7VL6i&FNGuNmECDZi8KJAbzOnERb}Vf)D4eciY}!oKs3ecRW+-r0|hOKa#U_DI_2 zKZkFA=<^GF-%Ovs2-{p}y+95iiG+^W~nMKK~}UpT=+GFJk6t9|cYTjWh^doHv+tjYEg%o=C4C|G6Z8;QgD@yPfYz z>hnXse<$z1$VZL2_b{@2x^Erw-Fme{m*lha8J7}Wln3V@0`J!>NFVLL26o;*$H!5F zyx;2M{aExvS8k$@t?rO}KG8QlA<9Dm?0Z)u(!F`OpX?CyY4VaDHn{Xie%!l*^F5oL z^FE+|3ArwpKI&~E^dHU8$A(hSA6}p6iS?eLPohqU{`)fYP5$A#()7 z$k-X|5_){{b?JJ7Jx!#ZKIYORJ0Mf#dg^e>3;O?aljxD{YXW-wT88fFM3>H2YI&D? zxc4dVpGseT8@s$yT{@&UlsE9U(!V%Qu}to}@@M$)d~Q2m?9^l6?PmPEe~J&kF_xdX z(BT(&*Rj0F2m2kXe!uSUL;YI&|750K=-A4H>Sg$)j=fO5pk1K-EXuUc&r!X&?X!J? z^#8RvO&|7Hjs8f6KG%Q!`0eP2u0BY9a0C5A8N2%14E;qDl>cWL`tYNmKjnd>T(H}n z8TzQliL{F+GxX7qfc~e}@q zDf`rW0Q@Jt(+GboyZ)(L-?9JsrSf@-{r_0@edzo|udr|U7wGpkvhQQ@uOA=9uGc$y z4ZH&^*I4qr&($Nz^Bk4u#!P#gs2`kYdwZ?ccY*j#q`vQT>I>&QAt&2us=P989;>|f zX39H5%RB!V^*<{kkNNw3Df=5H>SNo}C2sp5{iFY-d!!^^11EgOYo3co`_Qs+)mvS8iI2rSr)as^A5EY?dY4OwT=%Z1+EmWoN?~J>jT3%KJ_#@3Hh_6Sc3$sGK(L3iK5GSpD>quT1x| z)-FS*J|OQj>WALLwVSr1S7z+U{LDhOBl)gJ_B-D6-5jRWofFa8$ z;qSuoJ61-gP{HWIyiwn+g*V{uzB`uQ6`dmT;rH%4`ug$v%D!Iu9e+u=K@s`^CiL^U z0^xF$Uj6+S9KD!+qv^swnlAjJl|+mlyoZKm*B!}6dg{pByK(i!6n`8q`G8OV#rK&9 z-Vi|2-*k>25qH3!n4aEvQpoS~{vQ54@9)>~r_cC-Cl`mf=lyYx-@aFX^4>%~-o6`b z_bdcnH`9eYXjgU*@EreMz9$xP0O3t~zr;d5O{Ry0zG4ue;e^D zR`5HY^z0s*Rn%T!@vDd^ zEH~UP<+S_Z`uw>%pYnHnUk2)fx+JQPcKUbh`Z%ttJ<9wd$^kmzpp09irX^Yqxi2GX zTB-1{l{4@j7rE4);m>|W?F8c^n6}w<^LfuvGvvQ4%|nxPs&|kKYN*OtS7rSJ-$zU5$7Art}d!d ze-`Tj^5YNt{z5cY{20Yi@*YMmh_cYmkCo?WV{q12oCKr7tOJURd zu)^ZE-1&9Tfu7J0z~7$VPvyN^_?X`hydUuot~^=4h?C5fcC?lACExYX_E6ULVE1F| z_on0TVeZ<`@+S8ltzmd9{$H!=CpR*Gln?!q-7_~9o%L1AasMBz9REzaw zu4QanJe3mjH~_-?dOiFcGno|4}Rau9c@|0`m=r~@GfG!vFhi3`o65$TT;%3 zm_F>W(oZiOm+p3QTnRl;f&HPiOMHv?F8Th?GpqNcoU@qjSmm5W1F6Ig!5#96AGUE$ zB;7KV*ZQM2#YN7 z@%M_PT!HsFDgOr5V^asi;jROc4)5o5EPL8R0bgRj7}bw&za#4Z?7l(zem3*5aTwx? zU%e1?q&(rElrx``?*qAbPY@o>%X9u{Lp!HE6By^5h&WK&S*YLJ$>$KIk{_V@WB-zA zcj2JW&*y&1d;(g%27WRQ*`u)NEo$1$aD0zu8Q3(xK*Y2D{8MkO)*q3f&=YNGWje)O zLvTwEeJ_}QNBeMsN39|cFiYA_N;8lf?XiPX*RIAI7mYTac{byvom5V{C()H-v~f|1^n`jwIZ<9{ z1bXfzJ$HKzTpst{-apj*-3`p2Du$kF^4;XrFW$pWp3VH-SLy0!8^?hj{pXb=ETMYE z=pOA`+l|f>#^XnwFAU4t?$DU&0Ub1{vE~gw?eHz>cru|G(TWrjODtygzcgIQ)XK=e2)9LkzTE)N3u;MbWX(KV-YO#o;?zyRiL?dET{$ z`Kjk|yLH$7j=1|I$llGrokc_FfW02IPiH;uAnDE4hcM5-*Inl#cO>&85-*LF@1mDT zAI5%w^1&sbUM?ZNSl5DoiB=qu{%;Ui^gH?ABN_hL{eRzo70Fu^e9*h%h9rJImVR_6 z*-_Gu%KW<7i`(Dsa_lMFe~w%(a^O3xTpp4Q&&c_b;&<3#^eX9RtzXUi#GIbIKb!OA z{T5zFa{H@4^?vg~(hKyJ?Kj`T?GwEb?CT~@frqC%z-|l42MkxwZ%)-m3*!ae=OqrI z{2@65u_{}0teQ9g5%ihIc9lDG$#rqW~ajL98%SM%?`kN)q6 zZArgt?cDuN!yhW%xSZ>4HkUK-W^s!0|DpJw&-^6-|6{~kbD00=@m8bb2h9GSO}w?k zsdvzWeOtU0$3Gfh+qyy#le+YnUFLHlZ$6jf{P-Of?0)wFbZz`ps+Vv7hD*gCVZH|M z?LPT<{$?5dNRK=J4?i|CpuayXDg5t~x6#`FX8pZKQ;p+hJt}b2Bm8WiW2AIu694JW zI&yw;BWDQ9GOo(=sw@1YmQTBsz&n%iOkNvDbjxS4Ji9O7=JU|6pq#P%C6NpAe~09^ z{XDa@Uy0Y{^m~uf`UO8)D{1%fvcQ&=Kj2=D>PO{#Hgf&TGmtBP{C`V-x>4lJ+EHBp z%eDS#5*~W#md`^adK<6)9sT_sKCEZN_(Eq|gQO*`U$cj3uF(CkyiWMrxT8m2*gl+YjkCsz zd%m5Cm(b(UcQ%>OSosdPaT*m5H3a)S_2!AiN$!40+-TR>Ql8;#Kg0p9rOSdd2f3pBoRs-Xe>W^76hSPU@8T zhx~EGoSyt~XG;4mD?SnVQ;(09kv^a&*t|Qhu!xG(t?S`&d?e=V&7t@Rs;;Kr>r?g6 z!ioqynV-Y@KJ+?=;-k^>UzN%asbH7?%>DxNl24)DWV;A`_eAUhaT6>fI)~A{=q9RQ zz*oq7$cg9o86SOu*8gl?!q%Jr81Yd9*V}9@?;k!sI)VBB@!}(&`HP`ev+LuW_HXw4 zY~rJ}PQ8O3OwHC=Vn3$+gS&r`&z1FXHSs>RkB>4A?OBxgN7z3VFWG;wP4Z)2l*gk+ zkK%|QyZ)Wp2U-&LeXe)*JHrpI=puTnb$mMpz1(#gED#;^V`nM7tUq5u^vs__UbMt` zzsMN$&(6?CIU(hkRiodLp-_p^$FhhTi($Ct@%nbcACrJOV zGxT8>)%5?|4E@;?r2pv*eHw-_{j7ex41Kh_iRkBh8TuywaK`?Bc^%C^QRj)!b0Y2b zR~fn{cXqz&zlg5Ispc1A|Aod*kIh?U=YN2|{dZU&l<`ov|8B+)i_-tjp}1|d{{EF@ zXi41mKF();*^Te6p>ZhqAZ{ye{W-@2#a&Nu8s5p-Je&8j?^+=)VEep4-jB#|i1$y! zUq%iv*ljP|3-lF_haT-lMz;Z;34@%l8>&x)-h;w@yWuJiU1IPG?f+ zuHW1EKJb$D=RZ{Y`G3j#62Q2w>g*@k<2VW6C7Fpcgm@I&vZ7Rpk|vI02vHUi$1G76 zIVQx!Ec#>noeCLnmFm3-Ru1_Ni`*vmU8RD5k$Bx7V)Ki|nSu}e$20zUQn9}! z-G^;`sFqW zoSbJ&pLQ+3u=!2fPnB-W$UMn8k}vvRveIpSMwj*jHcx5uo#AJ*o7`#FWXMeb3eWO~@4_VmOp~w-q53WCy4o z9AA-m@N=~Gf00k`1Crk6%OgJ8yt&FxQV!-(0r3Cqe2duwqdPxC^rxWm47w*HeYcbs zeP5R7=J;{Y{j-86x2u)z<7|JUqb)Cb9n&lG8xg%zlrH1*12Lb+OYb*{UK=-?euWj$ zSDWXu^$VNdPx86#0ong$bQWh|^h$O~@j#!?qW*lC_=uz@2;wEamF0RXL!KR?^e}!uqr+HGnaDs>HDkFf4C}reugl@4kqv&kX@6tyS`^3X=fUzYOFo=ETe z$5)ffY5C&u#thDoFAHA^*)RMzBJyRySIF*TI8^_K_TMTj{*TM~T!*GhALw?;)kHkNH94CWVdO0}RLX9+daq_PHLM69XkRRsgLWacI%e|#c~R5AE!xKK{qZRD zqt?T%!2|l}Uo_7fpTqk{<`3Ra)Hq`f@vq+b>1K~_#@7?^^S3V; z-Oo=2e<1SF+9&N_7XF82X{Tu4Wj5e+6tD7h)Y2<_L}8P+!wlDx`!|v3jMPKHAIr64 z{IOj3Djh0M+07%$nF@XP{Ea?>G5?LO33lV(SCageAr-Q3J}E~peGudN4O~uaAKp_{ zZdeh1xaJnd6IO&Dt~sZ$@WVBWevlu`blSRbY17Lzo$$MWMyJPR+9kd$?P2~poqOi| zg^bLLZ@>+i*($0fffA4u=p>-%X6si@=4 zw0u6A?6t`K*!KF}jK7e*p2K`u$}40$7`E}W%eE*i`rxwd3>S4DbSb+~-tU%jeR)pO zyN@;sgcV6={YtuFGV^V8yZBwk?^>rz*guOyznsP3i>GJXw0$}VGx+;9Y9D_-89kfX zGvgD|Z6pF*PO?tW{&2KyXQ*1dzO5I>yw|$#RY{W z2N|A6^U4sZT6Er9MW?ZAg>sYbzcZ7hz|Ap;5Whlt<`@e+v!CV5zCbbb}IOc z&{;OQ`K7`pH%A$c<>rvWCO3x}?pC?!$sW=7A`dP*m0`bKlXR_kgzVw2r2JgY^&BBT z51_V~KPxj{yq~Ckbs@FSshq!S;qqg>BCu-y?jlcqO}dEY3{5DQ? znIVNmK3!&j;nJqH9QJHo!=Zbilf$q)UFj5g%9lGBE@XQ6eZDOAvygeSrk|zh#V{1h z3mGnDp3wL0`u<^s#lE`CLyAx8Q^>rF;qJ23rza!pV)?S@T_N*6O@EZ}g%!~s*SwA6 zVb}1Ozh215K$iBEaQb@v(m~=k_>8P_?=!p2)r?Anzjp3N?0eSC@yD+pe`(X4yE*toVa|pS`I%0UC=(XQZ63I3D$)sF8d4H@Q zv7F01m+Q|7e|L|qFOS#6^Cv>D`a8vO;CU0Ri;dK~-&Z`-IqWXWdT>wH`g7C2J^a3& z9-aAEE&RJVUo3|*j~L700e(;84h~)GUV)=?rTZA}-hPzBo+bO`y`Bs2xp9Eo(Jc_W z=9>E$4lA9UE*|$RQ@EYq7b`0mF6nqCtgO@bi#30*!kwCagQl1M$oy2-Ed4=P*{12& zY5D<8FLIWz2>%Lt&b+%K{OxIdm89D=OUunEp6Lp=E3ExXWevlHW*VH+ldp)KEHuk{ zPgv>D^f`UMS<_#ou-LCc^UD|xD+@J!hrS_JwKOggB^0UmInq58-zimCa&ZGNnmofkA`3VQeeuADGj>0ZT z`^MwfzmxoBZcg5}f%Lwg@Zom&36d`!zaEr!C;tT^GFtzaFaHClD`c(Tlky5#k#AdP zb=f{n7x{l#(PLZpFJ(oK?Oq7q{w3*stcqT7u)+bMHx-DTi0S$(E;nB`y7ns_hd88p z+5}yD8II}NC-1%fm|WnR{qaXgZsKw4OPS#&AAZ06F;9NN=)RxLTn_rf+Vh|r_`Tmh zVq{Tk9GT=-$1kaWRsPsL9&tZ;9n%@_w`fuLh?JMfDSTLAwV!rhNJi{uX_JiqY@V#3 z^HwI;c^z*SGE{kb@@0{iLS`YuZmZf!n@`W&!12*IR_Cvx`RU9Z{64SuYZNkF3QKzz zbUb788&2o9qI2ZY{FSt~%gFqd-D^?G+{gHm_L1)2XFg1%J-lZOd$iJ%CzH1mu}6n! z{Q-Db@2PA&){ZG!Jpo+L9>G6@J^B=F^fy1Kt3mW(JmZ!#S-(Y}V>u(=Mp!M4$_0xT3w%^b0yNUU?kJH(HIGbmzci!m7Y2RLdmfOwr$G6u%CDUg8z3Z3x zbK4I?el*Wl!)}w;@N|!$=V_*=yZleuj}=fnR6%NNsogyDMnbUQ7?#(Hy<)5m%t^O#9Lh5T4fmkQdse7v8i^@djJPwK7X zw|V`D^)n~pr+t*x9nCLG@`3J~RJk)h;-K=+?8l)o`9H_wzl~GUjkt|S)-kw0!zLhl zY+jVwi}6ywrR8h8RU{tk2gry1bPDk+75qx%t)g@`?`3?^JXP}^hNJn6))vN_uZaIw zXuU|vsYrX<`eZcU(mIRZ7j?d-)SA=$;(rxdrz$M|S)uhzO)q{`sWo6Ynzw2_s`Rem zc)IU^;e18>nL@MNcb%_@KT~L)it5t+b9*>_sr9htAJY7X6dq9cAj73if3AGkz;I9V z7Zu*D@SiH&r|>?8<8>8jZ(CQfc5#_)l27%-W%?8ry>~h<6qZHrU1o#67rW&$y$a{J zT$fp=aErn+{tnAxFI{GZzF(;Cmnqz#aHqnH6<(}xr@|cyFH?A-!YdSRS9p!WHhx{F za8BR%Dm;r}w{^P4Z_{}3gY#vPr$Xj0`F*}D@>a-vNz?Dw^nb%}u`Kdb%6wbji@dqa zzbHIi+BNf!4Cl)tZ-vZv6c%|aWd2>#?^FEWXSi4v`734Q!U?i(`kn*YXK+N}pKAU+ z43{$SNU?8hufCtA@Ii&oQTUL;azA;od|30(*Y{$#X+OWhVz+5OzrxcseXGI)3SX%3 zkizmk@?!a`3SYwSyUSl;xF;j`|HF>qvH8eU(97?~Gv55ypTzyp@vM_weQ~Y+Rr;5B zyz*&o$9TLc`W*XB+xUGv&J=x)$1|eun!b<2dj0Xss>UU?$9;BBqxA>xm*$N6{d`6ESZJ2~(R_Wg%;OdHKFv~d z6Xy&o!bhj`@L@FnKZD=rD^l-5^92eEUkc6h7%o<{o`X{VaJ%rOl#zKalQ+8$r?g1~ z&}}_k%8%xwWI*R`q{Tvd+ya^BFEwAwa4Ptg@Xy9~I&b3hb4ce!-pg_-@(|C{%KA+* zy+2QTn2y-kexG=rR^-setE11;evIiWWN+s%UzYL;(fY3N#pXrqoQ>1@kfP4Bm9mRD zzm2bPE)*OCACvoYrk?GOudif2)k=2;P3_qDI@~VxvGvJrX~w|c*8@qZbv_gKZjI+W z=ugh_=^`TOiPtA{TtBy@g+o|T>=(+<5&3kB+U32sp9ed9YR$uj*UFX*u$-{1)3!B1bmwJ(`{H@hzizfWPl~^RZ*8;6X08xJ&I*Uh7Np z2+V%{kq`Cn)cU`J>R;OQX3h|*pVXuC?BpLZ-a=-LzL)x$zv#A#pO`OqYPz>@x_nve zS0S@r^NF6i%mWH9-o$WG?*T7mev9GK1G1k7a)ih9kG_w<`NrdSeC5Z_ z&F{FF?fF42CvNvs=Xab}lOFLqTz?jj-9UC<#k=RkP&|+ zUsnGpBkOIYt+Ib0UMK5dJR|ktD_qX7xIs1VkvODwqs00k?bFpjlUMYFTclp|=S z5o~tb+7I@ov8rDdzSK%L*|Y!FE`}%R|D*!3KgC_&WctycA0;}&Cz-4ul;#QCxk6vG zKiBG6mUPI6`q_6Xxc_+@4(k08YKN{FBqr5iuV2~xo)I2>Ln>Fs=U z_>|3*E|aqn`h6UF_q$|5 z-BjTd@cD9?KJ9+3|2ht>|LT4PxK484!2#QK9?=o=`x;ayqW47jU98J*5%5%S2bYI?u`n;u-68hg zT_t?PJ%T(RaWf|iN^36WA3am$+(6H=R)$0MKYJFoFzi}#63!CC<9dnV^q4+7)pPI} zkJ+bG5YJysl>GlO^Ir_yh({qIM-zEh0^B?0~Dalyy``)b%V zarB0FN`Bmve3<0l>W%M5oaN^ywqWFe{LfPU@!Yd_zMr4)AwTXP>`mPN_^Vft9nyNB z--SxpeHg>rl|CvTx(9k4zerDhF}JHfFLs3R+Wq*E9n6Y9VE1Jtzn43a-mO}C(!T$0^Pi5&#{>Lh*~NEJ*Jk67_jkQzlil64iY`SAH{y_Y1$5fEHKq7?`u`%Nxz>8wsCn#KT+!l`-zS&p0$Ae zUc~i*e?r%C94mIBmehVXsoz5OgzeFt937OVP(pf23lK}8t`Cm zET`i8B_HPUp&j7sv3w^66{)P{i|6TolPi!fe~$APvR~$X z3i-0&D`XEaY<9?Hb>D^E1Elk^)SqxV`c6BCwqL%K)qNOtPtR_#$Mxu(Ta(W7nNHWg zf$_)m%D$7B-l<%VnBM6O)AtQIUotRH!(l#{taut4z5q!9?P_T3ptGW(aCUp&OqipovxEd z_jc&{p?dz#1tg*Jt@CFz7=ZUt|mOGU^~|Xax+o={9jQQRBzww-;n)2nf<}5Xr0phKI;$Sbz8Zw zZ9I14+q{00Y)_GsxINnw?YVHw_WXKHyfRN1H2^%HL;2o+EjiH71@f z)uiu}ipT8N)C7Ig$He=&ns~*}jq9!Zfg^f@G4Xz~Cf*Mw=#_nnW)G;}`Y$MwuO~^n zwzDSQz64&|H?8(0J96K267L6V;(auMcR$k?(|ce{di!ePeJFu3HpY{#Jh&_7OuDYAva2+SL65b=X#HZ~TX~Pd@?l51cR!y_Ax&@R z64o$W%G@k+Qts9K?V5f-(=Sn22GDYsQ09nGTr*VPv7Si-mLIz6<)z` zDYI7LWeWEw+{thub1%cCt?M*?54T$>BNs+fy%k=s?>8%4VmRI(cAvtwf9yd`zfR@A zF>Leq7(YHj|NH$7`X9f)xqg|w0+K0r}ANzi__v^Z6#3*DYjd z(TJXW69+*-&t=%YGG88Vr6j)m{fOp@OKD;QN_)O0+hH$Ig+sW_WR! z*Swa)R3Q7U(H;{uj{o}?)*r`zg_aUb4opr?WM237i$pG|iqU+ojq7QhisfrOcH~h{ zzihoK-ltq(Jh48lU^v#}UWQA0uVJiL>o`8X|M0NF>W7Rt2lIkazX!I9_!{e($dU0c z738?RllCh)-;)YnF6k;_H(cvMwzJT$n)d~H=TjhZc0MJ#-=Fe*H;;}bG9HRYXy5yoe|iu=gY0|FW|tv9kFuNz zA8NhdoRG7LlK=H%$p8Hbx?oRFME-w7^VTL8;5YbZ{ixG>bFJTUYd5p}S^L?3e7~Q> zeh8=Y?|%H(IQ}TNmpfys$nhB)1fRCQd*}$iPw`iIXnz33b9-(fqUf1V0NT^(dFg4i z2Mv$e+wMWRXRo+j?vF2BC+nd-mx;kEXnMC&?0;l;XVT;$J&|3WDIG;*w`b1g_odsK zBwU~4@HCPy=9ivJuFhYj3?^9vf5ua@#}!reVDJIj-Nt}cXl3Azk^NdJ)ExCL<&JqNxx$k?iBs5N7tG6 z#(q=0ZX$d&KdHE@wjTxkn^cuw`ps~clp9t=&WH}KXSz|&4W(?}sby5IXJrf!&|G{M_H;bUq(8zz=*<_&lupI#Hk3(fEB>6(y`} z5dP~u=(f)8o_z`%}A49I67B+DIwvYS@8;^&2{<}-(`z>Es$#FU9M&Z{k!bfP2 z-AN%NjLy&Vd(ijY7eL+~5xRzyzh$LU`CRMX?W8<@hVB)$ej==h-;D2Y;feO2Jis8? z5mD^)R5`!p*MB}Ni#59-5ba&K5($NTnOgi!Cdbgk`*uT%23F66LSS;k?h zwL{-af9aa9;qvT!jN3X(;OP5r(r(7TP|vBk%uPb4-XrZYw=i7Pd#FnpVirBH<9N)D zr-GZfd^h|Jm>(cq@L{mZfwS z<1vAUS4lYgQ3;*ycXpw`m<5`?o{XqIv_8#rTDfg`>G)@neyFPOew@(GQ_rCWr3ZM> z?usU8J4^Z5e~9B^`zP%?e3hguEc$U&9(su3WfDJ3b->dm!)o?V_ikMNfVM^;j+N@HPo&tDZ&m*eLeX>XANO?m4yg zF3xP?jPS?m)A>uGbE>Q-nE#dv_HsP-t=819xh;%;gnpfU4#$U0s%NUVPQT+@Sn?~z z3qG;lXuW*H#g@*ed4sEg98e>!`k#7FZJGo}5^9=i4N-sH#Z-PPT{E$u+X`*hp; zR3PUI>WxG95&uBX9p8grwvX|}^I5XL(C>ed-uyJ=`}jQgnUXJ_&)P5TNNNqvB*%lM z-}&+vIb9(u_YdWDKV!lC&1j#|0H=%g^PB&r=X^>w|22+%D*uNzM%%ch>$HcMvEXZR ze(7&%e1rN?b?N?DsgKPM73WHO`1d++J+IXGvn0g+OXRnGmi5jHeYT1&8CTf74&C#B zo#>tu<0aHJ?~(Ygs`5tv&iBWv%Db5n+jnBYkBJ($evs(s3h2-!J*hza5O>CAZf|#2 zpM*=cafp6{J|}T3e<5m5_4nop$aRb63F^t~{$BW@+Mc@aDBgD?^H#2ZgUFlusjl^? z!qR`zy;(w6_ArO_%KIeyy`~@1j`lrQ>)&WSQ}FK=y6WM(noz|0X86dE(?jc>jK}r` z+r6vx@a>}UM~rWw;t@J*-Xp2MK0b`wp(nH6i2XaVe`O-&=XRE#Q@5Y=dM+QmlJxiJ z*}ykgaPZ|u&yJX#IgxpnFSd}JkNTaQJGA|!{qhyD-`#_MCh^ip>`Wma%V`}`PBDY{pCo5Esm&@Oo5anD8ke)t@TAKocpt#dnn;GZucF@WVpyFWxj zF7pFmx4`M~oU^(6V$o%ki19621m{)OY>wlB|B-75-$T-l_0H}5nNJ_#yHN4%zpol! zNcenu(emS=_xlO_&5HkE;@r`j68N!#F&_M9-x|{ieqbgG{5YDxpC|k{7jz!*j)O0k zB=CZsT6mX&?mWGu2Yml3!REiz^Q+7*e!Ls@RrIN=;a=#S^? zZWnz02ahq{Ck}BK?iP8p`ycAzeWHplH!HsVithl2R-bx!HhOqs`oLA{CwB`!>g7jG ztbJ%-4(Ce+VyD3GiSmOUqV}%05A|(cJDVJwNI&vRYJ2NPQmj=3_luu09=_e?@x7~I z2J_AJ@0E5N2j7=?`Qvtz{-#)#cC+tW)N4Q3gSh?3FwhgNgXugX_(lIB`)>Mc<&-k8 zTF58;PANl!8hT1w#nHEU;ZkM}$J@T8QU z9-YW&-(j@xMTc{QFI|&PXS~+_zP-4t%3idMn(lH>j%<8l-_a^w%h>{VnUsg~PRzIK zB)*j0#qEo7$rK0idW8Bv6pzRDFW7mf6yGXF_N*-LVV{28&m*RZPvCRXpG&cxHgQEx z#rdV5kOx!Nn&&PSTw zCi`9MPwSme`5WR}+@HRK={ElOdUU|!pY@+bio@fNzezM|j=#|l+jzg;xysK~(PQI% zz2`-SGXeCEj+-1S%C@iQyrEAARL<^`oHsc`wxhN`@rkPPE}&GfGyhlgnJP0;{oIFH zephPw;>Qn*ndSPz^0=G$bujGl0sf4gx9q+`>`l*IpJV#-zbWYpi=_VnA5NpFTJ8Iu zDn5u`l?voLc}PD|e0VGK;aVm<6}*f?vx{c$-J&6`pYOMkt5~=~HsvV8p#v=SaVZdE%;jtsy%5r*3}W8ZKY^#~Soq=h+*RSF@vLKac0U={|C0 z%&!AJ`ZvPwiS`#|E@D1M`-?JS=wi7Le=zc=be+GuEPj5EuHV@C2HS_&t>;SZ`;fLS zQQF$X<&`$&IE?Q@R{y9nAoAWU?H^WD{`FqL_`YSaU(xpwo5g=~nM(w(&PTh9`0+O1 z=Q7vu`)>8adNN{Yz$ZMZ;GeksP|JIoj1gXS$@S&YexqnSm7E9k) zJ$erK^e8`OD}N$6Oz;Qo2YhWCrT;Yf4P{so%`<>6=wGa!Z4W3t6v^=wdPxtehyEtw z*CP^-_WK;@vv#{*;%%KeqVHB?&x1an*9)HE7752{|8%3-1?gY98f3vEp3fHh z5b;~vu}$wM$9|8x{4NO{;P-D4owh$}c2VL(+kau}WTC{nCnap#Wcz+*a>VmNmwQfh z$$Fj1C)71Z6r!FFJ|OoEfMC0)B^^8^`gextdn(w%aMJ(v`{`biTj2Yr@1lS1<@C{d z-tJKHmr)AIIhBv}{(R4GUV!nm@zD%d4;T;9|+5v z`8};m@cZb#*K9AtbPj>vm$Dn={g9NKte;Qs+sQ!=ZQoQxcii7n6{G&o&fBB{onL5O z#^tytK*h%QI?a%f3mz1l&elV8D*dLXBm+py9p*NDBA1Q3|bA;hoeq=vXEI+c} zuUqA(NAI5q$00xGF85AUMR5ci>p`vp|yVfb=^bv z(T%28>8bDIa>BBd@9%p9g^3xsk~?ZAGrKj&y#-tSDRyf z0$<>doQPlDMN@*K`PFm|hWQ`czmmcxzw5Le#h%f98!R`&yC7wfX4{qA0OS?ohk_Fj(f*6-%@WcDy(^4B@u z`yP|R1N^?Ub*-ioz3qw4-HATfxjVOMnWj_yiO$=p-PL)|d|CR3LZ*k)=gZQ66f$qt z{9>P--kV?4^Kzxk6Z*ba>3dk=bqYVE_|`C7$h?c;?y}UoC-Yu?FZQO8d7r{ZIDJ?V zeRs{@wsc$M*Fgr|)WLVLZ_|?>U|qi^q8~4hx6G5Ap3B%D4J}j%gkpv7Mihphx$e zALsXfVtV$AK8@r2+Bvi#CZ4CD$y<7C++u#W&1af^r+D`nrPKXIW}j_d+xFL*-xIDw zFBk;#g3;IWUQYHZ_5(&=&+G8)R{Xs|>2C;ytm_rIxS%)_F{Iz>4|Ja`_OO`Nep>Ha zL;ubFw9b=s>-Rc(GC9s4onMI7DZ~$p?=|1c{C1g3HT^z?uVT1c_tW&~`7b+HkstW9 zq}wF?Dd@dug^UQg?Z3|t9N=`NrAruJ&y9;YEG)P|!YSmG(o@iN8SD2;nd>>;ZM~4g zQu8Z0G(EC*O$C3+_z^!*{UatI>&??o^4b}6ooN5Gk$k;Wu!HM4Ot|sTJt7Q;tA+ot zH{g611cDyGcx*g8d!fK#UczBa8qhOMnwjPk1Yc2_BXDaEGybl|(>WdV1P|=MFFL7w zZFjd-;?YO@^B6WSkUniaCrB|Dh%Ukd3W4X@ao|axru~u92fq~g!Pgvx!;jG)dZPIU zYMUIv(fHmQZ|9*}`vD1U+!pP_-XihIdRe(`8)bkV@!jT;jPI)z|CJKj ze$r{y4*K2b;*2Iv(53sJjc%Xce@%2p^x6E##@h4^YyHwwM1O4FqB!F^&QQwAo_IT# z5$#hZzTxr5MP&Yu+4$T)FYy8Ju~*Y;`;W@UQRqycF7tWdCnVVB$)f$hL=WOkF469& zQ7w8NC3>tMj^`0Xex1!DD824sq5EkGf_YQU=k zLDxZ{qeeN~68`-F@d0)LD?hMvmqI@4@M*XvT_QJjk6ujI9Og^RuN=c+4Z04ELD%_X z(Df5?Ibwcc76f)k_-uB3G`}gP_gx8kHw(Rr$7RL;_s2^ukfRD0$Mdz|r$1i0hhBlN zQ$T-S(~HmY$NB0+Ir2n;Z`uVcTWkuz2P{u!Qf%r-Gy-D+@ z@@175Js0S<-iPW3h2}R&sNczjeZrHkXnPGxJDHzF_Xx54yUZ}BD=gS6Ve=nxX!jb{ zvnMv5xsL70L6(DP{&MJR4EuVL9DjUpHsn$A#q*akZW&u1zrpw?@_vm+tLPO5rvlS! zv5WCI?zxSd;`;*jbN$Bi9oMaI@W)Lm{{zZLA`_HayT{|Ee`Nf2&UHNFq7M@4cwE%Z zasoMnKWyy%zC~lF+F((Ao;H@P^GdAx6s;)Jt*&dHdwIp$EOpm-xHP zGOy>`A*8o{1^LdH4LcM3<>pDlzuSJj98L`_jU2^|a zK3cyS62B%|zcK$yA-=J6 ztRJzQe~IPM^>+w=$Fc7CY)w3}FU$2W95Yr|@EhMNggjp|rnL->*@8 zqPL}t4B(UN8za|04s-sV%z)xQr1-Wed{E&&hD*`+9y>H1+5!K&Q(@7ccpXE=1Mxb> zd76HOrq3~)FAp&sf8SK>Zb83q8kU!7`VLLMpW%E(>|8k5&TwggtaF5e3l)|Lo^Wun z`++c ztI{InH}BT;GGOz^MW3WM)^B2b16K}q^A?gT*f%`!dPoP$E8-{0Ke>tQ>8V`jypqeO zKlGs9vk=no6cPtMEt(Vi#nvC3h<~)ViTFK5U?Ig5C#IZ{PK7B0cu+ z=@Ke>j84CwZ1U=1{bEtv+`#`XBGYplqX~x75}rnVF?D0d+-*X4S4!4DYL)ZCDtcr+ z$iDN1{*Z>*$BM5&DO7Kr7sNhnVtL@MpBx9pFbjHV!qv(9UhzxNsGHuMJI<*6%sn{f@J!8TVcyVoX_wyKNuf@{Wj|FEcqjo*bfhfBteG z!H~Cg7u4>TRuI49?~LBSh@$z8>6DS4lW|VyTe;XCI9)eM1s`Ypu;;kHC_ficLFv5l z4K&2|t)(Z&`|=*OEG#qt7uLVLyf z_eSP}>HmrNQSYU4%r2&aWrA1COyHh4Aa>jlA~hx zOh(_i-nEDG*?k8o{eE3+H;ziVx-Y=$pW?4DKp#cEefzVYuXX@Md(ij z;z!xMtDm3khDY~ak8aziWcRYg_hJhE;&!=bskmFl*EYYoyal}%@wY7efS$u1+5Jn< zqmLE{ey6+-2Zf*Eknr8~Z?(4n@MV(D?gcGf2dNRjZ8QH_`6T=cn~p%AN(AmGNbkvcPB{R^J@D}BL7R=fne2C z>8II_qP(fyIZ-|W3SKedNJmUC11Q=AciPj=YERu zM(0wqeGEtYm+ZbY-5+QENW9K1{nmKax!+%to|)V(wBJYRnD~7GJ6FW~9c>@O=<8zY zZ;WFd>!T!Uv3d9wLm z$kh*MzqakW4x@XbO&`R5hxYxX{$(N;k-sGVo$Zrzt>O>axm4G>kJH#PUdsR=i-i>?l{+i2$J(;L+9lp3zZ(Y6QwdcvObI+bX($2->Dmjl? z)cy2%m7nfG@sEq!3fkUyU(t)sa@km?(BZN{0^~Cg{7DB`}_{EUxnzN zJh3Bg=|X+~X{IATu!qCajpC^FERYF|Li2h~SD13EgiFOSD`j+Dr@TV)Ws3ZszRxE0 z();buo_J#Zzm?x7=k2k+eGR3v_BXkP9^y-Ev0adIYNcz<#dg8`Rh&!QNAhp?2!-=O z4dD~=1B~-J2)6UOSkInKa4r1jRM9bwQo(QdKG!Gg)p6ii9L?t;2fT8J@6&kd?pM%H z^S9==4Vvtwbxj*Vrfip2-HeA_1y7T?0K?JLQj1Ut5H9Cj=$irtF7KUoxeX5XhYJ7@MM zvQv8RPW+upv1|6-OSCJVQ(>nrpmI;8okG`E&)-dZ`fd7hB6jMjmyjGL_DLk|6#BK) zSC1Vty9M|q3HZDOJelaU^ur6$nq8WRMM0hPBq$k}V9ea4)REE16<$e0J za~U>2!0rzK9dtd|v9!)V*gC1r=Yl^FC9E&viM|(dt-yAlk@;7^N84lxpJYe{FW`h} zIC}KdD*qdtUIaG9xAzb~9}xPjd^@*i^TS5Z@CHU(#ec+@zv~_lzC?VSE9tS1gX=|Z z1;RF+=g0gZo;x+ZYtkZy!*hk6;SVqvtfuO5zMF*Z;hQAh>Gufck%NPt5_BT;$Aj>P z?OrAu?^?OFzF+hh*^#HIc$8%KS9RHUoP;bo4<_T6U79X^x;Vm4*A4vg_fYw^FTY;7 zy(pKad!<|%FGc0bG%(RKbPP3*?^hCkD_YN0zjBx1sSI#>w^sZtpRNO-Ydf&fo&;jr zVZe_F47vJUg6;mEt_IoHVE5XE6`{ke7lv5BVC`<-)99k_;@|xP+0{Tsfu2y;Cu|)glA9|f!|;`yEP%X#a>xsZLMG`m zq=)dVsp1+=C{~)3C8573@4-YAJmt&v3h*f@^oI#^w9LF9zS2}@y*%=_*Z-J z5kKcjeWqP5VZ=|&eqQ47&FAOUUVO4YfSu?hmV%!gk{p4RXopLP zF27$)zQ4@FYkr1PJs<9tc7hovR5Y#=cvZvH;7t0ts^Mbl8xSt!b(?g94DizpLtK7Q z=O0VcrC~uIM4Zm4Gon>A|1g8|Umm=O!gRx{xaUYWZ0GU0?LR86N9nXal9T?#dH9eo z6%6wGRSk1^eJ?O?5o^(LHt-2r<{Rj;{W)fzu?~h3llld|E+)dUUiBOF zK3pS+Oz&rJq)5b94v3xHeUQVew+J6n!5ig$o`YbTrXSYzJ>dVrVjAObllM-)@0JSw ziX&E0e-C?+Zdk=VXS(4r?s<)0K7Wvoz5}HBrUh^z(hZODm%-2;fK$N}{2utw6{Z^= zk$#NcqkU7srszFJF6oB%vOFL^+AkG6tnXJdztRow;2i;Y4>?H%Z`b!5c?A;j7)M6@ zCn6~-aF27cAXIxEJ}7)e`c8Uf=b=-4U&Esndz}{1^D+R@DGCpdJHdpPmy8c zQ$4wY2V?s-!eWl|MeFoMP)~U6eubjYY2QyX{5F3A`r)BP^(7c2NAgw%Hj*cbgrDH= zvpPgD>hlZwKU^*4L~^G3815E7ARO8+a<);%IVs*vU0eR47d|~K|KcuEy*DyFwe$ur zMdZT0kKK0ZMBmP3TTl)8_xAb$pY#zzAZWCCW;Doe6u7Ga(n@??iPoXe_W8_2Ey%v-Ibgcp1%5^8Bz{_xgf_k@T`F*LKT9gO zj9*}17v$E;G5#+DTibaa?TepHS&gqIm*8KH;!)qt zsIS(`>TCDon1AZd75Z(Q=FS!RZQSZ~9BupCOrOCAlw*7_IdgaAq+TTBcx=36-=U4h z6IBJAST5b#6Fas9JK@UeyZ5#T-Q?VATb_-fV>;tWbBTmM@)Oh#jQj-Yr>%dm?`hk41(PS=@9ZFYqVFtMsBn59 z*H~vZc?TV@C&xCHCoMOUCoMOUr+rLsEKedIez|M7+(7tKr`*?}+#%uT375Z1>qqj@ zN9Fte5bA65Nq)UwN#zd@X}+le&2&?`jRJ!&w~&Yq@7DJuDvU?v$Ly7l?^>>pw5Q>* z?|UQN1%wKC`8!`)4)hQ4_Wg7}-TgOF`CdBoyuQ8}zIBOoZ$!E$=?^_Vz8*>!Rzz;2 z@2T4TicLfqJ<&XI6ETG04i2MzsL^@N7H(hru5|p}=oU#IeK)$DVe~7on@;bGv;M=z zk9d#A<`1IzJBr6Ei$^;6V+Fkj()1tkny(+*adJVq=^=%~kYx97^E93XT=UNvtzH}p`hw5MEfX5M? zl;7mJ*8Jixsor*efzFvSo@ky=O{w)`cT#)MKbqhA3od}py>j|pln(Lf1|pOmmlb(5 zc?JEm$u16y_>sISy;G4Z_IvF+?N#}__J%wl$7phs3VxsQ**Od=$34-@blSdS*T0!z z*SdkjQ182m^hf7$L(`w^fTT11$!=4ai=+DXG3@g_=`X^5Sv!CqAEAL4-RH~s;{9*J zARkXJ@{!!&LB9FCFG}ckS;-#`N&UjzQZM7*e98xjFneQuQBuBqd-Ba2N$#{gjZa~v zL+fk)$&kX<-Y1_wo4_BHljRq}I#kOw_yT^Uz>kXXBgqHTixc4ozSRu=uzV-(?HkFb zmI>h#>iy;_{-~c?W;R9lejwd9>BHDbzMKd@K3qdS(o>{=SWV3Ydu01n;nzW;Po%u} z)+i6(-#kj~pPnKEVe^;5nJS;HDxWh|KJEO3?uW5?gLvIy{Q3(y0AF9u`YUqxl5-J@ zdViDKKdHY~f8_hU8toB%Z=}+mke{OoJv*YX*okNy(8R?@;{ZFqW8ck-?|0ZM`J;PK z_9?uAL#N+$iT07{`9eEKWZx4HcP`}gHeP_g!|hxVI^d7O{y}d#DGK#oO6>^yjmPY_ z_49atEA78UNZF!(-Ok^+MWR>FrC)y!l{>Ouht~!BD|p>Q)204vX9+(xX@CBh_U9X= zKR3Ud{Ny9ZZ+1C-x^$G`lO})51kaOHA$nYEr^4E9+Fyt2&$-qPes6wGI4Jp@erG-$ zl>Bbd0l_o4m_xT{zrvE=Et2*uw0@4`OX^>M@1!z;eV50V&(ZviACsJp?r-E6e=UEb zUE3Y?uH|oh4|1UWOQ`YpriI`=W<8-8v)1rdNzaTkNpj$cZ9!DBcCUSWBVIV zF#xZU_ zAN+V8$IS*D;emtxEuAJmYK=d)iQs!`srL%)6}>+kXR>-%f8N8GQ=xFGfmk0#{jNJ4%NC*
=;tyYo+JA;`uJ4r`*Z2n&xIcqjZdGy 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%0D^hZ)OcQdizVsxyuG3;E`u!_*=(thutXFE% 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 literal 0 HcmV?d00001 diff --git a/programs/token-voter/tests/program_test/governance_test.rs b/programs/token-voter/tests/program_test/governance_test.rs new file mode 100644 index 00000000..d71c708d --- /dev/null +++ b/programs/token-voter/tests/program_test/governance_test.rs @@ -0,0 +1,530 @@ +use std::{str::FromStr, sync::Arc}; + +use anchor_lang::prelude::Pubkey; +use solana_program_test::ProgramTest; +use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; +use spl_governance::{ + instruction::{ + create_governance, create_proposal, create_realm, create_token_owner_record, + deposit_governing_tokens, relinquish_vote, sign_off_proposal, + }, + state::{ + enums::{ + GovernanceAccountType, MintMaxVoterWeightSource, ProposalState, VoteThreshold, + VoteTipping, + }, + governance::get_governance_address, + proposal::{get_proposal_address, ProposalV2}, + realm::{get_realm_address, GoverningTokenConfigAccountArgs, RealmConfig, RealmV2}, + realm_config::GoverningTokenType, + token_owner_record::{ + get_token_owner_record_address, TokenOwnerRecordV2, TOKEN_OWNER_RECORD_LAYOUT_VERSION, + }, + }, +}; + +use crate::program_test::{ + program_test_bench::{MintCookie, ProgramTestBench, WalletCookie}, + tools::clone_keypair, +}; + +use super::{program_test_bench::MintType, token_voter_test::UserCookie}; + +#[allow(dead_code)] +pub struct RealmCookie { + pub address: Pubkey, + pub account: RealmV2, + pub realm_authority: Keypair, + pub community_mint_cookie: MintCookie, + pub council_mint_cookie: Option, +} + +impl RealmCookie { + pub fn get_realm_authority(&self) -> Keypair { + clone_keypair(&self.realm_authority) + } +} + +pub struct ProposalCookie { + pub address: Pubkey, + pub account: ProposalV2, +} + +pub struct TokenOwnerRecordCookie { + pub address: Pubkey, + pub account: TokenOwnerRecordV2, +} + +#[allow(dead_code)] +pub struct GovernanceTest { + pub program_id: Pubkey, + pub bench: Arc, + pub next_id: u8, + pub community_voter_weight_addin: Option, + pub max_community_voter_weight_addin: Option, +} + +impl GovernanceTest { + pub fn program_id() -> Pubkey { + Pubkey::from_str("Governance111111111111111111111111111111111").unwrap() + } + + #[allow(dead_code)] + pub fn add_program(program_test: &mut ProgramTest) { + // program_test.add_program("spl_governance", Self::program_id(), None); + program_test.add_program("spl_governance_2022", Self::program_id(), None); + } + + #[allow(dead_code)] + pub fn new( + bench: Arc, + community_voter_weight_addin: Option, + max_community_voter_weight_addin: Option, + ) -> Self { + GovernanceTest { + bench, + program_id: Self::program_id(), + next_id: 0, + community_voter_weight_addin, + max_community_voter_weight_addin, + } + } + + #[allow(dead_code)] + pub async fn with_realm(&mut self) -> Result { + let realm_authority = Keypair::new(); + + let community_mint_cookie = self.bench.with_mint(&MintType::SplToken, None).await?; + let council_mint_cookie = self.bench.with_mint(&MintType::SplToken, None).await?; + + self.next_id += 1; + let realm_name = format!("Realm #{}", self.next_id).to_string(); + + let min_community_weight_to_create_governance = 1; + let community_mint_max_voter_weight_source = MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION; + + let realm_key = get_realm_address(&self.program_id, &realm_name); + + let community_token_config_args = GoverningTokenConfigAccountArgs { + voter_weight_addin: self.community_voter_weight_addin, + max_voter_weight_addin: self.community_voter_weight_addin, + token_type: GoverningTokenType::default(), + }; + + let create_realm_ix = create_realm( + &self.program_id, + &realm_authority.pubkey(), + &community_mint_cookie.address, + &self.bench.payer.pubkey(), + Some(council_mint_cookie.address), + Some(community_token_config_args), + None, + realm_name.clone(), + min_community_weight_to_create_governance, + community_mint_max_voter_weight_source.clone(), + false, + ); + + self.bench + .process_transaction(&[create_realm_ix], None) + .await?; + + let account = RealmV2 { + account_type: GovernanceAccountType::RealmV2, + community_mint: community_mint_cookie.address, + + name: realm_name, + reserved: [0; 6], + authority: Some(realm_authority.pubkey()), + config: RealmConfig { + council_mint: Some(council_mint_cookie.address), + reserved: [0; 6], + min_community_weight_to_create_governance, + legacy1: 0, + legacy2: 0, + community_mint_max_voter_weight_source, + }, + reserved_v2: [0; 128], + legacy1: 0, + }; + + Ok(RealmCookie { + address: realm_key, + account, + realm_authority, + community_mint_cookie, + council_mint_cookie: Some(council_mint_cookie), + }) + } + + #[allow(dead_code)] + pub async fn with_realm_token_extension(&mut self) -> Result { + let realm_authority = Keypair::new(); + + let community_mint_cookie = self.bench.with_mint(&MintType::SplTokenExtensions, None).await?; + let council_mint_cookie = self.bench.with_mint(&MintType::SplTokenExtensions, None).await?; + + self.next_id += 1; + let realm_name = format!("Realm #{}", self.next_id).to_string(); + + let min_community_weight_to_create_governance = 1; + let community_mint_max_voter_weight_source = MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION; + + let realm_key = get_realm_address(&self.program_id, &realm_name); + + let community_token_config_args = GoverningTokenConfigAccountArgs { + voter_weight_addin: self.community_voter_weight_addin, + max_voter_weight_addin: self.community_voter_weight_addin, + token_type: GoverningTokenType::default(), + }; + + let create_realm_ix = create_realm( + &self.program_id, + &realm_authority.pubkey(), + &community_mint_cookie.address, + &self.bench.payer.pubkey(), + Some(council_mint_cookie.address), + Some(community_token_config_args), + None, + realm_name.clone(), + min_community_weight_to_create_governance, + community_mint_max_voter_weight_source.clone(), + true, + ); + + self.bench + .process_transaction(&[create_realm_ix], None) + .await?; + + let account = RealmV2 { + account_type: GovernanceAccountType::RealmV2, + community_mint: community_mint_cookie.address, + + name: realm_name, + reserved: [0; 6], + authority: Some(realm_authority.pubkey()), + config: RealmConfig { + council_mint: Some(council_mint_cookie.address), + reserved: [0; 6], + min_community_weight_to_create_governance, + legacy1: 0, + legacy2: 0, + community_mint_max_voter_weight_source, + }, + reserved_v2: [0; 128], + legacy1: 0, + }; + + Ok(RealmCookie { + address: realm_key, + account, + realm_authority, + community_mint_cookie, + council_mint_cookie: Some(council_mint_cookie), + }) + } + + #[allow(dead_code)] + pub async fn with_proposal( + &mut self, + realm_cookie: &RealmCookie, + ) -> Result { + let token_account_cookie = self + .bench + .with_token_account(&realm_cookie.account.community_mint, &MintType::SplToken) + .await?; + + let token_owner = self.bench.payer.pubkey(); + let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); + let governing_token_mint = council_mint_cookie.address; + + let governing_token_account_cookie = self + .bench + .with_tokens(council_mint_cookie, &token_owner, 1, &MintType::SplToken) + .await?; + + let proposal_owner_record_key = get_token_owner_record_address( + &self.program_id, + &realm_cookie.address, + &governing_token_mint, + &token_owner, + ); + + let create_tor_ix = create_token_owner_record( + &self.program_id, + &realm_cookie.address, + &self.bench.payer.pubkey(), + &governing_token_mint, + &self.bench.payer.pubkey(), + ); + + self.bench + .process_transaction(&[create_tor_ix], None) + .await?; + + let deposit_ix = deposit_governing_tokens( + &self.program_id, + &realm_cookie.address, + &governing_token_account_cookie.address, + &token_owner, + &token_owner, + &self.bench.payer.pubkey(), + 1, + &governing_token_mint, + false, + ); + + self.bench.process_transaction(&[deposit_ix], None).await?; + + let governance_key = get_governance_address( + &self.program_id, + &realm_cookie.address, + &token_account_cookie.address, + ); + + let create_governance_ix = create_governance( + &self.program_id, + &realm_cookie.address, + &token_account_cookie.address, + &proposal_owner_record_key, + &self.bench.payer.pubkey(), + &realm_cookie.realm_authority.pubkey(), + None, + spl_governance::state::governance::GovernanceConfig { + min_community_weight_to_create_proposal: 1, + transactions_hold_up_time: 10, + min_council_weight_to_create_proposal: 1, + community_vote_threshold: VoteThreshold::YesVotePercentage(60), + voting_base_time: 600, + community_vote_tipping: VoteTipping::Strict, + council_vote_threshold: VoteThreshold::YesVotePercentage(60), + council_veto_vote_threshold: VoteThreshold::Disabled, + council_vote_tipping: VoteTipping::Disabled, + community_veto_vote_threshold: VoteThreshold::Disabled, + voting_cool_off_time: 0, + deposit_exempt_proposal_count: 10, + }, + ); + + self.bench + .process_transaction( + &[create_governance_ix], + Some(&[&realm_cookie.realm_authority]), + ) + .await?; + + let proposal_governing_token_mint = realm_cookie.account.community_mint; + let proposal_seed = Pubkey::new_unique(); + + let proposal_key = get_proposal_address( + &self.program_id, + &governance_key, + &proposal_governing_token_mint, + &proposal_seed, + ); + + let create_proposal_ix = create_proposal( + &self.program_id, + &governance_key, + &proposal_owner_record_key, + &token_owner, + &self.bench.payer.pubkey(), + None, + &realm_cookie.address, + String::from("Proposal #1"), + String::from("Proposal #1 link"), + &proposal_governing_token_mint, + spl_governance::state::proposal::VoteType::SingleChoice, + vec!["Yes".to_string()], + true, + &proposal_seed, + ); + + let sign_off_proposal_ix = sign_off_proposal( + &self.program_id, + &realm_cookie.address, + &governance_key, + &proposal_key, + &token_owner, + Some(&proposal_owner_record_key), + ); + + self.bench + .process_transaction(&[create_proposal_ix, sign_off_proposal_ix], None) + .await?; + + let account = ProposalV2 { + account_type: GovernanceAccountType::GovernanceV2, + governing_token_mint: proposal_governing_token_mint, + state: ProposalState::Voting, + governance: governance_key, + token_owner_record: proposal_owner_record_key, + signatories_count: 1, + signatories_signed_off_count: 1, + vote_type: spl_governance::state::proposal::VoteType::SingleChoice, + options: vec![], + deny_vote_weight: Some(1), + veto_vote_weight: 0, + abstain_vote_weight: None, + start_voting_at: None, + draft_at: 1, + signing_off_at: None, + voting_at: None, + voting_at_slot: None, + voting_completed_at: None, + executing_at: None, + closed_at: None, + execution_flags: spl_governance::state::enums::InstructionExecutionFlags::None, + max_vote_weight: None, + max_voting_time: None, + reserved: [0; 64], + name: String::from("Proposal #1"), + description_link: String::from("Proposal #1 link"), + reserved1: 0, + vote_threshold: None, + }; + + Ok(ProposalCookie { + address: proposal_key, + account, + }) + } + + #[allow(dead_code)] + pub async fn with_token_owner_record( + &mut self, + realm_cookie: &RealmCookie, + token_owner_cookie: &WalletCookie, + ) -> Result { + let token_owner_record_key = get_token_owner_record_address( + &self.program_id, + &realm_cookie.address, + &realm_cookie.account.community_mint, + &token_owner_cookie.address, + ); + + let create_tor_ix = create_token_owner_record( + &self.program_id, + &realm_cookie.address, + &token_owner_cookie.address, + &realm_cookie.account.community_mint, + &self.bench.payer.pubkey(), + ); + + self.bench + .process_transaction(&[create_tor_ix], None) + .await?; + + let account = TokenOwnerRecordV2 { + account_type: GovernanceAccountType::TokenOwnerRecordV2, + realm: realm_cookie.address, + governing_token_mint: realm_cookie.account.community_mint, + governing_token_owner: token_owner_cookie.address, + governing_token_deposit_amount: 0, + unrelinquished_votes_count: 0, + + outstanding_proposal_count: 0, + reserved: [0; 6], + governance_delegate: None, + reserved_v2: [0; 124], + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + locks: vec![], + }; + + Ok(TokenOwnerRecordCookie { + address: token_owner_record_key, + account, + }) + } + + #[allow(dead_code)] + pub async fn with_token_owner_record_using_user_cookie( + &mut self, + realm_cookie: &RealmCookie, + user_cookie: &UserCookie, + ) -> Result { + let token_owner_record_key = get_token_owner_record_address( + &self.program_id, + &realm_cookie.address, + &realm_cookie.account.community_mint, + &user_cookie.key.pubkey(), + ); + + let create_tor_ix = create_token_owner_record( + &self.program_id, + &realm_cookie.address, + &user_cookie.key.pubkey(), + &realm_cookie.account.community_mint, + &self.bench.payer.pubkey(), + ); + + self.bench + .process_transaction(&[create_tor_ix], None) + .await?; + + let account = TokenOwnerRecordV2 { + account_type: GovernanceAccountType::TokenOwnerRecordV2, + realm: realm_cookie.address, + governing_token_mint: realm_cookie.account.community_mint, + governing_token_owner: user_cookie.key.pubkey(), + governing_token_deposit_amount: 0, + unrelinquished_votes_count: 0, + + outstanding_proposal_count: 0, + reserved: [0; 6], + governance_delegate: None, + reserved_v2: [0; 124], + version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, + locks: vec![], + }; + + Ok(TokenOwnerRecordCookie { + address: token_owner_record_key, + account, + }) + } + + #[allow(dead_code)] + pub async fn relinquish_vote( + &mut self, + proposal_cookie: &ProposalCookie, + token_owner_cookie: &WalletCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + ) -> Result<(), TransportError> { + let relinquish_vote_ix = relinquish_vote( + &self.program_id, + &token_owner_record_cookie.account.realm, + &proposal_cookie.account.governance, + &proposal_cookie.address, + &token_owner_record_cookie.address, + &proposal_cookie.account.governing_token_mint, + Some(token_owner_record_cookie.account.governing_token_owner), + Some(self.bench.payer.pubkey()), + ); + + self.bench + .process_transaction(&[relinquish_vote_ix], Some(&[&token_owner_cookie.signer])) + .await?; + + Ok(()) + } + + // #[allow(dead_code)] + // pub async fn get_proposal(&mut self, proposal_key: &Pubkey) -> ProposalV2 { + // let proposal_data = self.bench.get_account_data(proposal_key).await; + // let mut data_slice: &[u8] = &proposal_data; + // let proposal_state: ProposalV2 = + // anchor_lang::AnchorDeserialize::deserialize(&mut data_slice).unwrap(); + // proposal_state + // } + + // #[allow(dead_code)] + // pub async fn get_token_owner_record( + // &mut self, + // token_owner_record_key: &Pubkey, + // ) -> TokenOwnerRecordV2 { + // self.bench + // .get_borsh_account::(token_owner_record_key) + // .await + // } +} diff --git a/programs/token-voter/tests/program_test/mod.rs b/programs/token-voter/tests/program_test/mod.rs new file mode 100644 index 00000000..78a6730e --- /dev/null +++ b/programs/token-voter/tests/program_test/mod.rs @@ -0,0 +1,39 @@ +pub mod governance_test; +pub mod program_test_bench; +pub mod token_voter_test; +pub mod tools; +use std::{sync::Arc, sync::RwLock}; +use log::*; + +#[derive(Default, Clone)] +pub struct ProgramOutput { + pub logs: Vec, + pub data: Vec, +} +struct LoggerWrapper { + inner: env_logger::Logger, + output: Arc>, +} + +impl Log for LoggerWrapper { + fn enabled(&self, metadata: &log::Metadata) -> bool { + self.inner.enabled(metadata) + } + + fn log(&self, record: &log::Record) { + if record + .target() + .starts_with("solana_runtime::message_processor") + { + let msg = record.args().to_string(); + if let Some(data) = msg.strip_prefix("Program log: ") { + self.output.write().unwrap().logs.push(data.into()); + } else if let Some(data) = msg.strip_prefix("Program data: ") { + self.output.write().unwrap().data.push(data.into()); + } + } + self.inner.log(record); + } + + fn flush(&self) {} +} diff --git a/programs/token-voter/tests/program_test/program_test_bench.rs b/programs/token-voter/tests/program_test/program_test_bench.rs new file mode 100644 index 00000000..b6da321e --- /dev/null +++ b/programs/token-voter/tests/program_test/program_test_bench.rs @@ -0,0 +1,819 @@ +use std::cell::RefCell; + +use anchor_lang::{ + prelude::{Pubkey, Rent}, + AccountDeserialize, +}; + +use borsh::BorshDeserialize; +use solana_program::system_program; +use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; +use solana_sdk::{ + account::{Account, ReadableAccount}, + borsh1::try_from_slice_unchecked, + instruction::Instruction, + program_option::COption, + program_pack::Pack, + signature::Keypair, + signer::Signer, + system_instruction, + transaction::Transaction, + transport::TransportError, +}; +use spl_associated_token_account::get_associated_token_address_with_program_id; +use spl_token_2022::extension::{BaseStateWithExtensions, ExtensionType, StateWithExtensionsOwned}; +use spl_token_client::token::ExtensionInitializationParams; + +use crate::program_test::tools::clone_keypair; + +use super::token_voter_test::UserCookie; + +use spl_token_2022::extension::transfer_fee::{TransferFee, TransferFeeConfig}; + +pub struct TransferFeeConfigWithKeypairs { + pub transfer_fee_config: TransferFeeConfig, + pub transfer_fee_config_authority: Keypair, + pub withdraw_withheld_authority: Keypair, +} + +const TEST_MAXIMUM_FEE: u64 = 10_000_000; +const TEST_FEE_BASIS_POINTS: u16 = 250; + +fn test_transfer_fee() -> TransferFee { + TransferFee { + epoch: 0.into(), + transfer_fee_basis_points: TEST_FEE_BASIS_POINTS.into(), + maximum_fee: TEST_MAXIMUM_FEE.into(), + } +} + +pub fn test_transfer_fee_config_with_keypairs() -> TransferFeeConfigWithKeypairs { + let transfer_fee = test_transfer_fee(); + let transfer_fee_config_authority = Keypair::new(); + let withdraw_withheld_authority = Keypair::new(); + let transfer_fee_config = TransferFeeConfig { + transfer_fee_config_authority: COption::Some(transfer_fee_config_authority.pubkey()) + .try_into() + .unwrap(), + withdraw_withheld_authority: COption::Some(withdraw_withheld_authority.pubkey()) + .try_into() + .unwrap(), + withheld_amount: 0.into(), + older_transfer_fee: transfer_fee, + newer_transfer_fee: transfer_fee, + }; + TransferFeeConfigWithKeypairs { + transfer_fee_config, + transfer_fee_config_authority, + withdraw_withheld_authority, + } +} + +#[derive(Debug, PartialEq)] +pub struct MintCookie { + pub address: Pubkey, + pub mint_authority: Keypair, + pub freeze_authority: Option, + pub index: usize, + pub decimals: u8, + pub unit: f64, + pub base_lot: f64, + pub quote_lot: f64, + pub is_token_2022: bool, +} + +impl Clone for MintCookie { + fn clone(&self) -> Self { + let freeze_authority = if let Some(freeze_authority) = &self.freeze_authority { + Some(clone_keypair(&freeze_authority)) + } else { + None + }; + + Self { + mint_authority: clone_keypair(&self.mint_authority), + freeze_authority, + index: self.index, + decimals: self.decimals, + unit: self.unit, + base_lot: self.base_lot, + quote_lot: self.quote_lot, + address: self.address.clone(), + is_token_2022: self.is_token_2022, + } + } +} +pub struct TokenAccountCookie { + pub address: Pubkey, +} + +#[allow(dead_code)] +#[derive(Debug)] +pub struct WalletCookie { + pub address: Pubkey, + pub account: Account, + pub signer: Keypair, +} + +trait AddPacked { + fn add_packable_account( + &mut self, + pubkey: Pubkey, + amount: u64, + data: &T, + owner: &Pubkey, + ); +} + +impl AddPacked for ProgramTest { + fn add_packable_account( + &mut self, + pubkey: Pubkey, + amount: u64, + data: &T, + owner: &Pubkey, + ) { + let mut account = solana_sdk::account::Account::new(amount, T::get_packed_len(), owner); + data.pack_into_slice(&mut account.data); + self.add_account(pubkey, account); + } +} + +pub struct ProgramTestBench { + pub context: RefCell, + pub payer: Keypair, + pub rent: Rent, +} + +#[allow(dead_code)] +pub enum MintType { + SplToken, + SplTokenExtensions, + SplTokenExtensionsWithTransferFees, + SplTokenExtensionsWithTransferHook, +} + +impl ProgramTestBench { + /// Create new bench given a ProgramTest instance populated with all of the + /// desired programs. + pub async fn start_new(program_test: ProgramTest) -> Self { + let mut context = program_test.start_with_context().await; + + let payer = clone_keypair(&context.payer); + + let rent = context.banks_client.get_rent().await.unwrap(); + + Self { + payer, + context: RefCell::new(context), + rent, + } + } + + #[allow(dead_code)] + pub fn add_mints_and_user_cookies_spl_token( + program_test: &mut ProgramTest, + mint_type: MintType, + ) -> (Vec, Vec) { + + let (token_program_id, is_token_2022) = match mint_type { + MintType::SplToken => { + (spl_token::id(), false) + } + _ => { + (spl_token_2022::id(), true) + } + }; + // Mints + let mints: Vec = vec![ + MintCookie { + index: 0, + address: Pubkey::new_unique(), + decimals: 6, + unit: 10u64.pow(6) as f64, + base_lot: 100 as f64, + quote_lot: 10 as f64, + mint_authority: Keypair::new(), + freeze_authority: None, + is_token_2022 + }, // symbol: "MNGO".to_string() + MintCookie { + index: 1, + address: Pubkey::new_unique(), + decimals: 6, + unit: 10u64.pow(6) as f64, + base_lot: 0 as f64, + quote_lot: 0 as f64, + mint_authority: Keypair::new(), + freeze_authority: None, + is_token_2022 + }, // symbol: "USDC".to_string() + ]; + // Add mints in loop + for mint_index in 0..mints.len() { + let mint_pk: Pubkey; + mint_pk = mints[mint_index].address; + + program_test.add_packable_account( + mint_pk, + u32::MAX as u64, + &spl_token_2022::state::Mint { + is_initialized: true, + mint_authority: COption::Some(mints[mint_index].mint_authority.pubkey()), + decimals: mints[mint_index].decimals, + supply: 100, + ..spl_token_2022::state::Mint::default() + }, + &token_program_id, + ); + } + + // Users + let num_users = 4; + let mut users = Vec::new(); + for _ in 0..num_users { + let user_key = Keypair::new(); + program_test.add_account( + user_key.pubkey(), + solana_sdk::account::Account::new( + u32::MAX as u64, + 0, + &solana_sdk::system_program::id(), + ), + ); + + // give every user 10^18 (< 2^60) of every token + // ~~ 1 trillion in case of 6 decimals + let mut token_accounts = Vec::new(); + for mint_index in 0..mints.len() { + let token_key = get_associated_token_address_with_program_id( + &user_key.pubkey(), + &mints[mint_index].address, + &token_program_id, + ); + program_test.add_packable_account( + token_key, + u32::MAX as u64, + &spl_token_2022::state::Account { + mint: mints[mint_index].address, + owner: user_key.pubkey(), + amount: 10, + state: spl_token_2022::state::AccountState::Initialized, + ..spl_token_2022::state::Account::default() + }, + &token_program_id, + ); + + token_accounts.push(token_key); + } + users.push(UserCookie { + key: user_key, + token_accounts, + }); + } + + (mints, users) + } + + #[allow(dead_code)] + pub async fn process_transaction( + &self, + instructions: &[Instruction], + signers: Option<&[&Keypair]>, + ) -> Result<(), BanksClientError> { + let mut context = self.context.borrow_mut(); + + let mut transaction = + Transaction::new_with_payer(&instructions, Some(&context.payer.pubkey())); + + let mut all_signers = vec![&context.payer]; + + if let Some(signers) = signers { + all_signers.extend_from_slice(signers); + } + + transaction.sign(&all_signers, context.last_blockhash); + + context + .banks_client + .process_transaction_with_commitment( + transaction, + solana_sdk::commitment_config::CommitmentLevel::Processed, + ) + .await + } + + pub async fn get_clock(&self) -> solana_program::clock::Clock { + self.context + .borrow_mut() + .banks_client + .get_sysvar::() + .await + .unwrap() + } + + #[allow(dead_code)] + pub async fn advance_clock(&self) { + let clock = self.get_clock().await; + self.context + .borrow_mut() + .warp_to_slot(clock.slot + 2) + .unwrap(); + } + + pub async fn with_mint( + &self, + mint_type: &MintType, + transfer_hook_program_id: Option<&Pubkey>, + ) -> Result { + let mint_keypair = Keypair::new(); + let mint_authority = Keypair::new(); + let freeze_authority = Keypair::new(); + + match mint_type { + MintType::SplToken => { + self.create_mint(&mint_keypair, &mint_authority.pubkey(), None) + .await?; + } + MintType::SplTokenExtensions => { + self.create_mint_token_extension(&mint_keypair, &mint_authority.pubkey(), None) + .await?; + } + MintType::SplTokenExtensionsWithTransferFees => { + self.create_mint_token_extension_with_transfer_fees( + &mint_keypair, + &mint_authority.pubkey(), + None, + ) + .await?; + } + MintType::SplTokenExtensionsWithTransferHook => { + self.create_mint_token_extension_with_transfer_hook( + &mint_keypair, + &mint_authority.pubkey(), + None, + transfer_hook_program_id.unwrap(), + ) + .await?; + } + } + + Ok(MintCookie { + address: mint_keypair.pubkey(), + mint_authority, + freeze_authority: Some(freeze_authority), + index: 1, + decimals: 6, + unit: 10u64.pow(6) as f64, + base_lot: 0 as f64, + quote_lot: 0 as f64, + is_token_2022: false, + }) + } + + #[allow(dead_code)] + pub async fn create_mint( + &self, + mint_keypair: &Keypair, + mint_authority: &Pubkey, + freeze_authority: Option<&Pubkey>, + ) -> Result<(), BanksClientError> { + let mint_rent = self.rent.minimum_balance(spl_token::state::Mint::LEN); + + let instructions = [ + system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &mint_keypair.pubkey(), + mint_rent, + spl_token::state::Mint::LEN as u64, + &spl_token::id(), + ), + spl_token::instruction::initialize_mint( + &spl_token::id(), + &mint_keypair.pubkey(), + mint_authority, + freeze_authority, + 0, + ) + .unwrap(), + ]; + + self.process_transaction(&instructions, Some(&[mint_keypair])) + .await + } + + #[allow(dead_code)] + pub async fn create_mint_token_extension( + &self, + mint_keypair: &Keypair, + mint_authority: &Pubkey, + freeze_authority: Option<&Pubkey>, + ) -> Result<(), BanksClientError> { + let mint_rent = self.rent.minimum_balance(spl_token_2022::state::Mint::LEN); + + let instructions = [ + system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &mint_keypair.pubkey(), + mint_rent, + spl_token_2022::state::Mint::LEN as u64, + &spl_token_2022::id(), + ), + spl_token_2022::instruction::initialize_mint( + &spl_token_2022::id(), + &mint_keypair.pubkey(), + mint_authority, + freeze_authority, + 0, + ) + .unwrap(), + ]; + + self.process_transaction(&instructions, Some(&[mint_keypair])) + .await + } + + #[allow(dead_code)] + pub async fn create_mint_token_extension_with_transfer_fees( + &self, + mint_keypair: &Keypair, + mint_authority: &Pubkey, + freeze_authority: Option<&Pubkey>, + ) -> Result<(), BanksClientError> { + let TransferFeeConfigWithKeypairs { + transfer_fee_config_authority, + withdraw_withheld_authority, + transfer_fee_config, + .. + } = test_transfer_fee_config_with_keypairs(); + let transfer_fee_basis_points = u16::from( + transfer_fee_config + .newer_transfer_fee + .transfer_fee_basis_points, + ); + let maximum_fee = u64::from(transfer_fee_config.newer_transfer_fee.maximum_fee); + let extension_initialization_params = + vec![ExtensionInitializationParams::TransferFeeConfig { + transfer_fee_config_authority: transfer_fee_config_authority.pubkey().into(), + withdraw_withheld_authority: withdraw_withheld_authority.pubkey().into(), + transfer_fee_basis_points, + maximum_fee, + }]; + let extension_types = extension_initialization_params + .iter() + .map(|e| e.extension()) + .collect::>(); + let space = ExtensionType::try_calculate_account_len::( + &extension_types, + ) + .unwrap(); + + let mint_rent = self.rent.minimum_balance(space); + + let instructions = [ + system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &mint_keypair.pubkey(), + mint_rent, + space as u64, + &spl_token_2022::id(), + ), + spl_token_2022::instruction::initialize_mint( + &spl_token_2022::id(), + &mint_keypair.pubkey(), + mint_authority, + freeze_authority, + 0, + ) + .unwrap(), + ]; + + self.process_transaction(&instructions, Some(&[mint_keypair])) + .await + } + + #[allow(dead_code)] + pub async fn create_mint_token_extension_with_transfer_hook( + &self, + mint_keypair: &Keypair, + mint_authority: &Pubkey, + freeze_authority: Option<&Pubkey>, + program_id: &Pubkey, + ) -> Result<(), BanksClientError> { + let extension_initialization_params = vec![ExtensionInitializationParams::TransferHook { + authority: Some(*mint_authority), + program_id: Some(*program_id), + }]; + + let extension_types = extension_initialization_params + .iter() + .map(|e| e.extension()) + .collect::>(); + let space = ExtensionType::try_calculate_account_len::( + &extension_types, + ) + .unwrap(); + let mint_rent = self.rent.minimum_balance(space); + + let mut instructions = vec![system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &mint_keypair.pubkey(), + mint_rent, + space as u64, + &spl_token_2022::id(), + )]; + + for params in extension_initialization_params { + instructions.push( + params + .instruction(&spl_token_2022::id(), &mint_keypair.pubkey()) + .unwrap(), + ); + } + + instructions.push( + spl_token_2022::instruction::initialize_mint( + &spl_token_2022::id(), + &mint_keypair.pubkey(), + mint_authority, + freeze_authority, + 0, + ) + .unwrap(), + ); + + self.process_transaction(&instructions, Some(&[mint_keypair])) + .await + } + + #[allow(dead_code)] + pub async fn with_token_account( + &self, + token_mint: &Pubkey, + mint_type: &MintType, + ) -> Result { + let token_account_keypair = Keypair::new(); + + self.create_token_account( + &token_account_keypair, + token_mint, + &self.payer.pubkey(), + mint_type, + ) + .await?; + Ok(TokenAccountCookie { + address: token_account_keypair.pubkey(), + }) + } + + #[allow(dead_code)] + pub async fn with_tokens( + &self, + mint_cookie: &MintCookie, + owner: &Pubkey, + amount: u64, + mint_type: &MintType, + ) -> Result { + let token_account_keypair = Keypair::new(); + + self.create_token_account( + &token_account_keypair, + &mint_cookie.address, + owner, + mint_type, + ) + .await?; + + self.mint_tokens( + &mint_cookie.address, + &mint_cookie.mint_authority, + &token_account_keypair.pubkey(), + amount, + mint_type, + ) + .await?; + Ok(TokenAccountCookie { + address: token_account_keypair.pubkey(), + }) + } + + pub async fn mint_tokens( + &self, + token_mint: &Pubkey, + token_mint_authority: &Keypair, + token_account: &Pubkey, + amount: u64, + mint_type: &MintType, + ) -> Result<(), BanksClientError> { + + let token_program_id = match mint_type { + MintType::SplToken => { + spl_token::id() + } + _ => { + spl_token_2022::id() + } + }; + + let mint_instruction = spl_token_2022::instruction::mint_to( + &token_program_id, + token_mint, + token_account, + &token_mint_authority.pubkey(), + &[], + amount, + ) + .unwrap(); + + self.process_transaction(&[mint_instruction], Some(&[token_mint_authority])) + .await + } + + #[allow(dead_code)] + pub async fn create_token_account( + &self, + token_account_keypair: &Keypair, + token_mint: &Pubkey, + owner: &Pubkey, + mint_type: &MintType, + ) -> Result<(), BanksClientError> { + let instructions = match mint_type { + MintType::SplToken => { + let create_account_instruction = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &token_account_keypair.pubkey(), + self.rent.minimum_balance(spl_token::state::Account::LEN), + spl_token::state::Account::LEN as u64, + &spl_token::id(), + ); + + let initialize_account_instruction = spl_token::instruction::initialize_account( + &spl_token::id(), + &token_account_keypair.pubkey(), + token_mint, + owner, + ) + .unwrap(); + vec![create_account_instruction, initialize_account_instruction] + } + _ => { + let mint_account = self.get_account(token_mint).await; + let mint_info = StateWithExtensionsOwned::::unpack( + mint_account.unwrap().data, + ) + .unwrap(); + let extension_types = mint_info.get_extension_types().unwrap(); + let space = + ExtensionType::try_calculate_account_len::( + &extension_types, + ) + .unwrap(); + let mint_rent = self.rent.minimum_balance(space); + + let create_account_instruction = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &token_account_keypair.pubkey(), + mint_rent, + space as u64, + &spl_token::id(), + ); + + let initialize_account_instruction = spl_token::instruction::initialize_account( + &spl_token::id(), + &token_account_keypair.pubkey(), + token_mint, + owner, + ) + .unwrap(); + vec![create_account_instruction, initialize_account_instruction] + } + }; + + self.process_transaction(&instructions, Some(&[token_account_keypair])) + .await + } + + #[allow(dead_code)] + pub async fn create_token_extensions_account( + &self, + token_account_keypair: &Keypair, + token_mint: &Pubkey, + owner: &Pubkey, + ) -> Result<(), BanksClientError> { + let rent = self + .context + .borrow_mut() + .banks_client + .get_rent() + .await + .unwrap(); + + let create_account_instruction = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &token_account_keypair.pubkey(), + rent.minimum_balance(spl_token_2022::state::Account::get_packed_len()), + spl_token_2022::state::Account::get_packed_len() as u64, + &spl_token_2022::id(), + ); + + let initialize_account_instruction = spl_token_2022::instruction::initialize_account( + &spl_token_2022::id(), + &token_account_keypair.pubkey(), + token_mint, + owner, + ) + .unwrap(); + + self.process_transaction( + &[create_account_instruction, initialize_account_instruction], + Some(&[token_account_keypair]), + ) + .await + } + #[allow(dead_code)] + pub async fn with_wallet(&self) -> WalletCookie { + let account_rent = self.rent.minimum_balance(0); + let account_keypair = Keypair::new(); + + let create_account_ix = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &account_keypair.pubkey(), + account_rent, + 0, + &system_program::id(), + ); + + self.process_transaction(&[create_account_ix], Some(&[&account_keypair])) + .await + .unwrap(); + + let account = Account { + lamports: account_rent, + data: vec![], + owner: system_program::id(), + executable: false, + rent_epoch: 0, + }; + + WalletCookie { + address: account_keypair.pubkey(), + account, + signer: account_keypair, + } + } + + #[allow(dead_code)] + pub async fn get_account(&self, address: &Pubkey) -> Option { + self.context + .borrow_mut() + .banks_client + .get_account(*address) + .await + .unwrap() + } + + #[allow(dead_code)] + pub async fn get_borsh_account< + T: BorshDeserialize + + anchor_spl::token_2022_extensions::spl_token_metadata_interface::borsh::BorshDeserialize, + >( + &self, + address: &Pubkey, + ) -> T { + #[allow(deprecated)] + self.get_account(address) + .await + .map(|a| try_from_slice_unchecked(&a.data).unwrap()) + .unwrap_or_else(|| panic!("GET-TEST-ACCOUNT-ERROR: Account {} not found", address)) + } + + #[allow(dead_code)] + pub async fn get_account_data(&self, address: Pubkey) -> Vec { + self.context + .borrow_mut() + .banks_client + .get_account(address) + .await + .unwrap() + .unwrap() + .data() + .to_vec() + } + + #[allow(dead_code)] + pub async fn advance_clock_by_slots(&self, slots: u64) { + let clock = self.get_clock().await; + self.context + .borrow_mut() + .warp_to_slot(clock.slot + slots) + .unwrap(); + } + + #[allow(dead_code)] + pub async fn get_anchor_account(&self, address: Pubkey) -> T { + let data = self.get_account_data(address).await; + // println!("{:?}", data); + let mut data_slice: &[u8] = &data; + AccountDeserialize::try_deserialize(&mut data_slice).unwrap() + } +} diff --git a/programs/token-voter/tests/program_test/token_voter_test.rs b/programs/token-voter/tests/program_test/token_voter_test.rs new file mode 100644 index 00000000..2b242725 --- /dev/null +++ b/programs/token-voter/tests/program_test/token_voter_test.rs @@ -0,0 +1,662 @@ +use std::sync::{Arc, RwLock}; + +use anchor_lang::{prelude::Pubkey, system_program::System, Id}; + +use anchor_spl::{associated_token::{self, AssociatedToken}, token_interface::TokenAccount}; +use solana_sdk::sysvar::instructions; +use token_voter::state::*; + +use solana_program_test::{BanksClientError, ProgramTest}; +use solana_sdk::instruction::Instruction; +use solana_sdk::signature::Keypair; +use solana_sdk::signer::Signer; + + +use crate::program_test::governance_test::GovernanceTest; +use crate::program_test::program_test_bench::ProgramTestBench; + +use crate::program_test::governance_test::RealmCookie; + +use crate::program_test::tools::NopOverride; + +use crate::program_test::governance_test::TokenOwnerRecordCookie; + +use super::{program_test_bench::{MintCookie, MintType}, LoggerWrapper, ProgramOutput}; + +#[derive(Debug, PartialEq)] +pub struct RegistrarCookie { + pub address: Pubkey, + pub account: Registrar, + pub mint: Vec, + pub realm_authority: Keypair, + pub max_mints: u8, +} + +#[allow(dead_code)] +pub struct VoterWeightRecordCookie { + pub address: Pubkey, + pub account: VoterWeightRecord, +} + +#[allow(dead_code)] +pub struct MaxVoterWeightRecordCookie { + pub address: Pubkey, + pub account: MaxVoterWeightRecord, +} + +#[derive(Debug, PartialEq)] +pub struct UserCookie { + pub key: Keypair, + pub token_accounts: Vec, +} + +#[allow(dead_code)] +pub struct VoterCookie { + pub address: Pubkey, + pub authority: Pubkey, + pub voter_weight_record: Pubkey, + pub voter_weight_record_cookie: VoterWeightRecordCookie, +} + +pub struct GovernanceProgramCookie { + pub program_id: Pubkey, +} + +#[allow(dead_code)] +pub struct TokenVoterTest { + pub program_id: Pubkey, + pub bench: Arc, + pub governance: GovernanceTest, + pub mints: Vec, + pub users: Vec, +} + +impl TokenVoterTest { + #[allow(dead_code)] + pub async fn start_new() -> Self { + let mut program_test = ProgramTest::new("token_voter", token_voter::id(), None); + let (mints, users) = ProgramTestBench::add_mints_and_user_cookies_spl_token(&mut program_test, MintType::SplToken); + + GovernanceTest::add_program(&mut program_test); + let program_id = token_voter::id(); + + let bench = ProgramTestBench::start_new(program_test).await; + let bench_rc = Arc::new(bench); + + let governance_bench = + GovernanceTest::new(bench_rc.clone(), Some(program_id), Some(program_id)); + + // Setup the environment + // We need to intercept logs to capture program log output + let log_filter = "solana_rbpf=trace,\ + solana_runtime::message_processor=debug,\ + solana_runtime::system_instruction_processor=trace,\ + solana_program_test=info"; + let env_logger = + env_logger::Builder::from_env(env_logger::Env::new().default_filter_or(log_filter)) + .format_timestamp_nanos() + .build(); + let program_output = Arc::new(RwLock::new(ProgramOutput::default())); + let _ = log::set_boxed_logger(Box::new(LoggerWrapper { + inner: env_logger, + output: program_output.clone(), + })); + + Self { + program_id, + bench: bench_rc, + governance: governance_bench, + mints, + users, + } + } + + #[allow(dead_code)] + pub async fn start_new_token_extensions() -> Self { + let mut program_test = ProgramTest::new("token_voter", token_voter::id(), None); + let (mints, users) = ProgramTestBench::add_mints_and_user_cookies_spl_token(&mut program_test, MintType::SplTokenExtensions); + + GovernanceTest::add_program(&mut program_test); + let program_id = token_voter::id(); + + let bench = ProgramTestBench::start_new(program_test).await; + let bench_rc = Arc::new(bench); + + let governance_bench = + GovernanceTest::new(bench_rc.clone(), Some(program_id), Some(program_id)); + + // Setup the environment + // We need to intercept logs to capture program log output + let log_filter = "solana_rbpf=trace,\ + solana_runtime::message_processor=debug,\ + solana_runtime::system_instruction_processor=trace,\ + solana_program_test=info"; + let env_logger = + env_logger::Builder::from_env(env_logger::Env::new().default_filter_or(log_filter)) + .format_timestamp_nanos() + .build(); + let program_output = Arc::new(RwLock::new(ProgramOutput::default())); + let _ = log::set_boxed_logger(Box::new(LoggerWrapper { + inner: env_logger, + output: program_output.clone(), + })); + + Self { + program_id, + bench: bench_rc, + governance: governance_bench, + mints, + users, + } + } + + #[allow(dead_code)] + pub async fn with_governance_program( + &mut self, + program_id: Option, + ) -> GovernanceProgramCookie { + let program_id = program_id.unwrap_or(GovernanceTest::program_id()); + + // Use the spl-governance instance used for testing + GovernanceProgramCookie { program_id } + } + + #[allow(dead_code)] + pub async fn with_registrar( + &mut self, + realm_cookie: &RealmCookie, + ) -> Result { + self.with_registrar_using_ix(realm_cookie, NopOverride, None) + .await + } + + #[allow(dead_code)] + pub async fn with_registrar_using_ix( + &mut self, + realm_cookie: &RealmCookie, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result { + let registrar_key = + get_registrar_address(&realm_cookie.address, &realm_cookie.account.community_mint); + + let max_mints = 10; + let data = anchor_lang::InstructionData::data(&token_voter::instruction::CreateRegistrar { + max_mints, + }); + + let accounts = anchor_lang::ToAccountMetas::to_account_metas( + &token_voter::accounts::CreateRegistrar { + registrar: registrar_key, + realm: realm_cookie.address, + governance_program_id: self.governance.program_id, + governing_token_mint: realm_cookie.account.community_mint, + realm_authority: realm_cookie.get_realm_authority().pubkey(), + payer: self.bench.payer.pubkey(), + system_program: solana_sdk::system_program::id(), + }, + None, + ); + + let mut create_registrar_ix = Instruction { + program_id: token_voter::id(), + accounts, + data, + }; + + instruction_override(&mut create_registrar_ix); + + let default_signers = &[&realm_cookie.realm_authority]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[create_registrar_ix], Some(signers)) + .await?; + + let account = Registrar { + governance_program_id: self.governance.program_id, + realm: realm_cookie.address, + governing_token_mint: realm_cookie.account.community_mint, + voting_mint_configs: vec![], + max_mints, + reserved: [0; 127], + }; + Ok(RegistrarCookie { + address: registrar_key, + mint: vec![], + account, + realm_authority: realm_cookie.get_realm_authority(), + max_mints, + }) + } + + #[allow(dead_code)] + pub async fn with_voter( + &self, + registrar_cookie: &RegistrarCookie, + user_cookie: &UserCookie, + ) -> Result { + self.with_voter_using_ix(registrar_cookie, user_cookie, NopOverride) + .await + } + + #[allow(dead_code)] + pub async fn with_voter_using_ix( + &self, + registrar_cookie: &RegistrarCookie, + user_cookie: &UserCookie, + instruction_override: F, + ) -> Result { + let governing_token_owner = user_cookie.key.pubkey(); + let (voter_key, _) = Pubkey::find_program_address( + &[ + ®istrar_cookie.address.to_bytes(), + b"voter".as_ref(), + &governing_token_owner.to_bytes(), + ], + &token_voter::id(), + ); + let (voter_weight_record_key, _) = Pubkey::find_program_address( + &[ + ®istrar_cookie.address.to_bytes(), + b"voter-weight-record".as_ref(), + &governing_token_owner.to_bytes(), + ], + &token_voter::id(), + ); + + let data = anchor_lang::InstructionData::data( + &token_voter::instruction::CreateVoterWeightRecord {}, + ); + + let accounts = token_voter::accounts::CreateVoterWeightRecord { + registrar: registrar_cookie.address, + voter: voter_key, + voter_weight_record: voter_weight_record_key, + voter_authority: governing_token_owner, + system_program: solana_sdk::system_program::id(), + instructions: solana_program::sysvar::instructions::id(), + }; + + let mut create_voter_weight_record_ix = Instruction { + program_id: token_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut create_voter_weight_record_ix); + + self.bench + .process_transaction(&[create_voter_weight_record_ix], Some(&[&user_cookie.key])) + .await?; + + let account = VoterWeightRecord::new( + registrar_cookie.account.realm, + registrar_cookie.account.governing_token_mint, + governing_token_owner, + 0, + Some(0), + None, + None, + ); + let voter_weight_record_cookie = VoterWeightRecordCookie { + address: voter_weight_record_key, + account, + }; + + Ok(VoterCookie { + address: voter_key, + authority: governing_token_owner, + voter_weight_record: voter_weight_record_key, + voter_weight_record_cookie, + }) + } + + #[allow(dead_code)] + pub async fn with_max_voter_weight_record( + &self, + registrar_cookie: &RegistrarCookie, + ) -> Result { + self.with_max_voter_weight_record_using_ix(registrar_cookie, NopOverride) + .await + } + + #[allow(dead_code)] + pub async fn with_max_voter_weight_record_using_ix( + &self, + registrar_cookie: &RegistrarCookie, + instruction_override: F, + ) -> Result { + let max_voter_weight_record_key = MaxVoterWeightRecord::get_max_voter_weight_record_address( + ®istrar_cookie.account.realm, + ®istrar_cookie.account.governing_token_mint, + ); + + let data = anchor_lang::InstructionData::data( + &token_voter::instruction::CreateMaxVoterWeightRecord {}, + ); + + let accounts = token_voter::accounts::CreateMaxVoterWeightRecord { + registrar: registrar_cookie.address, + max_voter_weight_record: max_voter_weight_record_key, + payer: self.bench.payer.pubkey(), + realm: registrar_cookie.account.realm, + governance_program_id: self.governance.program_id, + realm_governing_token_mint: registrar_cookie.account.governing_token_mint, + system_program: solana_sdk::system_program::id(), + }; + + let mut create_max_voter_weight_record_ix = Instruction { + program_id: token_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut create_max_voter_weight_record_ix); + + self.bench + .process_transaction(&[create_max_voter_weight_record_ix], None) + .await?; + + let account = MaxVoterWeightRecord::new( + registrar_cookie.account.realm, + registrar_cookie.account.governing_token_mint, + 0, + Some(0), + ); + + Ok(MaxVoterWeightRecordCookie { + account, + address: max_voter_weight_record_key, + }) + } + + #[allow(dead_code)] + pub async fn configure_mint_config( + &self, + registrar_cookie: &RegistrarCookie, + governance_program_cookie: &GovernanceProgramCookie, + max_voter_weight_cookie: &MaxVoterWeightRecordCookie, + mint_cookie: &MintCookie, + digit_shift: i8, + ) -> Result { + self.configure_mint_config_using_ix( + registrar_cookie, + governance_program_cookie, + max_voter_weight_cookie, + mint_cookie, + digit_shift, + NopOverride, + None, + ) + .await + } + + #[allow(dead_code)] + pub async fn configure_mint_config_using_ix( + &self, + registrar_cookie: &RegistrarCookie, + governance_program_cookie: &GovernanceProgramCookie, + max_voter_weight_cookie: &MaxVoterWeightRecordCookie, + mint_cookie: &MintCookie, + digit_shift: i8, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result { + let data = + anchor_lang::InstructionData::data(&token_voter::instruction::ConfigureMintConfig { + digit_shift, + }); + + let accounts = token_voter::accounts::ConfigureVotingMintConfig { + registrar: registrar_cookie.address, + realm: registrar_cookie.account.realm, + mint: mint_cookie.address, + max_voter_weight_record: max_voter_weight_cookie.address, + realm_authority: registrar_cookie.realm_authority.pubkey(), + governance_program_id: governance_program_cookie.program_id.clone(), + }; + + let mut configure_mint_config_ix = Instruction { + program_id: token_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut configure_mint_config_ix); + + let default_signers = &[®istrar_cookie.realm_authority]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[configure_mint_config_ix], Some(signers)) + .await?; + + Ok(VotingMintConfig { + mint: mint_cookie.address, + digit_shift, + reserved1: [0; 63], + }) + } + + #[allow(dead_code)] + pub async fn deposit_entry( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &VoterCookie, + user_cookie: &UserCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + mint_cookie: &MintCookie, + token_program: &Pubkey, + deposit_entry_index: u8, + amount: u64, + ) -> Result<(), BanksClientError> { + self.deposit_entry_using_ix( + registrar_cookie, + voter_cookie, + user_cookie, + mint_cookie, + token_owner_record_cookie, + token_program, + deposit_entry_index, + amount, + NopOverride, + None, + ) + .await + } + + #[allow(dead_code)] + pub async fn deposit_entry_using_ix( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &VoterCookie, + user_cookie: &UserCookie, + mint_cookie: &MintCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_program: &Pubkey, + deposit_entry_index: u8, + amount: u64, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), BanksClientError> { + let data = anchor_lang::InstructionData::data(&token_voter::instruction::Deposit { + deposit_entry_index, + amount, + }); + let vault = associated_token::get_associated_token_address_with_program_id( + &voter_cookie.address, + &mint_cookie.address, + token_program, + ); + let deposit_token = associated_token::get_associated_token_address_with_program_id( + &user_cookie.key.pubkey(), + &mint_cookie.address, + token_program, + ); + let accounts = token_voter::accounts::Deposit { + registrar: registrar_cookie.address, + voter: voter_cookie.address, + voter_weight_record: voter_cookie.voter_weight_record, + vault, + deposit_token, + deposit_authority: user_cookie.key.pubkey(), + mint: mint_cookie.address, + token_owner_record: token_owner_record_cookie.address, + token_program: *token_program, + instructions: instructions::id(), + system_program: System::id(), + associated_token_program: AssociatedToken::id(), + }; + + let mut configure_mint_config_ix = Instruction { + program_id: token_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut configure_mint_config_ix); + + let default_signers = &[&user_cookie.key]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[configure_mint_config_ix], Some(signers)) + .await?; + + Ok(()) + } + + #[allow(dead_code)] + pub async fn withdraw_deposit_entry( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &VoterCookie, + user_cookie: &UserCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + mint_cookie: &MintCookie, + token_program: &Pubkey, + deposit_entry_index: u8, + amount: u64, + ) -> Result<(), BanksClientError> { + self.withdraw_deposit_entry_using_ix( + registrar_cookie, + voter_cookie, + user_cookie, + mint_cookie, + token_owner_record_cookie, + token_program, + deposit_entry_index, + amount, + NopOverride, + None, + ) + .await + } + + #[allow(dead_code)] + pub async fn withdraw_deposit_entry_using_ix( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &VoterCookie, + user_cookie: &UserCookie, + mint_cookie: &MintCookie, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_program: &Pubkey, + deposit_entry_index: u8, + amount: u64, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), BanksClientError> { + let data = anchor_lang::InstructionData::data(&token_voter::instruction::Withdraw { + deposit_entry_index, + amount, + }); + let vault = associated_token::get_associated_token_address_with_program_id( + &voter_cookie.address, + &mint_cookie.address, + token_program, + ); + let destination_ata = associated_token::get_associated_token_address_with_program_id( + &user_cookie.key.pubkey(), + &mint_cookie.address, + token_program, + ); + let accounts = token_voter::accounts::Withdraw { + registrar: registrar_cookie.address, + voter: voter_cookie.address, + voter_weight_record: voter_cookie.voter_weight_record, + vault, + destination: destination_ata, + voter_authority: user_cookie.key.pubkey(), + mint: mint_cookie.address, + token_owner_record: token_owner_record_cookie.address, + token_program: *token_program, + system_program: System::id(), + associated_token_program: AssociatedToken::id(), + }; + let mut configure_mint_config_ix = Instruction { + program_id: token_voter::id(), + accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + data, + }; + + instruction_override(&mut configure_mint_config_ix); + + let default_signers = &[&user_cookie.key]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[configure_mint_config_ix], Some(signers)) + .await?; + + Ok(()) + } + + #[allow(dead_code)] + pub async fn get_registrar_account(&self, registrar: &Pubkey) -> Registrar { + self.bench.get_anchor_account::(*registrar).await + } + + #[allow(dead_code)] + pub async fn get_max_voter_weight_record( + &self, + max_voter_weight_record: &Pubkey, + ) -> MaxVoterWeightRecord { + self.bench + .get_anchor_account(*max_voter_weight_record) + .await + } + + #[allow(dead_code)] + pub async fn get_voter_weight_record(&self, voter_weight_record: &Pubkey) -> VoterWeightRecord { + self.bench.get_anchor_account(*voter_weight_record).await + } + + #[allow(dead_code)] + pub async fn get_voter(&self, voter: &Pubkey) -> Voter { + self.bench.get_anchor_account(*voter).await + } + + #[allow(dead_code)] + pub async fn vault_balance(&self, voter: &VoterCookie, mint: &MintCookie) -> u64 { + let vault = self.vault_address(voter.address, mint); + self.bench + .get_anchor_account::(vault) + .await + .amount + } + + #[allow(dead_code)] + pub async fn deposit_amount(&self, voter: &VoterCookie, deposit_id: u8) -> u64 { + self.bench + .get_anchor_account::(voter.address) + .await + .deposits[deposit_id as usize] + .amount_deposited_native + } + + pub fn vault_address(&self, address: Pubkey, mint: &MintCookie) -> Pubkey { + spl_associated_token_account::get_associated_token_address(&address, &&mint.address) + } +} diff --git a/programs/token-voter/tests/program_test/tools.rs b/programs/token-voter/tests/program_test/tools.rs new file mode 100644 index 00000000..7736e19b --- /dev/null +++ b/programs/token-voter/tests/program_test/tools.rs @@ -0,0 +1,80 @@ +use anchor_lang::prelude::ERROR_CODE_OFFSET; +use solana_program::instruction::InstructionError; +use solana_program_test::BanksClientError; +use solana_sdk::{signature::Keypair, transaction::TransactionError, transport::TransportError}; +use spl_governance_tools::error::GovernanceToolsError; +use token_voter::error::TokenVoterError; + +pub fn clone_keypair(source: &Keypair) -> Keypair { + Keypair::from_bytes(&source.to_bytes()).unwrap() +} + +/// NOP (No Operation) Override function +#[allow(non_snake_case)] +pub fn NopOverride(_: &mut T) {} + +#[allow(dead_code)] +pub fn assert_token_voter_err( + banks_client_error: BanksClientError, + token_voter_error: TokenVoterError, +) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => match instruction_error { + InstructionError::Custom(e) => { + assert_eq!(e, token_voter_error as u32 + ERROR_CODE_OFFSET) + } + _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), + }, + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} + +#[allow(dead_code)] +pub fn assert_gov_tools_err( + banks_client_error: TransportError, + gov_tools_error: GovernanceToolsError, +) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => match instruction_error { + InstructionError::Custom(e) => { + assert_eq!(e, gov_tools_error as u32) + } + _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), + }, + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} + +#[allow(dead_code)] +pub fn assert_anchor_err( + banks_client_error: BanksClientError, + anchor_error: anchor_lang::error::ErrorCode, +) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => match instruction_error { + InstructionError::Custom(e) => { + assert_eq!(e, anchor_error as u32) + } + _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), + }, + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} + +#[allow(dead_code)] +pub fn assert_ix_err(banks_client_error: BanksClientError, ix_error: InstructionError) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => { + assert_eq!(instruction_error, ix_error); + } + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} diff --git a/programs/token-voter/tests/withdraw.rs b/programs/token-voter/tests/withdraw.rs new file mode 100644 index 00000000..a911a449 --- /dev/null +++ b/programs/token-voter/tests/withdraw.rs @@ -0,0 +1,699 @@ +use program_test::token_voter_test::TokenVoterTest; +use program_test::tools::*; +use solana_program_test::*; +use solana_sdk::transport::TransportError; +use token_voter::error::TokenVoterError; + +mod program_test; + +#[tokio::test] +async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + + let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token_2022::id(), + 0, + amount_deposited, + ) + .await?; + + + token_voter_test.bench.advance_clock().await; + + token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token_2022::id(), + 0, + amount_deposited, + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + // println!("{:?}", voter_data); + assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, 0); + assert_eq!(voter_data.deposits.len(), 1); + + Ok(()) +} + + +#[tokio::test] +async fn test_withdraw() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + + token_voter_test.bench.advance_clock().await; + + token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + println!("{:?}", voter_data); + assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, 0); + assert_eq!(voter_data.deposits.len(), 1); + + Ok(()) +} + +#[tokio::test] +async fn test_withdraw_fail_to_withdraw_in_same_slot() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; + + let err = token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await + .err() + .unwrap(); + + // Assert + assert_token_voter_err(err, TokenVoterError::CannotWithdraw); + + Ok(()) +} + +// #[tokio::test] +// async fn test_configure_voter_weights_multi_deposit() -> Result<(), TransportError> { +// // Arrange +// let mut token_voter_test = TokenVoterTest::start_new().await; + +// let realm_cookie = token_voter_test.governance.with_realm().await?; + +// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; +// let governance_program_cookie = token_voter_test.with_governance_program(None).await; + +// let mut users_iter = token_voter_test.users.iter(); +// let first_user_cookie = users_iter.next().unwrap(); + +// let mut mint_iter = token_voter_test.mints.iter(); +// let first_mint_cookie = mint_iter.next().unwrap(); +// let second_mint_cookie = mint_iter.next().unwrap(); + + + +// let voter_cookie = token_voter_test +// .with_voter(®istrar_cookie, &first_user_cookie) +// .await?; + +// let max_voter_weight_record_cookie = token_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// let _voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &first_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let _second_voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &second_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let token_owner_record_cookie = token_voter_test +// .governance +// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + +// let amount_deposited = 3_u64; +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// ) +// .await?; + +// token_voter_test.bench.advance_clock().await; + +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// ) +// .await?; +// token_voter_test.bench.advance_clock().await; + +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// ) +// .await?; + +// // Assert +// let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + +// assert_eq!(voter_data.registrar, registrar_cookie.address); +// let mut deposit_entries = voter_data.deposits.iter(); +// let first_deposit_entry = deposit_entries.next().unwrap(); +// assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited * 3); +// assert_eq!(voter_data.deposits.len(), 1); + +// let registrar = token_voter_test +// .get_registrar_account(®istrar_cookie.address) +// .await; + +// assert_eq!(registrar.voting_mint_configs.len(), 2); +// assert_eq!( +// registrar.voting_mint_configs.first().unwrap().mint, +// first_mint_cookie.address +// ); + +// let max_voter_weight_record = token_voter_test +// .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) +// .await; + +// // supply is 100 * 2 +// assert_eq!(max_voter_weight_record.max_voter_weight, 200); + +// assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); +// assert_eq!(max_voter_weight_record.realm, realm_cookie.address); +// assert_eq!( +// max_voter_weight_record.governing_token_mint, +// realm_cookie.account.community_mint +// ); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_configure_voter_weights_multi_token() -> Result<(), TransportError> { +// // Arrange +// let mut token_voter_test = TokenVoterTest::start_new().await; + +// let realm_cookie = token_voter_test.governance.with_realm().await?; + +// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; +// let governance_program_cookie = token_voter_test.with_governance_program(None).await; + +// let mut users_iter = token_voter_test.users.iter(); +// let first_user_cookie = users_iter.next().unwrap(); + +// let mut mint_iter = token_voter_test.mints.iter(); +// let first_mint_cookie = mint_iter.next().unwrap(); +// let second_mint_cookie = mint_iter.next().unwrap(); + + + +// let voter_cookie = token_voter_test +// .with_voter(®istrar_cookie, &first_user_cookie) +// .await?; + +// let max_voter_weight_record_cookie = token_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// let _voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &first_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let _second_voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &second_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let token_owner_record_cookie = token_voter_test +// .governance +// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + +// let amount_deposited = 10_u64; +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// ) +// .await?; + +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &second_mint_cookie, +// &spl_token::id(), +// 1, +// amount_deposited, +// ) +// .await?; + +// // Assert +// let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + +// assert_eq!(voter_data.registrar, registrar_cookie.address); + +// let mut deposit_entries = voter_data.deposits.iter(); +// let first_deposit_entry = deposit_entries.next().unwrap(); +// let second_deposit_entry = deposit_entries.next().unwrap(); +// assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited); +// assert_eq!(second_deposit_entry.amount_deposited_native, amount_deposited); +// assert_eq!(voter_data.deposits.len(), 2); + +// let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie).await; +// assert_eq!(first_vault_balance, amount_deposited); +// let second_vault_balance = token_voter_test.vault_balance(&voter_cookie, &second_mint_cookie).await; +// assert_eq!(second_vault_balance, amount_deposited); + + +// let registrar = token_voter_test +// .get_registrar_account(®istrar_cookie.address) +// .await; + +// assert_eq!(registrar.voting_mint_configs.len(), 2); +// assert_eq!( +// registrar.voting_mint_configs.first().unwrap().mint, +// first_mint_cookie.address +// ); + +// let max_voter_weight_record = token_voter_test +// .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) +// .await; + +// // supply is 100 * 2 +// assert_eq!(max_voter_weight_record.max_voter_weight, 200); + +// assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); +// assert_eq!(max_voter_weight_record.realm, realm_cookie.address); +// assert_eq!( +// max_voter_weight_record.governing_token_mint, +// realm_cookie.account.community_mint +// ); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_configure_voter_weights_invalid_deposit_entry_index() -> Result<(), TransportError> { +// // Arrange +// let mut token_voter_test = TokenVoterTest::start_new().await; + +// let realm_cookie = token_voter_test.governance.with_realm().await?; + +// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; +// let governance_program_cookie = token_voter_test.with_governance_program(None).await; + +// let mut users_iter = token_voter_test.users.iter(); +// let first_user_cookie = users_iter.next().unwrap(); + +// let mut mint_iter = token_voter_test.mints.iter(); +// let first_mint_cookie = mint_iter.next().unwrap(); +// let second_mint_cookie = mint_iter.next().unwrap(); + + + +// let voter_cookie = token_voter_test +// .with_voter(®istrar_cookie, &first_user_cookie) +// .await?; + +// let max_voter_weight_record_cookie = token_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// let _voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &first_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let _second_voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &second_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let token_owner_record_cookie = token_voter_test +// .governance +// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + +// let amount_deposited = 5_u64; +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// ) +// .await?; + +// let err = token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 2, +// amount_deposited, +// ) +// .await +// .err() +// .unwrap(); + +// // Deposit entry entered out of bounds +// assert_token_voter_err(err, TokenVoterError::OutOfBoundsDepositEntryIndex); + +// Ok(()) +// } + + +// #[tokio::test] +// async fn test_configure_voter_weights_insufficient_funds() -> Result<(), TransportError> { +// // Arrange +// let mut token_voter_test = TokenVoterTest::start_new().await; + +// let realm_cookie = token_voter_test.governance.with_realm().await?; + +// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; +// let governance_program_cookie = token_voter_test.with_governance_program(None).await; + +// let mut users_iter = token_voter_test.users.iter(); +// let first_user_cookie = users_iter.next().unwrap(); + +// let mut mint_iter = token_voter_test.mints.iter(); +// let first_mint_cookie = mint_iter.next().unwrap(); + + + +// let voter_cookie = token_voter_test +// .with_voter(®istrar_cookie, &first_user_cookie) +// .await?; + +// let max_voter_weight_record_cookie = token_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// let _voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &first_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let token_owner_record_cookie = token_voter_test +// .governance +// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + +// let amount_deposited = 20; + +// let err = token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// ) +// .await +// .err() +// .unwrap(); + +// // Insufficient funds it throws Custom(1) error +// assert_ix_err(err, InstructionError::Custom(1)); + +// Ok(()) +// } + +// #[tokio::test] +// async fn test_configure_voter_weights_with_invalid_registrar_error() -> Result<(), TransportError> { +// // Arrange +// let mut token_voter_test = TokenVoterTest::start_new().await; + +// let realm_cookie = token_voter_test.governance.with_realm().await?; + +// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + +// let second_realm_cookie = token_voter_test.governance.with_realm().await?; + +// let second_registrar_cookie = token_voter_test.with_registrar(&second_realm_cookie).await?; +// let governance_program_cookie = token_voter_test.with_governance_program(None).await; + +// let mut users_iter = token_voter_test.users.iter(); +// let first_user_cookie = users_iter.next().unwrap(); + +// let mut mint_iter = token_voter_test.mints.iter(); +// let first_mint_cookie = mint_iter.next().unwrap(); + + + +// let voter_cookie = token_voter_test +// .with_voter(®istrar_cookie, &first_user_cookie) +// .await?; + +// let max_voter_weight_record_cookie = token_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; + +// let _voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// &first_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let token_owner_record_cookie = token_voter_test +// .governance +// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + +// let amount_deposited = 20; + +// let err = token_voter_test +// .deposit_entry( +// &second_registrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// ) +// .await +// .err() +// .unwrap(); + +// // Assert + +// // PDA doesn't match and hence the error is ConstraintSeeds +// assert_anchor_err(err, ErrorCode::ConstraintSeeds); + +// Ok(()) +// } \ No newline at end of file diff --git a/rust-toolchain.toml b/rust-toolchain.toml index f8c2abbb..624eb0ea 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,2 +1,2 @@ [toolchain] -channel = "1.65.0" +channel = "1.76.0" diff --git a/src/gateway/client.ts b/src/gateway/client.ts index 84a02ae2..1b04f639 100644 --- a/src/gateway/client.ts +++ b/src/gateway/client.ts @@ -1,10 +1,6 @@ -import { Program, Provider } from '@project-serum/anchor'; -import { PublicKey } from '@solana/web3.js'; -import { Gateway, IDL } from './gateway'; - -export const GATEWAY_PLUGIN_ID = new PublicKey( - 'GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk' -); +import { Program, Provider } from '@coral-xyz/anchor'; +import { Gateway } from './gateway'; +import GatewayIDL from './gateway.json'; export class GatewayClient { constructor(public program: Program, public devnet?: boolean) {} @@ -13,12 +9,8 @@ export class GatewayClient { provider: Provider, devnet?: boolean, ): Promise { - // alternatively we could fetch from chain - // const idl = await Program.fetchIdl(GATEWAY_PLUGIN_ID, provider); - const idl = IDL; - return new GatewayClient( - new Program(idl as Gateway, GATEWAY_PLUGIN_ID, provider), + new Program(GatewayIDL as Gateway, provider), devnet, ); } diff --git a/src/gateway/gateway.json b/src/gateway/gateway.json new file mode 100644 index 00000000..024c14b2 --- /dev/null +++ b/src/gateway/gateway.json @@ -0,0 +1,510 @@ +{ + "address": "GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk", + "metadata": { + "name": "gateway", + "version": "0.1.1", + "spec": "0.1.0", + "description": "SPL Governance addin for Civic Pass (www.civic.com)" + }, + "instructions": [ + { + "name": "configure_registrar", + "discriminator": [ + 252, + 142, + 240, + 129, + 235, + 180, + 14, + 115 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The Gateway Plugin Registrar to be updated" + ], + "writable": true + }, + { + "name": "realm", + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- realm_authority is realm.authority" + ] + }, + { + "name": "realm_authority", + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true + }, + { + "name": "gatekeeper_network", + "docs": [ + "The new Identity.com Gateway gatekeeper network", + "(See the registry struct docs for details).", + "Gateway Token belongs to this gatekeeper network, so passing a particular key here is", + "essentially saying \"We trust this gatekeeper network\"." + ] + } + ], + "args": [ + { + "name": "use_previous_voter_weight_plugin", + "type": "bool" + } + ] + }, + { + "name": "create_registrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The Gateway Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "governing_token_mint" + } + ] + } + }, + { + "name": "governance_program_id", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm", + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] + }, + { + "name": "governing_token_mint", + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the Civic Pass plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] + }, + { + "name": "realm_authority", + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true + }, + { + "name": "gatekeeper_network", + "docs": [ + "The Identity.com Gateway gatekeeper network that this realm uses", + "(See the registry struct docs for details).", + "Gateway Token belongs to this gatekeeper network, so passing a particular key here is", + "essentially saying \"We trust this gatekeeper network\"." + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "use_previous_voter_weight_plugin", + "type": "bool" + } + ] + }, + { + "name": "create_voter_weight_record", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "Registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "Registrar" + }, + { + "kind": "arg", + "path": "governing_token_owner" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "governing_token_owner", + "type": "pubkey" + } + ] + }, + { + "name": "update_voter_weight_record", + "discriminator": [ + 45, + 185, + 3, + 36, + 109, + 190, + 115, + 169 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The Gateway Registrar" + ] + }, + { + "name": "input_voter_weight", + "docs": [ + "An account that is either of type TokenOwnerRecordV2 or VoterWeightRecord", + "depending on whether the registrar includes a predecessor or not" + ] + }, + { + "name": "gateway_token", + "docs": [ + "A gateway token from the gatekeeper network in the registrar.", + "Proves that the holder is permitted to take an action." + ] + }, + { + "name": "voter_weight_record", + "writable": true + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "Registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 + ] + }, + { + "name": "VoterWeightRecord", + "discriminator": [ + 46, + 249, + 155, + 75, + 153, + 248, + 116, + 9 + ] + } + ], + "types": [ + { + "name": "Registrar", + "docs": [ + "Registrar which stores Civic Pass voting configuration for the given Realm" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "governance_program_id", + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" + }, + { + "name": "realm", + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is used the mint is only used as identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" + }, + { + "name": "gatekeeper_network", + "docs": [ + "The Gatekeeper Network represents the \"Pass Type\" that a", + "user must present." + ], + "type": "pubkey" + }, + { + "name": "previous_voter_weight_plugin_program_id", + "docs": [ + "If the plugin is one in a sequence, this is the previous plugin program ID", + "If set, then update_voter_weight_record will expect a voter_weight_record owned by this program" + ], + "type": { + "option": "pubkey" + } + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 128 + ] + } + } + ] + } + }, + { + "name": "VoterWeightAction", + "docs": [ + "VoterWeightAction enum as defined in spl-governance-addin-api", + "It's redefined here for Anchor to export it to IDL" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "CastVote" + }, + { + "name": "CommentProposal" + }, + { + "name": "CreateGovernance" + }, + { + "name": "CreateProposal" + }, + { + "name": "SignOffProposal" + } + ] + } + }, + { + "name": "VoterWeightRecord", + "docs": [ + "VoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide voting power to the governance program from external addin contracts" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "realm", + "docs": [ + "The Realm the VoterWeightRecord belongs to" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing Token Mint the VoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" + }, + { + "name": "governing_token_owner", + "docs": [ + "The owner of the governing token and voter", + "This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner" + ], + "type": "pubkey" + }, + { + "name": "voter_weight", + "docs": [ + "Voter's weight", + "The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)" + ], + "type": "u64" + }, + { + "name": "voter_weight_expiry", + "docs": [ + "The slot when the voting weight expires", + "It should be set to None if the weight never expires", + "If the voter weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], + "type": { + "option": "u64" + } + }, + { + "name": "weight_action", + "docs": [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + "When the action is provided then the governance program asserts the executing action is the same as specified by the addin" + ], + "type": { + "option": { + "defined": { + "name": "VoterWeightAction" + } + } + } + }, + { + "name": "weight_action_target", + "docs": [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + "For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target", + "When the target is provided then the governance program asserts the target is the same as specified by the addin" + ], + "type": { + "option": "pubkey" + } + }, + { + "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/gateway/gateway.ts b/src/gateway/gateway.ts index a55c5854..56faad07 100644 --- a/src/gateway/gateway.ts +++ b/src/gateway/gateway.ts @@ -1,80 +1,63 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/gateway.json`. + */ export type Gateway = { - "version": "0.1.1", - "name": "gateway", + "address": "GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk", + "metadata": { + "name": "gateway", + "version": "0.2.0", + "spec": "0.1.0", + "description": "SPL Governance addin for Civic Pass (www.civic.com)" + }, "instructions": [ - { - "name": "createRegistrar", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "governingTokenMint", - "isMut": false, - "isSigner": false - }, - { - "name": "realmAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "gatekeeperNetwork", - "isMut": false, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "usePreviousVoterWeightPlugin", - "type": "bool" - } - ] - }, { "name": "configureRegistrar", + "discriminator": [ + 252, + 142, + 240, + 129, + 235, + 180, + 14, + 115 + ], "accounts": [ { "name": "registrar", - "isMut": true, - "isSigner": false + "docs": [ + "The Gateway Plugin Registrar to be updated" + ], + "writable": true }, { "name": "realm", - "isMut": false, - "isSigner": false + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- realm_authority is realm.authority" + ] }, { "name": "realmAuthority", - "isMut": false, - "isSigner": true + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true }, { "name": "gatekeeperNetwork", - "isMut": false, - "isSigner": false + "docs": [ + "The new Identity.com Gateway gatekeeper network", + "(See the registry struct docs for details).", + "Gateway Token belongs to this gatekeeper network, so passing a particular key here is", + "essentially saying \"We trust this gatekeeper network\"." + ] } ], "args": [ @@ -85,342 +68,103 @@ export type Gateway = { ] }, { - "name": "createVoterWeightRecord", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + "name": "createRegistrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 ], - "args": [ - { - "name": "governingTokenOwner", - "type": "publicKey" - } - ] - }, - { - "name": "updateVoterWeightRecord", "accounts": [ { "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "inputVoterWeight", - "isMut": false, - "isSigner": false - }, - { - "name": "gatewayToken", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - } - ], - "args": [] - } - ], - "accounts": [ - { - "name": "registrar", - "type": { - "kind": "struct", - "fields": [ - { - "name": "governanceProgramId", - "type": "publicKey" - }, - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "gatekeeperNetwork", - "type": "publicKey" - }, - { - "name": "previousVoterWeightPluginProgramId", - "type": { - "option": "publicKey" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 128 - ] - } - } - ] - } - }, - { - "name": "voterWeightRecord", - "type": { - "kind": "struct", - "fields": [ - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "governingTokenOwner", - "type": "publicKey" - }, - { - "name": "voterWeight", - "type": "u64" - }, - { - "name": "voterWeightExpiry", - "type": { - "option": "u64" - } - }, - { - "name": "weightAction", - "type": { - "option": { - "defined": "VoterWeightAction" - } - } - }, - { - "name": "weightActionTarget", - "type": { - "option": "publicKey" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - } - ], - "types": [ - { - "name": "GenericVoterWeightEnum", - "type": { - "kind": "enum", - "variants": [ - { - "name": "VoterWeightRecord", - "fields": [ + "docs": [ + "The Gateway Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ { - "defined": "spl_governance_addin_api::voter_weight::VoterWeightRecord" - } - ] - }, - { - "name": "TokenOwnerRecord", - "fields": [ + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, { - "defined": "TokenOwnerRecordV2" + "kind": "account", + "path": "governingTokenMint" } ] } - ] - } - }, - { - "name": "VoterWeightAction", - "type": { - "kind": "enum", - "variants": [ - { - "name": "CastVote" - }, - { - "name": "CommentProposal" - }, - { - "name": "CreateGovernance" - }, - { - "name": "CreateProposal" - }, - { - "name": "SignOffProposal" - } - ] - } - } - ], - "errors": [ - { - "code": 6000, - "name": "InvalidRealmAuthority", - "msg": "Invalid realm authority" - }, - { - "code": 6001, - "name": "InvalidRealmForRegistrar", - "msg": "Invalid realm for the provided registrar" - }, - { - "code": 6002, - "name": "InvalidPredecessorTokenOwnerRecord", - "msg": "Invalid TokenOwnerRecord as input voter weight (expecting TokenOwnerRecord V1 or V2)" - }, - { - "code": 6003, - "name": "InvalidPredecessorVoterWeightRecord", - "msg": "Invalid VoterWeightRecord as input voter weight (expecting VoterWeightRecord)" - }, - { - "code": 6004, - "name": "InvalidPredecessorVoterWeightRecordRealm", - "msg": "Invalid VoterWeightRecord realm for input voter weight" - }, - { - "code": 6005, - "name": "InvalidPredecessorVoterWeightRecordGovTokenMint", - "msg": "Invalid VoterWeightRecord governance token mint for input voter weight" - }, - { - "code": 6006, - "name": "InvalidPredecessorVoterWeightRecordGovTokenOwner", - "msg": "Invalid VoterWeightRecord governance token owner for input voter weight" - }, - { - "code": 6007, - "name": "InvalidVoterWeightRecordRealm", - "msg": "Invalid VoterWeightRecord realm" - }, - { - "code": 6008, - "name": "InvalidVoterWeightRecordMint", - "msg": "Invalid VoterWeightRecord mint" - }, - { - "code": 6009, - "name": "InvalidGatewayToken", - "msg": "Invalid gateway token" - }, - { - "code": 6010, - "name": "MissingPreviousVoterWeightPlugin", - "msg": "Previous voter weight plugin required but not provided" - } - ] -}; - -export const IDL: Gateway = { - "version": "0.1.1", - "name": "gateway", - "instructions": [ - { - "name": "createRegistrar", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false }, { "name": "governanceProgramId", - "isMut": false, - "isSigner": false + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] }, { "name": "realm", - "isMut": false, - "isSigner": false + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] }, { "name": "governingTokenMint", - "isMut": false, - "isSigner": false + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the Civic Pass plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] }, { "name": "realmAuthority", - "isMut": false, - "isSigner": true + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true }, { "name": "gatekeeperNetwork", - "isMut": false, - "isSigner": false + "docs": [ + "The Identity.com Gateway gatekeeper network that this realm uses", + "(See the registry struct docs for details).", + "Gateway Token belongs to this gatekeeper network, so passing a particular key here is", + "essentially saying \"We trust this gatekeeper network\"." + ] }, { "name": "payer", - "isMut": true, - "isSigner": true + "writable": true, + "signer": true }, { "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "usePreviousVoterWeightPlugin", - "type": "bool" - } - ] - }, - { - "name": "configureRegistrar", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "realmAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "gatekeeperNetwork", - "isMut": false, - "isSigner": false + "address": "11111111111111111111111111111111" } ], "args": [ @@ -432,57 +176,119 @@ export const IDL: Gateway = { }, { "name": "createVoterWeightRecord", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], "accounts": [ { - "name": "registrar", - "isMut": false, - "isSigner": false + "name": "registrar" }, { "name": "voterWeightRecord", - "isMut": true, - "isSigner": false + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "registrar" + }, + { + "kind": "arg", + "path": "governingTokenOwner" + } + ] + } }, { "name": "payer", - "isMut": true, - "isSigner": true + "writable": true, + "signer": true }, { "name": "systemProgram", - "isMut": false, - "isSigner": false + "address": "11111111111111111111111111111111" } ], "args": [ { "name": "governingTokenOwner", - "type": "publicKey" + "type": "pubkey" } ] }, { "name": "updateVoterWeightRecord", + "discriminator": [ + 45, + 185, + 3, + 36, + 109, + 190, + 115, + 169 + ], "accounts": [ { "name": "registrar", - "isMut": false, - "isSigner": false + "docs": [ + "The Gateway Registrar" + ] }, { "name": "inputVoterWeight", - "isMut": false, - "isSigner": false + "docs": [ + "An account that is either of type TokenOwnerRecordV2 or VoterWeightRecord", + "depending on whether the registrar includes a predecessor or not" + ] }, { "name": "gatewayToken", - "isMut": false, - "isSigner": false + "docs": [ + "A gateway token from the gatekeeper network in the registrar.", + "Proves that the holder is permitted to take an action." + ] }, { "name": "voterWeightRecord", - "isMut": true, - "isSigner": false + "writable": true } ], "args": [] @@ -491,33 +297,87 @@ export const IDL: Gateway = { "accounts": [ { "name": "registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 + ] + }, + { + "name": "voterWeightRecord", + "discriminator": [ + 46, + 249, + 155, + 75, + 153, + 248, + 116, + 9 + ] + } + ], + "types": [ + { + "name": "registrar", + "docs": [ + "Registrar which stores Civic Pass voting configuration for the given Realm" + ], "type": { "kind": "struct", "fields": [ { "name": "governanceProgramId", - "type": "publicKey" + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" }, { "name": "realm", - "type": "publicKey" + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is used the mint is only used as identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" }, { "name": "gatekeeperNetwork", - "type": "publicKey" + "docs": [ + "The Gatekeeper Network represents the \"Pass Type\" that a", + "user must present." + ], + "type": "pubkey" }, { "name": "previousVoterWeightPluginProgramId", + "docs": [ + "If the plugin is one in a sequence, this is the previous plugin program ID", + "If set, then update_voter_weight_record will expect a voter_weight_record owned by this program" + ], "type": { - "option": "publicKey" + "option": "pubkey" } }, { "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], "type": { "array": [ "u8", @@ -528,49 +388,120 @@ export const IDL: Gateway = { ] } }, + { + "name": "voterWeightAction", + "docs": [ + "VoterWeightAction enum as defined in spl-governance-addin-api", + "It's redefined here for Anchor to export it to IDL" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "castVote" + }, + { + "name": "commentProposal" + }, + { + "name": "createGovernance" + }, + { + "name": "createProposal" + }, + { + "name": "signOffProposal" + } + ] + } + }, { "name": "voterWeightRecord", + "docs": [ + "VoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide voting power to the governance program from external addin contracts" + ], "type": { "kind": "struct", "fields": [ { "name": "realm", - "type": "publicKey" + "docs": [ + "The Realm the VoterWeightRecord belongs to" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing Token Mint the VoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" }, { "name": "governingTokenOwner", - "type": "publicKey" + "docs": [ + "The owner of the governing token and voter", + "This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner" + ], + "type": "pubkey" }, { "name": "voterWeight", + "docs": [ + "Voter's weight", + "The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)" + ], "type": "u64" }, { "name": "voterWeightExpiry", + "docs": [ + "The slot when the voting weight expires", + "It should be set to None if the weight never expires", + "If the voter weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], "type": { "option": "u64" } }, { "name": "weightAction", + "docs": [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + "When the action is provided then the governance program asserts the executing action is the same as specified by the addin" + ], "type": { "option": { - "defined": "VoterWeightAction" + "defined": { + "name": "voterWeightAction" + } } } }, { "name": "weightActionTarget", + "docs": [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + "For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target", + "When the target is provided then the governance program asserts the target is the same as specified by the addin" + ], "type": { - "option": "publicKey" + "option": "pubkey" } }, { "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], "type": { "array": [ "u8", @@ -581,111 +512,5 @@ export const IDL: Gateway = { ] } } - ], - "types": [ - { - "name": "GenericVoterWeightEnum", - "type": { - "kind": "enum", - "variants": [ - { - "name": "VoterWeightRecord", - "fields": [ - { - "defined": "spl_governance_addin_api::voter_weight::VoterWeightRecord" - } - ] - }, - { - "name": "TokenOwnerRecord", - "fields": [ - { - "defined": "TokenOwnerRecordV2" - } - ] - } - ] - } - }, - { - "name": "VoterWeightAction", - "type": { - "kind": "enum", - "variants": [ - { - "name": "CastVote" - }, - { - "name": "CommentProposal" - }, - { - "name": "CreateGovernance" - }, - { - "name": "CreateProposal" - }, - { - "name": "SignOffProposal" - } - ] - } - } - ], - "errors": [ - { - "code": 6000, - "name": "InvalidRealmAuthority", - "msg": "Invalid realm authority" - }, - { - "code": 6001, - "name": "InvalidRealmForRegistrar", - "msg": "Invalid realm for the provided registrar" - }, - { - "code": 6002, - "name": "InvalidPredecessorTokenOwnerRecord", - "msg": "Invalid TokenOwnerRecord as input voter weight (expecting TokenOwnerRecord V1 or V2)" - }, - { - "code": 6003, - "name": "InvalidPredecessorVoterWeightRecord", - "msg": "Invalid VoterWeightRecord as input voter weight (expecting VoterWeightRecord)" - }, - { - "code": 6004, - "name": "InvalidPredecessorVoterWeightRecordRealm", - "msg": "Invalid VoterWeightRecord realm for input voter weight" - }, - { - "code": 6005, - "name": "InvalidPredecessorVoterWeightRecordGovTokenMint", - "msg": "Invalid VoterWeightRecord governance token mint for input voter weight" - }, - { - "code": 6006, - "name": "InvalidPredecessorVoterWeightRecordGovTokenOwner", - "msg": "Invalid VoterWeightRecord governance token owner for input voter weight" - }, - { - "code": 6007, - "name": "InvalidVoterWeightRecordRealm", - "msg": "Invalid VoterWeightRecord realm" - }, - { - "code": 6008, - "name": "InvalidVoterWeightRecordMint", - "msg": "Invalid VoterWeightRecord mint" - }, - { - "code": 6009, - "name": "InvalidGatewayToken", - "msg": "Invalid gateway token" - }, - { - "code": 6010, - "name": "MissingPreviousVoterWeightPlugin", - "msg": "Previous voter weight plugin required but not provided" - } ] }; diff --git a/src/index.ts b/src/index.ts index 9fa0659c..471bcd7f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,3 +1,5 @@ export * from './nftVoter/client'; export * from './gateway/client'; export * from './realmVoter/client'; +export * from './tokenVoter/client'; + diff --git a/src/nftVoter/client.ts b/src/nftVoter/client.ts index bfe1b0a7..cc3f675d 100644 --- a/src/nftVoter/client.ts +++ b/src/nftVoter/client.ts @@ -1,21 +1,16 @@ -import { Program, Provider } from '@project-serum/anchor'; -import { PublicKey } from '@solana/web3.js'; -import { NftVoter, IDL } from './nft_voter'; - -export const NFT_VOTER_ID = new PublicKey( - 'GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw', -); +import { Program, Provider } from '@coral-xyz/anchor'; +import { NftVoter } from './nft_voter'; +import NftVoterIDL from './nft_voter.json'; export class NftVoterClient { constructor(public program: Program, public devnet?: boolean) {} - static connect( + static async connect( provider: Provider, devnet?: boolean, - programId = NFT_VOTER_ID, - ): NftVoterClient { + ): Promise { return new NftVoterClient( - new Program(IDL, programId, provider), + new Program(NftVoterIDL as NftVoter, provider), devnet, ); } diff --git a/src/nftVoter/nft_voter.json b/src/nftVoter/nft_voter.json new file mode 100644 index 00000000..ead64e6b --- /dev/null +++ b/src/nftVoter/nft_voter.json @@ -0,0 +1,822 @@ +{ + "address": "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw", + "metadata": { + "name": "nft_voter", + "version": "0.2.2", + "spec": "0.1.0", + "description": "SPL Governance addin implementing NFT based governance" + }, + "instructions": [ + { + "name": "cast_nft_vote", + "discriminator": [ + 150, + 177, + 73, + 223, + 30, + 12, + 172, + 125 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The NFT voting registrar" + ] + }, + { + "name": "voter_weight_record", + "writable": true + }, + { + "name": "voter_token_owner_record", + "docs": [ + "TokenOwnerRecord of the voter who casts the vote" + ] + }, + { + "name": "voter_authority", + "docs": [ + "Authority of the voter who casts the vote", + "It can be either governing_token_owner or its delegate and must sign this instruction" + ], + "signer": true + }, + { + "name": "payer", + "docs": [ + "The account which pays for the transaction" + ], + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "proposal", + "type": "pubkey" + } + ] + }, + { + "name": "configure_collection", + "discriminator": [ + 71, + 128, + 33, + 233, + 71, + 167, + 155, + 164 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "Registrar for which we configure this Collection" + ], + "writable": true + }, + { + "name": "realm" + }, + { + "name": "realm_authority", + "docs": [ + "Authority of the Realm must sign and match Realm.authority" + ], + "signer": true + }, + { + "name": "collection" + }, + { + "name": "max_voter_weight_record", + "writable": true + } + ], + "args": [ + { + "name": "weight", + "type": "u64" + }, + { + "name": "size", + "type": "u32" + } + ] + }, + { + "name": "create_max_voter_weight_record", + "discriminator": [ + 182, + 70, + 243, + 119, + 162, + 176, + 38, + 248 + ], + "accounts": [ + { + "name": "max_voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 109, + 97, + 120, + 45, + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "realm_governing_token_mint" + } + ] + } + }, + { + "name": "governance_program_id", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm" + }, + { + "name": "realm_governing_token_mint", + "docs": [ + "Either the realm community mint or the council mint." + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "create_registrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The NFT voting Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "governing_token_mint" + } + ] + } + }, + { + "name": "governance_program_id", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm", + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] + }, + { + "name": "governing_token_mint", + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the NFT plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] + }, + { + "name": "realm_authority", + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "max_collections", + "type": "u8" + } + ] + }, + { + "name": "create_voter_weight_record", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], + "accounts": [ + { + "name": "voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "realm_governing_token_mint" + }, + { + "kind": "arg", + "path": "governing_token_owner" + } + ] + } + }, + { + "name": "governance_program_id", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm" + }, + { + "name": "realm_governing_token_mint", + "docs": [ + "Either the realm community mint or the council mint." + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "governing_token_owner", + "type": "pubkey" + } + ] + }, + { + "name": "relinquish_nft_vote", + "discriminator": [ + 180, + 111, + 224, + 230, + 204, + 199, + 66, + 66 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The NFT voting Registrar" + ] + }, + { + "name": "voter_weight_record", + "writable": true + }, + { + "name": "governance", + "docs": [ + "Governance account the Proposal is for" + ] + }, + { + "name": "proposal" + }, + { + "name": "voter_token_owner_record", + "docs": [ + "TokenOwnerRecord of the voter who cast the original vote" + ] + }, + { + "name": "voter_authority", + "docs": [ + "Authority of the voter who cast the original vote", + "It can be either governing_token_owner or its delegate and must sign this instruction" + ], + "signer": true + }, + { + "name": "vote_record", + "docs": [ + "The account is used to validate that it doesn't exist and if it doesn't then Anchor owner check throws error", + "The check is disabled here and performed inside the instruction", + "#[account(owner = registrar.governance_program_id)]" + ] + }, + { + "name": "beneficiary", + "writable": true + } + ], + "args": [] + }, + { + "name": "update_voter_weight_record", + "discriminator": [ + 45, + 185, + 3, + 36, + 109, + 190, + 115, + 169 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The NFT voting Registrar" + ] + }, + { + "name": "voter_weight_record", + "writable": true + } + ], + "args": [ + { + "name": "voter_weight_action", + "type": { + "defined": { + "name": "VoterWeightAction" + } + } + } + ] + } + ], + "accounts": [ + { + "name": "MaxVoterWeightRecord", + "discriminator": [ + 157, + 95, + 242, + 151, + 16, + 98, + 26, + 118 + ] + }, + { + "name": "Registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 + ] + }, + { + "name": "VoterWeightRecord", + "discriminator": [ + 46, + 249, + 155, + 75, + 153, + 248, + 116, + 9 + ] + } + ], + "types": [ + { + "name": "CollectionConfig", + "docs": [ + "Configuration of an NFT collection used for governance power" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "collection", + "docs": [ + "The NFT collection used for governance" + ], + "type": "pubkey" + }, + { + "name": "size", + "docs": [ + "The size of the NFT collection used to calculate max voter weight", + "Note: At the moment the size is not captured on Metaplex accounts", + "and it has to be manually updated on the Registrar" + ], + "type": "u32" + }, + { + "name": "weight", + "docs": [ + "Governance power weight of the collection", + "Each NFT in the collection has governance power = 1 * weight", + "Note: The weight is scaled accordingly to the governing_token_mint decimals", + "Ex: if the the mint has 2 decimal places then weight of 1 should be stored as 100" + ], + "type": "u64" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "MaxVoterWeightRecord", + "docs": [ + "MaxVoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide max voting power to the governance program from external addin contracts" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "realm", + "docs": [ + "The Realm the MaxVoterWeightRecord belongs to" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing Token Mint the MaxVoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" + }, + { + "name": "max_voter_weight", + "docs": [ + "Max voter weight", + "The max voter weight provided by the addin for the given realm and governing_token_mint" + ], + "type": "u64" + }, + { + "name": "max_voter_weight_expiry", + "docs": [ + "The slot when the max voting weight expires", + "It should be set to None if the weight never expires", + "If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], + "type": { + "option": "u64" + } + }, + { + "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "Registrar", + "docs": [ + "Registrar which stores NFT voting configuration for the given Realm" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "governance_program_id", + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" + }, + { + "name": "realm", + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is used the mint is only used as identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" + }, + { + "name": "collection_configs", + "docs": [ + "MPL Collection used for voting" + ], + "type": { + "vec": { + "defined": { + "name": "CollectionConfig" + } + } + } + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 128 + ] + } + } + ] + } + }, + { + "name": "VoterWeightAction", + "docs": [ + "VoterWeightAction enum as defined in spl-governance-addin-api", + "It's redefined here for Anchor to export it to IDL" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "CastVote" + }, + { + "name": "CommentProposal" + }, + { + "name": "CreateGovernance" + }, + { + "name": "CreateProposal" + }, + { + "name": "SignOffProposal" + } + ] + } + }, + { + "name": "VoterWeightRecord", + "docs": [ + "VoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide voting power to the governance program from external addin contracts" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "realm", + "docs": [ + "The Realm the VoterWeightRecord belongs to" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing Token Mint the VoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" + }, + { + "name": "governing_token_owner", + "docs": [ + "The owner of the governing token and voter", + "This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner" + ], + "type": "pubkey" + }, + { + "name": "voter_weight", + "docs": [ + "Voter's weight", + "The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)" + ], + "type": "u64" + }, + { + "name": "voter_weight_expiry", + "docs": [ + "The slot when the voting weight expires", + "It should be set to None if the weight never expires", + "If the voter weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], + "type": { + "option": "u64" + } + }, + { + "name": "weight_action", + "docs": [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + "When the action is provided then the governance program asserts the executing action is the same as specified by the addin" + ], + "type": { + "option": { + "defined": { + "name": "VoterWeightAction" + } + } + } + }, + { + "name": "weight_action_target", + "docs": [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + "For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target", + "When the target is provided then the governance program asserts the target is the same as specified by the addin" + ], + "type": { + "option": "pubkey" + } + }, + { + "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/nftVoter/nft_voter.ts b/src/nftVoter/nft_voter.ts index 28abf446..67668eba 100644 --- a/src/nftVoter/nft_voter.ts +++ b/src/nftVoter/nft_voter.ts @@ -1,327 +1,635 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/nft_voter.json`. + */ export type NftVoter = { - "version": "0.0.0", - "name": "nft_voter", + "address": "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw", + "metadata": { + "name": "nftVoter", + "version": "0.3.0", + "spec": "0.1.0", + "description": "SPL Governance addin implementing NFT based governance" + }, "instructions": [ { - "name": "createRegistrar", + "name": "castNftVote", + "discriminator": [ + 150, + 177, + 73, + 223, + 30, + 12, + 172, + 125 + ], "accounts": [ { "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false + "docs": [ + "The NFT voting registrar" + ] }, { - "name": "realm", - "isMut": false, - "isSigner": false + "name": "voterWeightRecord", + "writable": true }, { - "name": "governingTokenMint", - "isMut": false, - "isSigner": false + "name": "voterTokenOwnerRecord", + "docs": [ + "TokenOwnerRecord of the voter who casts the vote" + ] }, { - "name": "realmAuthority", - "isMut": false, - "isSigner": true + "name": "voterAuthority", + "docs": [ + "Authority of the voter who casts the vote", + "It can be either governing_token_owner or its delegate and must sign this instruction" + ], + "signer": true }, { "name": "payer", - "isMut": true, - "isSigner": true + "docs": [ + "The account which pays for the transaction" + ], + "writable": true, + "signer": true }, { "name": "systemProgram", - "isMut": false, - "isSigner": false + "address": "11111111111111111111111111111111" } ], "args": [ { - "name": "maxCollections", - "type": "u8" + "name": "proposal", + "type": "pubkey" } ] }, { - "name": "createVoterWeightRecord", + "name": "configureCollection", + "discriminator": [ + 71, + 128, + 33, + 233, + 71, + 167, + 155, + 164 + ], "accounts": [ { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false + "name": "registrar", + "docs": [ + "Registrar for which we configure this Collection" + ], + "writable": true }, { - "name": "realm", - "isMut": false, - "isSigner": false + "name": "realm" }, { - "name": "realmGoverningTokenMint", - "isMut": false, - "isSigner": false + "name": "realmAuthority", + "docs": [ + "Authority of the Realm must sign and match Realm.authority" + ], + "signer": true }, { - "name": "payer", - "isMut": true, - "isSigner": true + "name": "collection" }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + "name": "maxVoterWeightRecord", + "writable": true } ], "args": [ { - "name": "governingTokenOwner", - "type": "publicKey" + "name": "weight", + "type": "u64" + }, + { + "name": "size", + "type": "u32" } ] }, { "name": "createMaxVoterWeightRecord", + "discriminator": [ + 182, + 70, + 243, + 119, + 162, + 176, + 38, + 248 + ], "accounts": [ { "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 109, + 97, + 120, + 45, + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "realmGoverningTokenMint" + } + ] + } }, { "name": "governanceProgramId", - "isMut": false, - "isSigner": false + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] }, { - "name": "realm", - "isMut": false, - "isSigner": false + "name": "realm" }, { "name": "realmGoverningTokenMint", - "isMut": false, - "isSigner": false + "docs": [ + "Either the realm community mint or the council mint." + ] }, { "name": "payer", - "isMut": true, - "isSigner": true + "writable": true, + "signer": true }, { "name": "systemProgram", - "isMut": false, - "isSigner": false + "address": "11111111111111111111111111111111" } ], "args": [] }, { - "name": "updateVoterWeightRecord", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - } + "name": "createRegistrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 ], - "args": [ - { - "name": "voterWeightAction", - "type": { - "defined": "VoterWeightAction" - } - } - ] - }, - { - "name": "relinquishNftVote", "accounts": [ { "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false + "docs": [ + "The NFT voting Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "governingTokenMint" + } + ] + } }, { - "name": "governance", - "isMut": false, - "isSigner": false + "name": "governanceProgramId", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] }, { - "name": "proposal", - "isMut": false, - "isSigner": false + "name": "realm", + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] }, { - "name": "voterTokenOwnerRecord", - "isMut": false, - "isSigner": false + "name": "governingTokenMint", + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the NFT plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] }, { - "name": "voterAuthority", - "isMut": false, - "isSigner": true + "name": "realmAuthority", + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true }, { - "name": "voteRecord", - "isMut": false, - "isSigner": false + "name": "payer", + "writable": true, + "signer": true }, { - "name": "beneficiary", - "isMut": true, - "isSigner": false + "name": "systemProgram", + "address": "11111111111111111111111111111111" } ], - "args": [] + "args": [ + { + "name": "maxCollections", + "type": "u8" + } + ] }, { - "name": "configureCollection", + "name": "createVoterWeightRecord", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], "accounts": [ { - "name": "registrar", - "isMut": true, - "isSigner": false + "name": "voterWeightRecord", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "realmGoverningTokenMint" + }, + { + "kind": "arg", + "path": "governingTokenOwner" + } + ] + } }, { - "name": "realm", - "isMut": false, - "isSigner": false + "name": "governanceProgramId", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] }, { - "name": "realmAuthority", - "isMut": false, - "isSigner": true + "name": "realm" }, { - "name": "collection", - "isMut": false, - "isSigner": false + "name": "realmGoverningTokenMint", + "docs": [ + "Either the realm community mint or the council mint." + ] }, { - "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" } ], "args": [ { - "name": "weight", - "type": "u64" - }, - { - "name": "size", - "type": "u32" + "name": "governingTokenOwner", + "type": "pubkey" } ] }, { - "name": "castNftVote", + "name": "relinquishNftVote", + "discriminator": [ + 180, + 111, + 224, + 230, + 204, + 199, + 66, + 66 + ], "accounts": [ { "name": "registrar", - "isMut": false, - "isSigner": false + "docs": [ + "The NFT voting Registrar" + ] }, { "name": "voterWeightRecord", - "isMut": true, - "isSigner": false + "writable": true + }, + { + "name": "governance", + "docs": [ + "Governance account the Proposal is for" + ] + }, + { + "name": "proposal" }, { "name": "voterTokenOwnerRecord", - "isMut": false, - "isSigner": false + "docs": [ + "TokenOwnerRecord of the voter who cast the original vote" + ] }, { "name": "voterAuthority", - "isMut": false, - "isSigner": true + "docs": [ + "Authority of the voter who cast the original vote", + "It can be either governing_token_owner or its delegate and must sign this instruction" + ], + "signer": true }, { - "name": "payer", - "isMut": true, - "isSigner": true + "name": "voteRecord", + "docs": [ + "The account is used to validate that it doesn't exist and if it doesn't then Anchor owner check throws error", + "The check is disabled here and performed inside the instruction", + "#[account(owner = registrar.governance_program_id)]" + ] }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + "name": "beneficiary", + "writable": true + } + ], + "args": [] + }, + { + "name": "updateVoterWeightRecord", + "discriminator": [ + 45, + 185, + 3, + 36, + 109, + 190, + 115, + 169 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The NFT voting Registrar" + ] + }, + { + "name": "voterWeightRecord", + "writable": true } ], "args": [ { - "name": "proposal", - "type": "publicKey" + "name": "voterWeightAction", + "type": { + "defined": { + "name": "voterWeightAction" + } + } } ] } ], "accounts": [ { - "name": "nftVoteRecord", + "name": "maxVoterWeightRecord", + "discriminator": [ + 157, + 95, + 242, + 151, + 16, + 98, + 26, + 118 + ] + }, + { + "name": "registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 + ] + }, + { + "name": "voterWeightRecord", + "discriminator": [ + 46, + 249, + 155, + 75, + 153, + 248, + 116, + 9 + ] + } + ], + "types": [ + { + "name": "collectionConfig", + "docs": [ + "Configuration of an NFT collection used for governance power" + ], "type": { "kind": "struct", "fields": [ { - "name": "proposal", - "type": "publicKey" + "name": "collection", + "docs": [ + "The NFT collection used for governance" + ], + "type": "pubkey" + }, + { + "name": "size", + "docs": [ + "The size of the NFT collection used to calculate max voter weight", + "Note: At the moment the size is not captured on Metaplex accounts", + "and it has to be manually updated on the Registrar" + ], + "type": "u32" }, { - "name": "nftMint", - "type": "publicKey" + "name": "weight", + "docs": [ + "Governance power weight of the collection", + "Each NFT in the collection has governance power = 1 * weight", + "Note: The weight is scaled accordingly to the governing_token_mint decimals", + "Ex: if the the mint has 2 decimal places then weight of 1 should be stored as 100" + ], + "type": "u64" }, { - "name": "governingTokenOwner", - "type": "publicKey" + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 8 + ] + } } ] } }, { "name": "maxVoterWeightRecord", + "docs": [ + "MaxVoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide max voting power to the governance program from external addin contracts" + ], "type": { "kind": "struct", "fields": [ { "name": "realm", - "type": "publicKey" + "docs": [ + "The Realm the MaxVoterWeightRecord belongs to" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing Token Mint the MaxVoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" }, { "name": "maxVoterWeight", + "docs": [ + "Max voter weight", + "The max voter weight provided by the addin for the given realm and governing_token_mint" + ], "type": "u64" }, { "name": "maxVoterWeightExpiry", + "docs": [ + "The slot when the max voting weight expires", + "It should be set to None if the weight never expires", + "If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], "type": { "option": "u64" } }, { "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], "type": { "array": [ "u8", @@ -334,31 +642,54 @@ export type NftVoter = { }, { "name": "registrar", + "docs": [ + "Registrar which stores NFT voting configuration for the given Realm" + ], "type": { "kind": "struct", "fields": [ { "name": "governanceProgramId", - "type": "publicKey" + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" }, { "name": "realm", - "type": "publicKey" + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is used the mint is only used as identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" }, { "name": "collectionConfigs", + "docs": [ + "MPL Collection used for voting" + ], "type": { "vec": { - "defined": "CollectionConfig" + "defined": { + "name": "collectionConfig" + } } } }, { "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], "type": { "array": [ "u8", @@ -369,80 +700,120 @@ export type NftVoter = { ] } }, + { + "name": "voterWeightAction", + "docs": [ + "VoterWeightAction enum as defined in spl-governance-addin-api", + "It's redefined here for Anchor to export it to IDL" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "castVote" + }, + { + "name": "commentProposal" + }, + { + "name": "createGovernance" + }, + { + "name": "createProposal" + }, + { + "name": "signOffProposal" + } + ] + } + }, { "name": "voterWeightRecord", + "docs": [ + "VoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide voting power to the governance program from external addin contracts" + ], "type": { "kind": "struct", "fields": [ { "name": "realm", - "type": "publicKey" + "docs": [ + "The Realm the VoterWeightRecord belongs to" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing Token Mint the VoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" }, { "name": "governingTokenOwner", - "type": "publicKey" + "docs": [ + "The owner of the governing token and voter", + "This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner" + ], + "type": "pubkey" }, { "name": "voterWeight", + "docs": [ + "Voter's weight", + "The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)" + ], "type": "u64" }, { "name": "voterWeightExpiry", + "docs": [ + "The slot when the voting weight expires", + "It should be set to None if the weight never expires", + "If the voter weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], "type": { "option": "u64" } }, { "name": "weightAction", + "docs": [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + "When the action is provided then the governance program asserts the executing action is the same as specified by the addin" + ], "type": { "option": { - "defined": "VoterWeightAction" + "defined": { + "name": "voterWeightAction" + } } } }, { "name": "weightActionTarget", + "docs": [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + "For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target", + "When the target is provided then the governance program asserts the target is the same as specified by the addin" + ], "type": { - "option": "publicKey" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] + "option": "pubkey" } - } - ] - } - } - ], - "types": [ - { - "name": "CollectionConfig", - "type": { - "kind": "struct", - "fields": [ - { - "name": "collection", - "type": "publicKey" - }, - { - "name": "size", - "type": "u32" - }, - { - "name": "weight", - "type": "u64" }, { "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], "type": { "array": [ "u8", @@ -452,676 +823,6 @@ export type NftVoter = { } ] } - }, - { - "name": "NftVoterError", - "type": { - "kind": "enum", - "variants": [ - { - "name": "InvalidRealmAuthority" - }, - { - "name": "InvalidRealmForRegistrar" - }, - { - "name": "InvalidCollectionSize" - }, - { - "name": "InvalidMaxVoterWeightRecordRealm" - }, - { - "name": "InvalidMaxVoterWeightRecordMint" - }, - { - "name": "CastVoteIsNotAllowed" - }, - { - "name": "InvalidVoterWeightRecordRealm" - }, - { - "name": "InvalidVoterWeightRecordMint" - }, - { - "name": "InvalidTokenOwnerForVoterWeightRecord" - }, - { - "name": "CollectionMustBeVerified" - }, - { - "name": "VoterDoesNotOwnNft" - }, - { - "name": "CollectionNotFound" - }, - { - "name": "MissingMetadataCollection" - }, - { - "name": "TokenMetadataDoesNotMatch" - }, - { - "name": "InvalidAccountOwner" - }, - { - "name": "InvalidTokenMetadataAccount" - }, - { - "name": "DuplicatedNftDetected" - }, - { - "name": "InvalidNftAmount" - }, - { - "name": "NftAlreadyVoted" - }, - { - "name": "InvalidProposalForNftVoteRecord" - }, - { - "name": "InvalidTokenOwnerForNftVoteRecord" - }, - { - "name": "VoteRecordMustBeWithdrawn" - }, - { - "name": "InvalidVoteRecordForNftVoteRecord" - }, - { - "name": "VoterWeightRecordMustBeExpired" - }, - { - "name": "CannotConfigureCollectionWithVotingProposals" - } - ] - } - }, - { - "name": "VoterWeightAction", - "type": { - "kind": "enum", - "variants": [ - { - "name": "CastVote" - }, - { - "name": "CommentProposal" - }, - { - "name": "CreateGovernance" - }, - { - "name": "CreateProposal" - }, - { - "name": "SignOffProposal" - } - ] - } - } - ] -}; - -export const IDL: NftVoter = { - "version": "0.0.0", - "name": "nft_voter", - "instructions": [ - { - "name": "createRegistrar", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "governingTokenMint", - "isMut": false, - "isSigner": false - }, - { - "name": "realmAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "maxCollections", - "type": "u8" - } - ] - }, - { - "name": "createVoterWeightRecord", - "accounts": [ - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "realmGoverningTokenMint", - "isMut": false, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "governingTokenOwner", - "type": "publicKey" - } - ] - }, - { - "name": "createMaxVoterWeightRecord", - "accounts": [ - { - "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "realmGoverningTokenMint", - "isMut": false, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [] - }, - { - "name": "updateVoterWeightRecord", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "voterWeightAction", - "type": { - "defined": "VoterWeightAction" - } - } - ] - }, - { - "name": "relinquishNftVote", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "governance", - "isMut": false, - "isSigner": false - }, - { - "name": "proposal", - "isMut": false, - "isSigner": false - }, - { - "name": "voterTokenOwnerRecord", - "isMut": false, - "isSigner": false - }, - { - "name": "voterAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "voteRecord", - "isMut": false, - "isSigner": false - }, - { - "name": "beneficiary", - "isMut": true, - "isSigner": false - } - ], - "args": [] - }, - { - "name": "configureCollection", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "realmAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "collection", - "isMut": false, - "isSigner": false - }, - { - "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "weight", - "type": "u64" - }, - { - "name": "size", - "type": "u32" - } - ] - }, - { - "name": "castNftVote", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "voterTokenOwnerRecord", - "isMut": false, - "isSigner": false - }, - { - "name": "voterAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "proposal", - "type": "publicKey" - } - ] - } - ], - "accounts": [ - { - "name": "nftVoteRecord", - "type": { - "kind": "struct", - "fields": [ - { - "name": "proposal", - "type": "publicKey" - }, - { - "name": "nftMint", - "type": "publicKey" - }, - { - "name": "governingTokenOwner", - "type": "publicKey" - } - ] - } - }, - { - "name": "maxVoterWeightRecord", - "type": { - "kind": "struct", - "fields": [ - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "maxVoterWeight", - "type": "u64" - }, - { - "name": "maxVoterWeightExpiry", - "type": { - "option": "u64" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - }, - { - "name": "registrar", - "type": { - "kind": "struct", - "fields": [ - { - "name": "governanceProgramId", - "type": "publicKey" - }, - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "collectionConfigs", - "type": { - "vec": { - "defined": "CollectionConfig" - } - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 128 - ] - } - } - ] - } - }, - { - "name": "voterWeightRecord", - "type": { - "kind": "struct", - "fields": [ - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "governingTokenOwner", - "type": "publicKey" - }, - { - "name": "voterWeight", - "type": "u64" - }, - { - "name": "voterWeightExpiry", - "type": { - "option": "u64" - } - }, - { - "name": "weightAction", - "type": { - "option": { - "defined": "VoterWeightAction" - } - } - }, - { - "name": "weightActionTarget", - "type": { - "option": "publicKey" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - } - ], - "types": [ - { - "name": "CollectionConfig", - "type": { - "kind": "struct", - "fields": [ - { - "name": "collection", - "type": "publicKey" - }, - { - "name": "size", - "type": "u32" - }, - { - "name": "weight", - "type": "u64" - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - }, - { - "name": "NftVoterError", - "type": { - "kind": "enum", - "variants": [ - { - "name": "InvalidRealmAuthority" - }, - { - "name": "InvalidRealmForRegistrar" - }, - { - "name": "InvalidCollectionSize" - }, - { - "name": "InvalidMaxVoterWeightRecordRealm" - }, - { - "name": "InvalidMaxVoterWeightRecordMint" - }, - { - "name": "CastVoteIsNotAllowed" - }, - { - "name": "InvalidVoterWeightRecordRealm" - }, - { - "name": "InvalidVoterWeightRecordMint" - }, - { - "name": "InvalidTokenOwnerForVoterWeightRecord" - }, - { - "name": "CollectionMustBeVerified" - }, - { - "name": "VoterDoesNotOwnNft" - }, - { - "name": "CollectionNotFound" - }, - { - "name": "MissingMetadataCollection" - }, - { - "name": "TokenMetadataDoesNotMatch" - }, - { - "name": "InvalidAccountOwner" - }, - { - "name": "InvalidTokenMetadataAccount" - }, - { - "name": "DuplicatedNftDetected" - }, - { - "name": "InvalidNftAmount" - }, - { - "name": "NftAlreadyVoted" - }, - { - "name": "InvalidProposalForNftVoteRecord" - }, - { - "name": "InvalidTokenOwnerForNftVoteRecord" - }, - { - "name": "VoteRecordMustBeWithdrawn" - }, - { - "name": "InvalidVoteRecordForNftVoteRecord" - }, - { - "name": "VoterWeightRecordMustBeExpired" - }, - { - "name": "CannotConfigureCollectionWithVotingProposals" - } - ] - } - }, - { - "name": "VoterWeightAction", - "type": { - "kind": "enum", - "variants": [ - { - "name": "CastVote" - }, - { - "name": "CommentProposal" - }, - { - "name": "CreateGovernance" - }, - { - "name": "CreateProposal" - }, - { - "name": "SignOffProposal" - } - ] - } } ] }; diff --git a/src/realmVoter/client.ts b/src/realmVoter/client.ts index 8e78bf2f..8eb339df 100644 --- a/src/realmVoter/client.ts +++ b/src/realmVoter/client.ts @@ -1,10 +1,6 @@ -import { Program, Provider } from '@project-serum/anchor'; -import { PublicKey } from '@solana/web3.js'; -import { RealmVoter, IDL } from './realm_voter'; - -export const REALM_VOTER_ID = new PublicKey( - 'GRmVtfLq2BPeWs5EDoQoZc787VYkhdkA11k63QM1Xemz', -); +import { Program, Provider } from '@coral-xyz/anchor'; +import { RealmVoter } from './realm_voter'; +import RealmVoterIDL from './realm_voter.json'; export class RealmVoterClient { constructor(public program: Program, public devnet?: boolean) {} @@ -13,12 +9,8 @@ export class RealmVoterClient { provider: Provider, devnet?: boolean, ): Promise { - // alternatively we could fetch from chain - // const idl = await Program.fetchIdl(VSR_ID, provider); - const idl = IDL; - return new RealmVoterClient( - new Program(idl as RealmVoter, REALM_VOTER_ID, provider), + new Program(RealmVoterIDL as RealmVoter, provider), devnet, ); } diff --git a/src/realmVoter/realm_voter.json b/src/realmVoter/realm_voter.json new file mode 100644 index 00000000..2976d34c --- /dev/null +++ b/src/realmVoter/realm_voter.json @@ -0,0 +1,747 @@ +{ + "address": "GRmVtfLq2BPeWs5EDoQoZc787VYkhdkA11k63QM1Xemz", + "metadata": { + "name": "realm_voter", + "version": "0.0.1", + "spec": "0.1.0", + "description": "SPL Governance plugin granting governance power through Realms membership" + }, + "instructions": [ + { + "name": "configure_governance_program", + "discriminator": [ + 249, + 113, + 78, + 90, + 175, + 252, + 38, + 185 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "Registrar which we configure the provided spl-governance instance for" + ], + "writable": true + }, + { + "name": "realm" + }, + { + "name": "realm_authority", + "docs": [ + "Authority of the Realm must sign the transaction and must match realm.authority" + ], + "signer": true + }, + { + "name": "governance_program_id", + "docs": [ + "The onus is entirely on the caller side to ensure the provided instance is correct", + "In future versions once we have the registry of spl-governance instances it could be validated against the registry" + ] + } + ], + "args": [ + { + "name": "change_type", + "type": { + "defined": { + "name": "CollectionItemChangeType" + } + } + } + ] + }, + { + "name": "configure_voter_weights", + "discriminator": [ + 183, + 82, + 128, + 126, + 12, + 243, + 124, + 214 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The Registrar for the given realm and governing_token_mint" + ], + "writable": true + }, + { + "name": "realm" + }, + { + "name": "realm_authority", + "docs": [ + "Authority of the Realm must sign and match realm.authority" + ], + "signer": true + }, + { + "name": "max_voter_weight_record", + "docs": [ + "MaxVoterWeightRecord for the given registrar.realm and registrar.governing_token_mint" + ], + "writable": true + } + ], + "args": [ + { + "name": "realm_member_voter_weight", + "type": "u64" + }, + { + "name": "max_voter_weight", + "type": "u64" + } + ] + }, + { + "name": "create_max_voter_weight_record", + "discriminator": [ + 182, + 70, + 243, + 119, + 162, + 176, + 38, + 248 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "max_voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 109, + 97, + 120, + 45, + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "Registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "Registrar" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "create_registrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The Realm Voter Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "governing_token_mint" + } + ] + } + }, + { + "name": "governance_program_id", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm", + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] + }, + { + "name": "governing_token_mint", + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] + }, + { + "name": "realm_authority", + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "max_governance_programs", + "type": "u8" + } + ] + }, + { + "name": "create_voter_weight_record", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "Registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "Registrar" + }, + { + "kind": "arg", + "path": "governing_token_owner" + } + ] + } + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "governing_token_owner", + "type": "pubkey" + } + ] + }, + { + "name": "update_voter_weight_record", + "discriminator": [ + 45, + 185, + 3, + 36, + 109, + 190, + 115, + 169 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The RealmVoter voting Registrar" + ] + }, + { + "name": "voter_weight_record", + "writable": true + }, + { + "name": "token_owner_record", + "docs": [ + "TokenOwnerRecord for any of the configured spl-governance instances" + ] + } + ], + "args": [] + } + ], + "accounts": [ + { + "name": "MaxVoterWeightRecord", + "discriminator": [ + 157, + 95, + 242, + 151, + 16, + 98, + 26, + 118 + ] + }, + { + "name": "Registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 + ] + }, + { + "name": "VoterWeightRecord", + "discriminator": [ + 46, + 249, + 155, + 75, + 153, + 248, + 116, + 9 + ] + } + ], + "types": [ + { + "name": "CollectionItemChangeType", + "docs": [ + "Enum defining collection item change type" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "Upsert" + }, + { + "name": "Remove" + } + ] + } + }, + { + "name": "GovernanceProgramConfig", + "docs": [ + "Configuration of an spl-governance instance used to grant governance power" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "program_id", + "docs": [ + "The program id of the configured spl-governance instance" + ], + "type": "pubkey" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "MaxVoterWeightRecord", + "docs": [ + "MaxVoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide max voting power to the governance program from external addin contracts" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "realm", + "docs": [ + "The Realm the MaxVoterWeightRecord belongs to" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing Token Mint the MaxVoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" + }, + { + "name": "max_voter_weight", + "docs": [ + "Max voter weight", + "The max voter weight provided by the addin for the given realm and governing_token_mint" + ], + "type": "u64" + }, + { + "name": "max_voter_weight_expiry", + "docs": [ + "The slot when the max voting weight expires", + "It should be set to None if the weight never expires", + "If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], + "type": { + "option": "u64" + } + }, + { + "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, + { + "name": "Registrar", + "docs": [ + "Registrar which stores spl-governance configurations for the given Realm" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "governance_program_id", + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" + }, + { + "name": "realm", + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is enabled the mint is only used as the identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" + }, + { + "name": "governance_program_configs", + "docs": [ + "spl-governance instances used for governance power", + "Any DAO member of any DAO created using the configured spl-governances would be given 1 vote", + "TODO: Once we have on-chain spl-governance registry this configuration won't be needed any longer" + ], + "type": { + "vec": { + "defined": { + "name": "GovernanceProgramConfig" + } + } + } + }, + { + "name": "realm_member_voter_weight", + "docs": [ + "Vote weight assigned to a member of any of the Realms from the configured spl-governances" + ], + "type": "u64" + }, + { + "name": "max_voter_weight", + "docs": [ + "Max voter weight (expressed in governing_token_mint decimal units) is used to establish the theoretical Max Attendance Quorum which is then used to calculate Approval Quorum", + "This manual configuration is a rough estimate because it's not practical to calculate on-chain the number of all DAO members for the given spl-governance instances", + "", + "Note: This is not a security vulnerability because the plugin is inherently not secure and used only to encourage DAO usage and registration of spl-governance instances" + ], + "type": "u64" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 128 + ] + } + } + ] + } + }, + { + "name": "VoterWeightAction", + "docs": [ + "VoterWeightAction enum as defined in spl-governance-addin-api", + "It's redefined here for Anchor to export it to IDL" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "CastVote" + }, + { + "name": "CommentProposal" + }, + { + "name": "CreateGovernance" + }, + { + "name": "CreateProposal" + }, + { + "name": "SignOffProposal" + } + ] + } + }, + { + "name": "VoterWeightRecord", + "docs": [ + "VoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide voting power to the governance program from external addin contracts" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "realm", + "docs": [ + "The Realm the VoterWeightRecord belongs to" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing Token Mint the VoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" + }, + { + "name": "governing_token_owner", + "docs": [ + "The owner of the governing token and voter", + "This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner" + ], + "type": "pubkey" + }, + { + "name": "voter_weight", + "docs": [ + "Voter's weight", + "The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)" + ], + "type": "u64" + }, + { + "name": "voter_weight_expiry", + "docs": [ + "The slot when the voting weight expires", + "It should be set to None if the weight never expires", + "If the voter weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], + "type": { + "option": "u64" + } + }, + { + "name": "weight_action", + "docs": [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + "When the action is provided then the governance program asserts the executing action is the same as specified by the addin" + ], + "type": { + "option": { + "defined": { + "name": "VoterWeightAction" + } + } + } + }, + { + "name": "weight_action_target", + "docs": [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + "For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target", + "When the target is provided then the governance program asserts the target is the same as specified by the addin" + ], + "type": { + "option": "pubkey" + } + }, + { + "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/realmVoter/realm_voter.ts b/src/realmVoter/realm_voter.ts index 95119463..765c8b85 100644 --- a/src/realmVoter/realm_voter.ts +++ b/src/realmVoter/realm_voter.ts @@ -1,153 +1,103 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/realm_voter.json`. + */ export type RealmVoter = { - "version": "0.0.1", - "name": "realm_voter", + "address": "GRmVtfLq2BPeWs5EDoQoZc787VYkhdkA11k63QM1Xemz", + "metadata": { + "name": "realmVoter", + "version": "0.0.1", + "spec": "0.1.0", + "description": "SPL Governance plugin granting governance power through Realms membership" + }, "instructions": [ { - "name": "createRegistrar", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "governingTokenMint", - "isMut": false, - "isSigner": false - }, - { - "name": "realmAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } + "name": "configureGovernanceProgram", + "discriminator": [ + 249, + 113, + 78, + 90, + 175, + 252, + 38, + 185 ], - "args": [ - { - "name": "maxGovernancePrograms", - "type": "u8" - } - ] - }, - { - "name": "createVoterWeightRecord", "accounts": [ { "name": "registrar", - "isMut": false, - "isSigner": false + "docs": [ + "Registrar which we configure the provided spl-governance instance for" + ], + "writable": true }, { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false + "name": "realm" }, { - "name": "payer", - "isMut": true, - "isSigner": true + "name": "realmAuthority", + "docs": [ + "Authority of the Realm must sign the transaction and must match realm.authority" + ], + "signer": true }, { - "name": "systemProgram", - "isMut": false, - "isSigner": false + "name": "governanceProgramId", + "docs": [ + "The onus is entirely on the caller side to ensure the provided instance is correct", + "In future versions once we have the registry of spl-governance instances it could be validated against the registry" + ] } ], "args": [ { - "name": "governingTokenOwner", - "type": "publicKey" + "name": "changeType", + "type": { + "defined": { + "name": "collectionItemChangeType" + } + } } ] }, - { - "name": "createMaxVoterWeightRecord", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [] - }, - { - "name": "updateVoterWeightRecord", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "voterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "tokenOwnerRecord", - "isMut": false, - "isSigner": false - } - ], - "args": [] - }, { "name": "configureVoterWeights", + "discriminator": [ + 183, + 82, + 128, + 126, + 12, + 243, + 124, + 214 + ], "accounts": [ { "name": "registrar", - "isMut": true, - "isSigner": false + "docs": [ + "The Registrar for the given realm and governing_token_mint" + ], + "writable": true }, { - "name": "realm", - "isMut": false, - "isSigner": false + "name": "realm" }, { "name": "realmAuthority", - "isMut": false, - "isSigner": true + "docs": [ + "Authority of the Realm must sign and match realm.authority" + ], + "signer": true }, { "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false + "docs": [ + "MaxVoterWeightRecord for the given registrar.realm and registrar.governing_token_mint" + ], + "writable": true } ], "args": [ @@ -162,314 +112,168 @@ export type RealmVoter = { ] }, { - "name": "configureGovernanceProgram", + "name": "createMaxVoterWeightRecord", + "discriminator": [ + 182, + 70, + 243, + 119, + 162, + 176, + 38, + 248 + ], "accounts": [ { - "name": "registrar", - "isMut": true, - "isSigner": false + "name": "registrar" }, { - "name": "realm", - "isMut": false, - "isSigner": false + "name": "maxVoterWeightRecord", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 109, + 97, + 120, + 45, + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "registrar" + } + ] + } }, { - "name": "realmAuthority", - "isMut": false, - "isSigner": true + "name": "payer", + "writable": true, + "signer": true }, { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false + "name": "systemProgram", + "address": "11111111111111111111111111111111" } ], - "args": [ - { - "name": "changeType", - "type": { - "defined": "crate::state::CollectionItemChangeType" - } - } - ] - } - ], - "accounts": [ - { - "name": "maxVoterWeightRecord", - "type": { - "kind": "struct", - "fields": [ - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "maxVoterWeight", - "type": "u64" - }, - { - "name": "maxVoterWeightExpiry", - "type": { - "option": "u64" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - }, - { - "name": "registrar", - "type": { - "kind": "struct", - "fields": [ - { - "name": "governanceProgramId", - "type": "publicKey" - }, - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "governanceProgramConfigs", - "type": { - "vec": { - "defined": "GovernanceProgramConfig" - } - } - }, - { - "name": "realmMemberVoterWeight", - "type": "u64" - }, - { - "name": "maxVoterWeight", - "type": "u64" - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 128 - ] - } - } - ] - } - }, - { - "name": "voterWeightRecord", - "type": { - "kind": "struct", - "fields": [ - { - "name": "realm", - "type": "publicKey" - }, - { - "name": "governingTokenMint", - "type": "publicKey" - }, - { - "name": "governingTokenOwner", - "type": "publicKey" - }, - { - "name": "voterWeight", - "type": "u64" - }, - { - "name": "voterWeightExpiry", - "type": { - "option": "u64" - } - }, - { - "name": "weightAction", - "type": { - "option": { - "defined": "VoterWeightAction" - } - } - }, - { - "name": "weightActionTarget", - "type": { - "option": "publicKey" - } - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - } - ], - "types": [ - { - "name": "GovernanceProgramConfig", - "type": { - "kind": "struct", - "fields": [ - { - "name": "programId", - "type": "publicKey" - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - }, - { - "name": "CollectionItemChangeType", - "type": { - "kind": "enum", - "variants": [ - { - "name": "Upsert" - }, - { - "name": "Remove" - } - ] - } - }, - { - "name": "VoterWeightAction", - "type": { - "kind": "enum", - "variants": [ - { - "name": "CastVote" - }, - { - "name": "CommentProposal" - }, - { - "name": "CreateGovernance" - }, - { - "name": "CreateProposal" - }, - { - "name": "SignOffProposal" - } - ] - } - } - ], - "errors": [ - { - "code": 6000, - "name": "InvalidRealmAuthority", - "msg": "Invalid Realm Authority" - }, - { - "code": 6001, - "name": "InvalidRealmForRegistrar", - "msg": "Invalid Realm for Registrar" - }, - { - "code": 6002, - "name": "InvalidVoterWeightRecordRealm", - "msg": "Invalid VoterWeightRecord Realm" - }, - { - "code": 6003, - "name": "InvalidVoterWeightRecordMint", - "msg": "Invalid VoterWeightRecord Mint" - }, - { - "code": 6004, - "name": "TokenOwnerRecordFromOwnRealmNotAllowed", - "msg": "TokenOwnerRecord from own realm is not allowed" - }, - { - "code": 6005, - "name": "GovernanceProgramNotConfigured", - "msg": "Governance program not configured" + "args": [] }, - { - "code": 6006, - "name": "GoverningTokenOwnerMustMatch", - "msg": "Governing TokenOwner must match" - } - ] -}; - -export const IDL: RealmVoter = { - "version": "0.0.1", - "name": "realm_voter", - "instructions": [ { "name": "createRegistrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 + ], "accounts": [ { "name": "registrar", - "isMut": true, - "isSigner": false + "docs": [ + "The Realm Voter Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "governingTokenMint" + } + ] + } }, { "name": "governanceProgramId", - "isMut": false, - "isSigner": false + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] }, { "name": "realm", - "isMut": false, - "isSigner": false + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] }, { "name": "governingTokenMint", - "isMut": false, - "isSigner": false + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] }, { "name": "realmAuthority", - "isMut": false, - "isSigner": true + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true }, { "name": "payer", - "isMut": true, - "isSigner": true + "writable": true, + "signer": true }, { "name": "systemProgram", - "isMut": false, - "isSigner": false + "address": "11111111111111111111111111111111" } ], "args": [ @@ -481,177 +285,257 @@ export const IDL: RealmVoter = { }, { "name": "createVoterWeightRecord", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], "accounts": [ { - "name": "registrar", - "isMut": false, - "isSigner": false + "name": "registrar" }, { "name": "voterWeightRecord", - "isMut": true, - "isSigner": false + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "registrar" + }, + { + "kind": "arg", + "path": "governingTokenOwner" + } + ] + } }, { "name": "payer", - "isMut": true, - "isSigner": true + "writable": true, + "signer": true }, { "name": "systemProgram", - "isMut": false, - "isSigner": false + "address": "11111111111111111111111111111111" } ], "args": [ { "name": "governingTokenOwner", - "type": "publicKey" + "type": "pubkey" } ] }, - { - "name": "createMaxVoterWeightRecord", - "accounts": [ - { - "name": "registrar", - "isMut": false, - "isSigner": false - }, - { - "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false - }, - { - "name": "payer", - "isMut": true, - "isSigner": true - }, - { - "name": "systemProgram", - "isMut": false, - "isSigner": false - } - ], - "args": [] - }, { "name": "updateVoterWeightRecord", + "discriminator": [ + 45, + 185, + 3, + 36, + 109, + 190, + 115, + 169 + ], "accounts": [ { "name": "registrar", - "isMut": false, - "isSigner": false + "docs": [ + "The RealmVoter voting Registrar" + ] }, { "name": "voterWeightRecord", - "isMut": true, - "isSigner": false + "writable": true }, { "name": "tokenOwnerRecord", - "isMut": false, - "isSigner": false + "docs": [ + "TokenOwnerRecord for any of the configured spl-governance instances" + ] } ], "args": [] + } + ], + "accounts": [ + { + "name": "maxVoterWeightRecord", + "discriminator": [ + 157, + 95, + 242, + 151, + 16, + 98, + 26, + 118 + ] }, { - "name": "configureVoterWeights", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "realmAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "maxVoterWeightRecord", - "isMut": true, - "isSigner": false - } - ], - "args": [ - { - "name": "realmMemberVoterWeight", - "type": "u64" - }, - { - "name": "maxVoterWeight", - "type": "u64" - } + "name": "registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 ] }, { - "name": "configureGovernanceProgram", - "accounts": [ - { - "name": "registrar", - "isMut": true, - "isSigner": false - }, - { - "name": "realm", - "isMut": false, - "isSigner": false - }, - { - "name": "realmAuthority", - "isMut": false, - "isSigner": true - }, - { - "name": "governanceProgramId", - "isMut": false, - "isSigner": false - } - ], - "args": [ - { - "name": "changeType", - "type": { - "defined": "crate::state::CollectionItemChangeType" - } - } + "name": "voterWeightRecord", + "discriminator": [ + 46, + 249, + 155, + 75, + 153, + 248, + 116, + 9 ] } ], - "accounts": [ + "types": [ + { + "name": "collectionItemChangeType", + "docs": [ + "Enum defining collection item change type" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "upsert" + }, + { + "name": "remove" + } + ] + } + }, + { + "name": "governanceProgramConfig", + "docs": [ + "Configuration of an spl-governance instance used to grant governance power" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "programId", + "docs": [ + "The program id of the configured spl-governance instance" + ], + "type": "pubkey" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 8 + ] + } + } + ] + } + }, { "name": "maxVoterWeightRecord", + "docs": [ + "MaxVoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide max voting power to the governance program from external addin contracts" + ], "type": { "kind": "struct", "fields": [ { "name": "realm", - "type": "publicKey" + "docs": [ + "The Realm the MaxVoterWeightRecord belongs to" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing Token Mint the MaxVoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" }, { "name": "maxVoterWeight", + "docs": [ + "Max voter weight", + "The max voter weight provided by the addin for the given realm and governing_token_mint" + ], "type": "u64" }, { "name": "maxVoterWeightExpiry", + "docs": [ + "The slot when the max voting weight expires", + "It should be set to None if the weight never expires", + "If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], "type": { "option": "u64" } }, { "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], "type": { "array": [ "u8", @@ -664,39 +548,73 @@ export const IDL: RealmVoter = { }, { "name": "registrar", + "docs": [ + "Registrar which stores spl-governance configurations for the given Realm" + ], "type": { "kind": "struct", "fields": [ { "name": "governanceProgramId", - "type": "publicKey" + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" }, { "name": "realm", - "type": "publicKey" + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is enabled the mint is only used as the identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" }, { "name": "governanceProgramConfigs", + "docs": [ + "spl-governance instances used for governance power", + "Any DAO member of any DAO created using the configured spl-governances would be given 1 vote", + "TODO: Once we have on-chain spl-governance registry this configuration won't be needed any longer" + ], "type": { "vec": { - "defined": "GovernanceProgramConfig" + "defined": { + "name": "governanceProgramConfig" + } } } }, { "name": "realmMemberVoterWeight", + "docs": [ + "Vote weight assigned to a member of any of the Realms from the configured spl-governances" + ], "type": "u64" }, { "name": "maxVoterWeight", + "docs": [ + "Max voter weight (expressed in governing_token_mint decimal units) is used to establish the theoretical Max Attendance Quorum which is then used to calculate Approval Quorum", + "This manual configuration is a rough estimate because it's not practical to calculate on-chain the number of all DAO members for the given spl-governance instances", + "", + "Note: This is not a security vulnerability because the plugin is inherently not secure and used only to encourage DAO usage and registration of spl-governance instances" + ], "type": "u64" }, { "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], "type": { "array": [ "u8", @@ -707,49 +625,120 @@ export const IDL: RealmVoter = { ] } }, + { + "name": "voterWeightAction", + "docs": [ + "VoterWeightAction enum as defined in spl-governance-addin-api", + "It's redefined here for Anchor to export it to IDL" + ], + "type": { + "kind": "enum", + "variants": [ + { + "name": "castVote" + }, + { + "name": "commentProposal" + }, + { + "name": "createGovernance" + }, + { + "name": "createProposal" + }, + { + "name": "signOffProposal" + } + ] + } + }, { "name": "voterWeightRecord", + "docs": [ + "VoterWeightRecord account as defined in spl-governance-addin-api", + "It's redefined here without account_discriminator for Anchor to treat it as native account", + "", + "The account is used as an api interface to provide voting power to the governance program from external addin contracts" + ], "type": { "kind": "struct", "fields": [ { "name": "realm", - "type": "publicKey" + "docs": [ + "The Realm the VoterWeightRecord belongs to" + ], + "type": "pubkey" }, { "name": "governingTokenMint", - "type": "publicKey" + "docs": [ + "Governing Token Mint the VoterWeightRecord is associated with", + "Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only" + ], + "type": "pubkey" }, { "name": "governingTokenOwner", - "type": "publicKey" + "docs": [ + "The owner of the governing token and voter", + "This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner" + ], + "type": "pubkey" }, { "name": "voterWeight", + "docs": [ + "Voter's weight", + "The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter)" + ], "type": "u64" }, { "name": "voterWeightExpiry", + "docs": [ + "The slot when the voting weight expires", + "It should be set to None if the weight never expires", + "If the voter weight decays with time, for example for time locked based weights, then the expiry must be set", + "As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction", + "and the expiry set to the current slot to provide up to date weight" + ], "type": { "option": "u64" } }, { "name": "weightAction", + "docs": [ + "The governance action the voter's weight pertains to", + "It allows to provided voter's weight specific to the particular action the weight is evaluated for", + "When the action is provided then the governance program asserts the executing action is the same as specified by the addin" + ], "type": { "option": { - "defined": "VoterWeightAction" + "defined": { + "name": "voterWeightAction" + } } } }, { "name": "weightActionTarget", + "docs": [ + "The target the voter's weight action pertains to", + "It allows to provided voter's weight specific to the target the weight is evaluated for", + "For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target", + "When the target is provided then the governance program asserts the target is the same as specified by the addin" + ], "type": { - "option": "publicKey" + "option": "pubkey" } }, { "name": "reserved", + "docs": [ + "Reserved space for future versions" + ], "type": { "array": [ "u8", @@ -760,102 +749,5 @@ export const IDL: RealmVoter = { ] } } - ], - "types": [ - { - "name": "GovernanceProgramConfig", - "type": { - "kind": "struct", - "fields": [ - { - "name": "programId", - "type": "publicKey" - }, - { - "name": "reserved", - "type": { - "array": [ - "u8", - 8 - ] - } - } - ] - } - }, - { - "name": "CollectionItemChangeType", - "type": { - "kind": "enum", - "variants": [ - { - "name": "Upsert" - }, - { - "name": "Remove" - } - ] - } - }, - { - "name": "VoterWeightAction", - "type": { - "kind": "enum", - "variants": [ - { - "name": "CastVote" - }, - { - "name": "CommentProposal" - }, - { - "name": "CreateGovernance" - }, - { - "name": "CreateProposal" - }, - { - "name": "SignOffProposal" - } - ] - } - } - ], - "errors": [ - { - "code": 6000, - "name": "InvalidRealmAuthority", - "msg": "Invalid Realm Authority" - }, - { - "code": 6001, - "name": "InvalidRealmForRegistrar", - "msg": "Invalid Realm for Registrar" - }, - { - "code": 6002, - "name": "InvalidVoterWeightRecordRealm", - "msg": "Invalid VoterWeightRecord Realm" - }, - { - "code": 6003, - "name": "InvalidVoterWeightRecordMint", - "msg": "Invalid VoterWeightRecord Mint" - }, - { - "code": 6004, - "name": "TokenOwnerRecordFromOwnRealmNotAllowed", - "msg": "TokenOwnerRecord from own realm is not allowed" - }, - { - "code": 6005, - "name": "GovernanceProgramNotConfigured", - "msg": "Governance program not configured" - }, - { - "code": 6006, - "name": "GoverningTokenOwnerMustMatch", - "msg": "Governing TokenOwner must match" - } ] }; diff --git a/src/tokenVoter/client.ts b/src/tokenVoter/client.ts new file mode 100644 index 00000000..71ca1ddb --- /dev/null +++ b/src/tokenVoter/client.ts @@ -0,0 +1,17 @@ +import { Program, Provider } from '@coral-xyz/anchor'; +import { TokenVoter } from './token_voter'; +import TokenVoterIDL from './token_voter.json'; + +export class TokenVoterClient { + constructor(public program: Program, public devnet?: boolean) {} + + static async connect( + provider: Provider, + devnet?: boolean, + ): Promise { + return new TokenVoterClient( + new Program(TokenVoterIDL as TokenVoter, provider), + devnet, + ); + } +} diff --git a/src/tokenVoter/token_voter.json b/src/tokenVoter/token_voter.json new file mode 100644 index 00000000..d3e8a595 --- /dev/null +++ b/src/tokenVoter/token_voter.json @@ -0,0 +1,941 @@ +{ + "address": "", + "metadata": { + "name": "token_voter", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "close_voter", + "discriminator": [ + 117, + 35, + 234, + 247, + 206, + 131, + 182, + 149 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "voter.registrar", + "account": "Voter" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "voter_authority" + } + ] + } + }, + { + "name": "voter_authority", + "signer": true + }, + { + "name": "sol_destination", + "writable": true + }, + { + "name": "token_program" + } + ], + "args": [] + }, + { + "name": "configure_mint_config", + "discriminator": [ + 106, + 243, + 103, + 28, + 15, + 98, + 97, + 11 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "Registrar which we configure the provided spl-governance instance for" + ], + "writable": true + }, + { + "name": "realm" + }, + { + "name": "realm_authority", + "docs": [ + "Authority of the Realm must sign the transaction and must match realm.authority" + ], + "signer": true + }, + { + "name": "mint", + "docs": [ + "Tokens of this mint will be included in the Mint Configs" + ] + }, + { + "name": "max_voter_weight_record", + "writable": true + }, + { + "name": "governance_program_id", + "docs": [ + "The onus is entirely on the caller side to ensure the provided instance is correct", + "In future versions once we have the registry of spl-governance instances it could be validated against the registry" + ] + } + ], + "args": [ + { + "name": "digit_shift", + "type": "i8" + } + ] + }, + { + "name": "create_max_voter_weight_record", + "discriminator": [ + 182, + 70, + 243, + 119, + 162, + 176, + 38, + 248 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "max_voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 109, + 97, + 120, + 45, + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "Registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "Registrar" + } + ] + } + }, + { + "name": "governance_program_id", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm" + }, + { + "name": "realm_governing_token_mint", + "docs": [ + "Either the realm community mint or the council mint." + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "create_registrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The Realm Voter Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "governing_token_mint" + } + ] + } + }, + { + "name": "governance_program_id", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm", + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] + }, + { + "name": "governing_token_mint", + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] + }, + { + "name": "realm_authority", + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "max_mints", + "type": "u8" + } + ] + }, + { + "name": "create_voter_weight_record", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "voter_authority" + } + ] + } + }, + { + "name": "voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "voter_authority" + } + ] + } + }, + { + "name": "voter_authority", + "writable": true, + "signer": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "instructions", + "address": "Sysvar1nstructions1111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "deposit", + "discriminator": [ + 242, + 35, + 198, + 137, + 82, + 225, + 242, + 182 + ], + "accounts": [ + { + "name": "registrar", + "relations": [ + "voter" + ] + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "deposit_authority" + } + ] + } + }, + { + "name": "vault", + "writable": true + }, + { + "name": "voter_weight_record", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "deposit_authority" + } + ] + } + }, + { + "name": "token_owner_record", + "docs": [ + "TokenOwnerRecord for any of the configured spl-governance instances" + ] + }, + { + "name": "mint", + "docs": [ + "Tokens of this mint must be included in the Voting Mint Configs" + ] + }, + { + "name": "deposit_token", + "writable": true + }, + { + "name": "deposit_authority", + "writable": true, + "signer": true + }, + { + "name": "token_program" + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "associated_token_program", + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "instructions", + "address": "Sysvar1nstructions1111111111111111111111111" + } + ], + "args": [ + { + "name": "deposit_entry_index", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "withdraw", + "discriminator": [ + 183, + 18, + 70, + 156, + 148, + 109, + 161, + 34 + ], + "accounts": [ + { + "name": "registrar", + "relations": [ + "voter" + ] + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "voter_authority" + } + ] + } + }, + { + "name": "voter_authority", + "writable": true, + "signer": true + }, + { + "name": "token_owner_record", + "docs": [ + "The token_owner_record for the voter_authority. This is needed", + "to be able to forbid withdraws while the voter is engaged with", + "a vote or has an open proposal.", + "", + "- owned by registrar.governance_program_id", + "- for the registrar.realm", + "- for the registrar.realm_governing_token_mint", + "- governing_token_owner is voter_authority" + ] + }, + { + "name": "mint", + "docs": [ + "Tokens of this mint must be included in the Voting Mint Configs" + ] + }, + { + "name": "voter_weight_record", + "docs": [ + "Withdraws must update the voter weight record, to prevent a stale", + "record being used to vote after the withdraw." + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "voter_authority" + } + ] + } + }, + { + "name": "vault", + "writable": true + }, + { + "name": "destination", + "writable": true + }, + { + "name": "system_program", + "address": "11111111111111111111111111111111" + }, + { + "name": "associated_token_program", + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "token_program" + } + ], + "args": [ + { + "name": "deposit_entry_index", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "Registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 + ] + }, + { + "name": "Voter", + "discriminator": [ + 241, + 93, + 35, + 191, + 254, + 147, + 17, + 202 + ] + } + ], + "types": [ + { + "name": "DepositEntry", + "docs": [ + "Bookkeeping for a single deposit for a given mint." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "amount_deposited_native", + "docs": [ + "Amount in deposited, in native currency.", + "Withdraws directly reduce this amount.", + "", + "This directly tracks the total amount added by the user. They may", + "never withdraw more than this amount." + ], + "type": "u64" + }, + { + "name": "voting_mint_config_idx", + "docs": [ + "Points to the VotingMintConfig this deposit uses." + ], + "type": "u8" + }, + { + "name": "deposit_slot_hash", + "docs": [ + "Deposit slot hash.", + "saves deposit slot hash so that depositor cannot withdraw at the same slot." + ], + "type": "u64" + }, + { + "name": "is_used", + "type": "bool" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 38 + ] + } + } + ] + } + }, + { + "name": "Registrar", + "docs": [ + "Registrar which stores Token Voting configuration for the given Realm" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "governance_program_id", + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" + }, + { + "name": "realm", + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" + }, + { + "name": "governing_token_mint", + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is used the mint is only used as identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" + }, + { + "name": "voting_mint_configs", + "docs": [ + "Storage for voting mints and their configuration.", + "The length should be adjusted for one's use case." + ], + "type": { + "vec": { + "defined": { + "name": "VotingMintConfig" + } + } + } + }, + { + "name": "max_mints", + "docs": [ + "Max mints that voters can create." + ], + "type": "u8" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 127 + ] + } + } + ] + } + }, + { + "name": "Voter", + "docs": [ + "User account for minting voting rights." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "voter_authority", + "docs": [ + "Voter Authority who owns the account tokens." + ], + "type": "pubkey" + }, + { + "name": "registrar", + "docs": [ + "Registrar in which the voter is created in." + ], + "type": "pubkey" + }, + { + "name": "deposits", + "docs": [ + "Deposit entries for a deposit for a given mint." + ], + "type": { + "vec": { + "defined": { + "name": "DepositEntry" + } + } + } + }, + { + "name": "voter_bump", + "docs": [ + "Voter account bump." + ], + "type": "u8" + }, + { + "name": "voter_weight_record_bump", + "docs": [ + "Voter weight record account bump." + ], + "type": "u8" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 94 + ] + } + } + ] + } + }, + { + "name": "VotingMintConfig", + "docs": [ + "Exchange rate for an asset that can be used to mint voting rights.", + "", + "See documentation of configure_voting_mint for details on how", + "native token amounts convert to vote weight." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "mint", + "docs": [ + "Mint for this entry." + ], + "type": "pubkey" + }, + { + "name": "digit_shift", + "docs": [ + "Number of digits to shift native amounts, applying a 10^digit_shift factor." + ], + "type": "i8" + }, + { + "name": "reserved1", + "type": { + "array": [ + "u8", + 63 + ] + } + } + ] + } + } + ] +} \ No newline at end of file diff --git a/src/tokenVoter/token_voter.ts b/src/tokenVoter/token_voter.ts new file mode 100644 index 00000000..786e527a --- /dev/null +++ b/src/tokenVoter/token_voter.ts @@ -0,0 +1,947 @@ +/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/token_voter.json`. + */ +export type TokenVoter = { + "address": "", + "metadata": { + "name": "tokenVoter", + "version": "0.1.0", + "spec": "0.1.0", + "description": "Created with Anchor" + }, + "instructions": [ + { + "name": "closeVoter", + "discriminator": [ + 117, + 35, + 234, + 247, + 206, + 131, + 182, + 149 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "voter.registrar", + "account": "voter" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "voterAuthority" + } + ] + } + }, + { + "name": "voterAuthority", + "signer": true + }, + { + "name": "solDestination", + "writable": true + }, + { + "name": "tokenProgram" + } + ], + "args": [] + }, + { + "name": "configureMintConfig", + "discriminator": [ + 106, + 243, + 103, + 28, + 15, + 98, + 97, + 11 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "Registrar which we configure the provided spl-governance instance for" + ], + "writable": true + }, + { + "name": "realm" + }, + { + "name": "realmAuthority", + "docs": [ + "Authority of the Realm must sign the transaction and must match realm.authority" + ], + "signer": true + }, + { + "name": "mint", + "docs": [ + "Tokens of this mint will be included in the Mint Configs" + ] + }, + { + "name": "maxVoterWeightRecord", + "writable": true + }, + { + "name": "governanceProgramId", + "docs": [ + "The onus is entirely on the caller side to ensure the provided instance is correct", + "In future versions once we have the registry of spl-governance instances it could be validated against the registry" + ] + } + ], + "args": [ + { + "name": "digitShift", + "type": "i8" + } + ] + }, + { + "name": "createMaxVoterWeightRecord", + "discriminator": [ + 182, + 70, + 243, + 119, + 162, + 176, + 38, + 248 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "maxVoterWeightRecord", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 109, + 97, + 120, + 45, + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "registrar.realm", + "account": "registrar" + }, + { + "kind": "account", + "path": "registrar.governing_token_mint", + "account": "registrar" + } + ] + } + }, + { + "name": "governanceProgramId", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm" + }, + { + "name": "realmGoverningTokenMint", + "docs": [ + "Either the realm community mint or the council mint." + ] + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "createRegistrar", + "discriminator": [ + 132, + 235, + 36, + 49, + 139, + 66, + 202, + 69 + ], + "accounts": [ + { + "name": "registrar", + "docs": [ + "The Realm Voter Registrar", + "There can only be a single registrar per governance Realm and governing mint of the Realm" + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "const", + "value": [ + 114, + 101, + 103, + 105, + 115, + 116, + 114, + 97, + 114 + ] + }, + { + "kind": "account", + "path": "realm" + }, + { + "kind": "account", + "path": "governingTokenMint" + } + ] + } + }, + { + "name": "governanceProgramId", + "docs": [ + "The program id of the spl-governance program the realm belongs to" + ] + }, + { + "name": "realm", + "docs": [ + "An spl-governance Realm", + "", + "Realm is validated in the instruction:", + "- Realm is owned by the governance_program_id", + "- governing_token_mint must be the community or council mint", + "- realm_authority is realm.authority" + ] + }, + { + "name": "governingTokenMint", + "docs": [ + "Either the realm community mint or the council mint.", + "It must match Realm.community_mint or Realm.config.council_mint", + "", + "Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity", + "for the voting population and the tokens of that are no longer used" + ] + }, + { + "name": "realmAuthority", + "docs": [ + "realm_authority must sign and match Realm.authority" + ], + "signer": true + }, + { + "name": "payer", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + } + ], + "args": [ + { + "name": "maxMints", + "type": "u8" + } + ] + }, + { + "name": "createVoterWeightRecord", + "discriminator": [ + 184, + 249, + 133, + 178, + 88, + 152, + 250, + 186 + ], + "accounts": [ + { + "name": "registrar" + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "voterAuthority" + } + ] + } + }, + { + "name": "voterWeightRecord", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "voterAuthority" + } + ] + } + }, + { + "name": "voterAuthority", + "writable": true, + "signer": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + }, + { + "name": "instructions", + "address": "Sysvar1nstructions1111111111111111111111111" + } + ], + "args": [] + }, + { + "name": "deposit", + "discriminator": [ + 242, + 35, + 198, + 137, + 82, + 225, + 242, + 182 + ], + "accounts": [ + { + "name": "registrar", + "relations": [ + "voter" + ] + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "depositAuthority" + } + ] + } + }, + { + "name": "vault", + "writable": true + }, + { + "name": "voterWeightRecord", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "depositAuthority" + } + ] + } + }, + { + "name": "tokenOwnerRecord", + "docs": [ + "TokenOwnerRecord for any of the configured spl-governance instances" + ] + }, + { + "name": "mint", + "docs": [ + "Tokens of this mint must be included in the Voting Mint Configs" + ] + }, + { + "name": "depositToken", + "writable": true + }, + { + "name": "depositAuthority", + "writable": true, + "signer": true + }, + { + "name": "tokenProgram" + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + }, + { + "name": "associatedTokenProgram", + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "instructions", + "address": "Sysvar1nstructions1111111111111111111111111" + } + ], + "args": [ + { + "name": "depositEntryIndex", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + } + ] + }, + { + "name": "withdraw", + "discriminator": [ + 183, + 18, + 70, + 156, + 148, + 109, + 161, + 34 + ], + "accounts": [ + { + "name": "registrar", + "relations": [ + "voter" + ] + }, + { + "name": "voter", + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114 + ] + }, + { + "kind": "account", + "path": "voterAuthority" + } + ] + } + }, + { + "name": "voterAuthority", + "writable": true, + "signer": true + }, + { + "name": "tokenOwnerRecord", + "docs": [ + "The token_owner_record for the voter_authority. This is needed", + "to be able to forbid withdraws while the voter is engaged with", + "a vote or has an open proposal.", + "", + "- owned by registrar.governance_program_id", + "- for the registrar.realm", + "- for the registrar.realm_governing_token_mint", + "- governing_token_owner is voter_authority" + ] + }, + { + "name": "mint", + "docs": [ + "Tokens of this mint must be included in the Voting Mint Configs" + ] + }, + { + "name": "voterWeightRecord", + "docs": [ + "Withdraws must update the voter weight record, to prevent a stale", + "record being used to vote after the withdraw." + ], + "writable": true, + "pda": { + "seeds": [ + { + "kind": "account", + "path": "registrar" + }, + { + "kind": "const", + "value": [ + 118, + 111, + 116, + 101, + 114, + 45, + 119, + 101, + 105, + 103, + 104, + 116, + 45, + 114, + 101, + 99, + 111, + 114, + 100 + ] + }, + { + "kind": "account", + "path": "voterAuthority" + } + ] + } + }, + { + "name": "vault", + "writable": true + }, + { + "name": "destination", + "writable": true + }, + { + "name": "systemProgram", + "address": "11111111111111111111111111111111" + }, + { + "name": "associatedTokenProgram", + "address": "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL" + }, + { + "name": "tokenProgram" + } + ], + "args": [ + { + "name": "depositEntryIndex", + "type": "u8" + }, + { + "name": "amount", + "type": "u64" + } + ] + } + ], + "accounts": [ + { + "name": "registrar", + "discriminator": [ + 193, + 202, + 205, + 51, + 78, + 168, + 150, + 128 + ] + }, + { + "name": "voter", + "discriminator": [ + 241, + 93, + 35, + 191, + 254, + 147, + 17, + 202 + ] + } + ], + "types": [ + { + "name": "depositEntry", + "docs": [ + "Bookkeeping for a single deposit for a given mint." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "amountDepositedNative", + "docs": [ + "Amount in deposited, in native currency.", + "Withdraws directly reduce this amount.", + "", + "This directly tracks the total amount added by the user. They may", + "never withdraw more than this amount." + ], + "type": "u64" + }, + { + "name": "votingMintConfigIdx", + "docs": [ + "Points to the VotingMintConfig this deposit uses." + ], + "type": "u8" + }, + { + "name": "depositSlotHash", + "docs": [ + "Deposit slot hash.", + "saves deposit slot hash so that depositor cannot withdraw at the same slot." + ], + "type": "u64" + }, + { + "name": "isUsed", + "type": "bool" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 38 + ] + } + } + ] + } + }, + { + "name": "registrar", + "docs": [ + "Registrar which stores Token Voting configuration for the given Realm" + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "governanceProgramId", + "docs": [ + "spl-governance program the Realm belongs to" + ], + "type": "pubkey" + }, + { + "name": "realm", + "docs": [ + "Realm of the Registrar" + ], + "type": "pubkey" + }, + { + "name": "governingTokenMint", + "docs": [ + "Governing token mint the Registrar is for", + "It can either be the Community or the Council mint of the Realm", + "When the plugin is used the mint is only used as identity of the governing power (voting population)", + "and the actual token of the mint is not used" + ], + "type": "pubkey" + }, + { + "name": "votingMintConfigs", + "docs": [ + "Storage for voting mints and their configuration.", + "The length should be adjusted for one's use case." + ], + "type": { + "vec": { + "defined": { + "name": "votingMintConfig" + } + } + } + }, + { + "name": "maxMints", + "docs": [ + "Max mints that voters can create." + ], + "type": "u8" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 127 + ] + } + } + ] + } + }, + { + "name": "voter", + "docs": [ + "User account for minting voting rights." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "voterAuthority", + "docs": [ + "Voter Authority who owns the account tokens." + ], + "type": "pubkey" + }, + { + "name": "registrar", + "docs": [ + "Registrar in which the voter is created in." + ], + "type": "pubkey" + }, + { + "name": "deposits", + "docs": [ + "Deposit entries for a deposit for a given mint." + ], + "type": { + "vec": { + "defined": { + "name": "depositEntry" + } + } + } + }, + { + "name": "voterBump", + "docs": [ + "Voter account bump." + ], + "type": "u8" + }, + { + "name": "voterWeightRecordBump", + "docs": [ + "Voter weight record account bump." + ], + "type": "u8" + }, + { + "name": "reserved", + "docs": [ + "Reserved for future upgrades" + ], + "type": { + "array": [ + "u8", + 94 + ] + } + } + ] + } + }, + { + "name": "votingMintConfig", + "docs": [ + "Exchange rate for an asset that can be used to mint voting rights.", + "", + "See documentation of configure_voting_mint for details on how", + "native token amounts convert to vote weight." + ], + "type": { + "kind": "struct", + "fields": [ + { + "name": "mint", + "docs": [ + "Mint for this entry." + ], + "type": "pubkey" + }, + { + "name": "digitShift", + "docs": [ + "Number of digits to shift native amounts, applying a 10^digit_shift factor." + ], + "type": "i8" + }, + { + "name": "reserved1", + "type": { + "array": [ + "u8", + 63 + ] + } + } + ] + } + } + ] +}; diff --git a/tsconfig.json b/tsconfig.json index 84f99edf..bba6c7b8 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -11,6 +11,7 @@ "lib": ["es2019"], "noImplicitAny": false, "outDir": "dist", + "module": "NodeNext", "resolveJsonModule": true, "sourceMap": true, "target": "es6" diff --git a/yarn.lock b/yarn.lock index 85d1254c..a36c70e0 100644 --- a/yarn.lock +++ b/yarn.lock @@ -23,12 +23,40 @@ chalk "^2.0.0" js-tokens "^4.0.0" -"@babel/runtime@^7.10.5", "@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5": - version "7.17.2" - resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz" - integrity sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw== +"@babel/runtime@^7.24.5": + version "7.24.5" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.5.tgz#230946857c053a36ccc66e1dd03b17dd0c4ed02c" + integrity sha512-Nms86NXrsaeU9vbBJKni6gXiEXZ4CVpYVzEjDH9Sb8vmZ3UljyA1GSOJl/6LGPO8EHLuSF9H+IxNXHPX8QHJ4g== dependencies: - regenerator-runtime "^0.13.4" + regenerator-runtime "^0.14.0" + +"@coral-xyz/anchor@^0.30.0": + version "0.30.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.30.0.tgz#52acdba504b0008f1026d3a4bbbcb2d4feb5c69e" + integrity sha512-qreDh5ztiRHVnCbJ+RS70NJ6aSTPBYDAgFeQ7Z5QvaT5DcDIhNyt4onOciVz2ieIE1XWePOJDDu9SbNvPGBkvQ== + dependencies: + "@coral-xyz/borsh" "^0.30.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.30.0": + version "0.30.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.30.0.tgz#3e6f23e944ef6c89f2c9cbead383358752ac5e73" + integrity sha512-OrcV+7N10cChhgDRUxM4iEIuwxUHHs52XD85R8cFCUqE0vbLYrcoPPPs+VF6kZ9DhdJGVW2I6DHJOp5TykyZog== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" "@eslint/eslintrc@^0.4.3": version "0.4.3" @@ -45,27 +73,6 @@ minimatch "^3.0.4" strip-json-comments "^3.1.1" -"@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@ethersproject/bytes/-/bytes-5.5.0.tgz" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/logger@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@ethersproject/logger/-/logger-5.5.0.tgz" - integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== - -"@ethersproject/sha2@^5.5.0": - version "5.5.0" - resolved "https://registry.npmjs.org/@ethersproject/sha2/-/sha2-5.5.0.tgz" - integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - hash.js "1.1.7" - "@humanwhocodes/config-array@^0.5.0": version "0.5.0" resolved "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.5.0.tgz" @@ -80,6 +87,18 @@ resolved "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz" integrity sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA== +"@noble/curves@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.0.tgz#f05771ef64da724997f69ee1261b2417a49522d6" + integrity sha512-p+4cb332SFCrReJkCYe8Xzm0OWi4Jji5jVdIZRL/PmacmDkFNw6MrrV+gGpiPxLHbV+zKFRywUWbaseT+tZRXg== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + "@nodelib/fs.scandir@2.1.5": version "2.1.5" resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz" @@ -101,165 +120,39 @@ "@nodelib/fs.scandir" "2.1.5" fastq "^1.6.0" -"@project-serum/anchor@^0.11.1": - version "0.11.1" - resolved "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.11.1.tgz" - integrity sha512-oIdm4vTJkUy6GmE6JgqDAuQPKI7XM4TPJkjtoIzp69RZe0iAD9JP2XHx7lV1jLdYXeYHqDXfBt3zcq7W91K6PA== - dependencies: - "@project-serum/borsh" "^0.2.2" - "@solana/web3.js" "^1.17.0" - base64-js "^1.5.1" - bn.js "^5.1.2" - bs58 "^4.0.1" - buffer-layout "^1.2.0" - camelcase "^5.3.1" - crypto-hash "^1.3.0" - eventemitter3 "^4.0.7" - find "^0.3.0" - js-sha256 "^0.9.0" - pako "^2.0.3" - snake-case "^3.0.4" - toml "^3.0.0" - -"@project-serum/anchor@^0.24.2": - version "0.24.2" - resolved "https://registry.npmjs.org/@project-serum/anchor/-/anchor-0.24.2.tgz" - integrity sha512-0/718g8/DnEuwAidUwh5wLYphUYXhUbiClkuRNhvNoa+1Y8a4g2tJyxoae+emV+PG/Gikd/QUBNMkIcimiIRTA== - 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" - toml "^3.0.0" - -"@project-serum/borsh@^0.2.2", "@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" - -"@project-serum/serum@^0.13.61": - version "0.13.61" - resolved "https://registry.npmjs.org/@project-serum/serum/-/serum-0.13.61.tgz" - integrity sha512-aebaRGQ0/K7a5kJ9UXO59BAQFJILVu5jbGobU8GD2CTSy6SPceprB6/pgZmZLQIabhXWUHaZRF/wXIClgWataA== - dependencies: - "@project-serum/anchor" "^0.11.1" - "@solana/spl-token" "^0.1.6" - "@solana/web3.js" "^1.21.0" - bn.js "^5.1.2" - buffer-layout "^1.2.0" - -"@solana/buffer-layout@^3.0.0": - version "3.0.0" - resolved "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-3.0.0.tgz" - integrity sha512-MVdgAKKL39tEs0l8je0hKaXLQFb7Rdfb0Xg2LjFZd8Lfdazkg6xiS98uAZrEKvaoF3i4M95ei9RydkGIDMeo3w== - dependencies: - buffer "~6.0.3" - -"@solana/buffer-layout@^4.0.0": - version "4.0.0" - resolved "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.0.tgz" - integrity sha512-lR0EMP2HC3+Mxwd4YcnZb0smnaDw7Bl2IQWZiTevRH5ZZBZn6VRWn3/92E3qdU4SSImJkA6IDHawOHAnx/qUvQ== +"@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/spl-token@^0.1.6": - version "0.1.8" - resolved "https://registry.npmjs.org/@solana/spl-token/-/spl-token-0.1.8.tgz" - integrity sha512-LZmYCKcPQDtJgecvWOgT/cnoIQPWjdH+QVyzPcFvyDUiT0DiRjZaam4aqNUyvchLFhzgunv3d9xOoyE34ofdoQ== - dependencies: - "@babel/runtime" "^7.10.5" - "@solana/web3.js" "^1.21.0" - bn.js "^5.1.0" - buffer "6.0.3" - buffer-layout "^1.2.0" - dotenv "10.0.0" - -"@solana/web3.js@^1.17.0": - version "1.35.1" - resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.35.1.tgz" - integrity sha512-3bDawFFI0KcvgI8Ae4N4hdQ8+Bg9gu6q+IkhPrYxOF6RYnB3U+9A4u+DhHZWLvTvgoTyesi/m5HzlleKtFEqRQ== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^3.0.0" - bn.js "^5.0.0" - borsh "^0.4.0" - bs58 "^4.0.1" - buffer "6.0.1" - cross-fetch "^3.1.4" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@solana/web3.js@^1.21.0": - version "1.36.0" - resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.36.0.tgz" - integrity sha512-RNT1451iRR7TyW7EJKMCrH/0OXawIe4zVm0DWQASwXlR/u1jmW6FrmH0lujIh7cGTlfOVbH+2ZU9AVUPLBFzwA== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^3.0.0" - bn.js "^5.0.0" - borsh "^0.4.0" - bs58 "^4.0.1" - buffer "6.0.1" - cross-fetch "^3.1.4" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@solana/web3.js@^1.36.0": - version "1.41.3" - resolved "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.41.3.tgz" - integrity sha512-H+zRDh7zpzma8fvA6S16DJY2sDemw4HHU/3WR9kXQG+3jsRtIJxhOD2NAwu1M2JrXoblyE2QYHWneLKDV2Bu6g== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^4.0.0" - bn.js "^5.0.0" +"@solana/web3.js@^1.68.0": + version "1.91.8" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.91.8.tgz#0d5eb69626a92c391b53e15bfbb0bad3f6858e51" + integrity sha512-USa6OS1jbh8zOapRJ/CBZImZ8Xb7AJjROZl5adql9TpOoBN9BUzyyouS5oPuZHft7S7eB8uJPuXWYjMi6BHgOw== + dependencies: + "@babel/runtime" "^7.24.5" + "@noble/curves" "^1.4.0" + "@noble/hashes" "^1.4.0" + "@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.1" - cross-fetch "^3.1.4" + buffer "6.0.3" fast-stable-stringify "^1.0.0" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - sinon-chai "^3.7.0" + jayson "^4.1.0" + node-fetch "^2.7.0" + rpc-websockets "^7.11.0" superstruct "^0.14.2" - tweetnacl "^1.0.0" "@tsconfig/recommended@^1.0.1": version "1.0.1" resolved "https://registry.npmjs.org/@tsconfig/recommended/-/recommended-1.0.1.tgz" integrity sha512-2xN+iGTbPBEzGSnVp/Hd64vKJCJWxsi9gfs88x4PPMyEjHJoA3o5BY9r5OLPHIZU2pAQxkSAsJFqn6itClP8mQ== -"@types/bn.js@^4.11.5": - 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/connect@^3.4.33": version "3.4.35" resolved "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz" @@ -267,15 +160,6 @@ dependencies: "@types/node" "*" -"@types/express-serve-static-core@^4.17.9": - version "4.17.28" - resolved "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz" - integrity sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - "@types/json-schema@^7.0.7": version "7.0.9" resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" @@ -286,11 +170,6 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= -"@types/lodash@^4.14.159": - version "4.14.179" - resolved "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.179.tgz" - integrity sha512-uwc1x90yCKqGcIOAT6DwOSuxnrAbpkdPsUOZtwrXb4D/6wZs+6qG7QnIawDuZWg0sWpxl+ltIKCaLoMlna678w== - "@types/node@*": version "17.0.21" resolved "https://registry.npmjs.org/@types/node/-/node-17.0.21.tgz" @@ -301,16 +180,6 @@ resolved "https://registry.npmjs.org/@types/node/-/node-12.20.46.tgz" integrity sha512-cPjLXj8d6anFPzFvOPxS3fvly3Shm5nTfl6g8X5smexixbuGUf7hfr21J5tX9JW+UPStp/5P5R8qrKL5IyVJ+A== -"@types/qs@*": - version "6.9.7" - resolved "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== - "@types/ws@^7.4.4": version "7.4.7" resolved "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz" @@ -411,6 +280,13 @@ acorn@^7.4.0: resolved "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz" integrity sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A== +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" + ajv@^6.10.0, ajv@^6.12.4: version "6.12.6" resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" @@ -507,35 +383,39 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" -base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.3.1: version "1.5.1" resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" 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.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz" integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== -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== +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.0.0, bn.js@^5.1.0, bn.js@^5.1.2, bn.js@^5.2.0: +bn.js@^5.1.2, bn.js@^5.2.0: version "5.2.0" resolved "https://registry.npmjs.org/bn.js/-/bn.js-5.2.0.tgz" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== -borsh@^0.4.0: - version "0.4.0" - resolved "https://registry.npmjs.org/borsh/-/borsh-0.4.0.tgz" - integrity sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g== - dependencies: - "@types/bn.js" "^4.11.5" - bn.js "^5.0.0" - bs58 "^4.0.0" - text-encoding-utf-8 "^1.0.2" +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" @@ -568,11 +448,6 @@ braces@^3.0.1, braces@~3.0.2: 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 sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= - browser-stdout@1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/browser-stdout/-/browser-stdout-1.3.1.tgz" @@ -595,14 +470,6 @@ buffer-layout@^1.2.0, buffer-layout@^1.2.2: resolved "https://registry.npmjs.org/buffer-layout/-/buffer-layout-1.2.2.tgz" integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.1.tgz" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - buffer@6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz" @@ -623,14 +490,9 @@ callsites@^3.0.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.0.0, camelcase@^6.3.0: version "6.3.0" - resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== chalk@^2.0.0: @@ -665,11 +527,6 @@ chokidar@3.5.3: optionalDependencies: fsevents "~2.3.2" -circular-json@^0.5.9: - version "0.5.9" - resolved "https://registry.npmjs.org/circular-json/-/circular-json-0.5.9.tgz" - integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== - cliui@^7.0.2: version "7.0.4" resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" @@ -718,7 +575,7 @@ create-require@^1.1.0: resolved "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz" integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ== -cross-fetch@^3.1.4, cross-fetch@^3.1.5: +cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.5.tgz" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== @@ -798,24 +655,6 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -dotenv@10.0.0: - version "10.0.0" - resolved "https://registry.npmjs.org/dotenv/-/dotenv-10.0.0.tgz" - integrity sha512-rlBi9d8jpv9Sf1klPjNfFAuWDjKLwTIJJ/VxtoTwIR6hnZxcEOQCZg2oIL3MWBYw5GpUDKOEnND7LXTbIpQ03Q== - -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" @@ -1036,6 +875,11 @@ file-entry-cache@^6.0.1: 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" + 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" @@ -1051,13 +895,6 @@ find-up@5.0.0: locate-path "^6.0.0" path-exists "^4.0.0" -find@^0.3.0: - version "0.3.0" - resolved "https://registry.npmjs.org/find/-/find-0.3.0.tgz" - integrity sha512-iSd+O4OEYV/I36Zl8MdYJO0xD82wH528SaCieTVHhclgiYNe9y+yPKSwK+A7/WsmHL1EZ+pYUJBXWTL5qofksw== - dependencies: - traverse-chain "~0.1.0" - flat-cache@^3.0.4: version "3.0.4" resolved "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz" @@ -1149,27 +986,17 @@ has-flag@^4.0.0: resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - 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" - 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== -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= +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: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" + ms "^2.0.0" ieee754@^1.2.1: version "1.2.1" @@ -1207,7 +1034,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@^2.0.4: +inherits@2: version "2.0.4" resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1261,14 +1088,12 @@ isomorphic-ws@^4.0.1: resolved "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -jayson@^3.4.4: - version "3.6.6" - resolved "https://registry.npmjs.org/jayson/-/jayson-3.6.6.tgz" - integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== +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/express-serve-static-core" "^4.17.9" - "@types/lodash" "^4.14.159" "@types/node" "^12.12.54" "@types/ws" "^7.4.4" JSONStream "^1.3.5" @@ -1278,20 +1103,9 @@ jayson@^3.4.4: eyes "^0.1.8" isomorphic-ws "^4.0.1" json-stringify-safe "^5.0.1" - lodash "^4.17.20" uuid "^8.3.2" ws "^7.4.5" -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: - version "0.8.0" - resolved "https://registry.npmjs.org/js-sha3/-/js-sha3-0.8.0.tgz" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" @@ -1374,11 +1188,6 @@ lodash.truncate@^4.4.2: resolved "https://registry.npmjs.org/lodash.truncate/-/lodash.truncate-4.4.2.tgz" integrity sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM= -lodash@^4.17.20: - 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" @@ -1429,16 +1238,6 @@ micromatch@^4.0.4: braces "^3.0.1" picomatch "^2.2.3" -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 sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - minimatch@4.2.1: version "4.2.1" resolved "https://registry.npmjs.org/minimatch/-/minimatch-4.2.1.tgz" @@ -1507,9 +1306,9 @@ ms@2.1.2: resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.0.0: version "2.1.3" - resolved "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== nanoid@3.3.1: @@ -1530,11 +1329,6 @@ no-case@^3.0.4: 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-fetch@2.6.7: version "2.6.7" resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz" @@ -1542,7 +1336,14 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: +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.3.0" resolved "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.3.0.tgz" integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== @@ -1661,10 +1462,10 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +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== regexpp@^3.1.0: version "3.2.0" @@ -1698,16 +1499,14 @@ rimraf@^3.0.2: dependencies: glob "^7.1.3" -rpc-websockets@^7.4.2: - version "7.4.17" - resolved "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-7.4.17.tgz" - integrity sha512-eolVi/qlXS13viIUH9aqrde902wzSLAai0IjmOZSRefp5I3CSG/vCnD0c0fDSYCWuEyUoRL1BHQA8K1baEUyow== +rpc-websockets@^7.11.0: + version "7.11.0" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.11.0.tgz#05451975963a7d1a4cf36d54e200bfc4402a56d7" + integrity sha512-IkLYjayPv6Io8C/TdCL5gwgzd1hFz2vmBZrjMw/SPEXo51ETOhnzgS4Qy5GWi2JQN7HKHa66J3+2mv0fgNh/7w== dependencies: - "@babel/runtime" "^7.11.2" - circular-json "^0.5.9" eventemitter3 "^4.0.7" - uuid "^8.3.0" - ws "^7.4.5" + uuid "^8.3.2" + ws "^8.5.0" optionalDependencies: bufferutil "^4.0.1" utf-8-validate "^5.0.2" @@ -1724,15 +1523,6 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0: resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -secp256k1@^4.0.2: - 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" - semver@^7.2.1, semver@^7.3.5: version "7.3.5" resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" @@ -1768,11 +1558,6 @@ shiki@^0.10.1: vscode-oniguruma "^1.6.1" vscode-textmate "5.2.0" -sinon-chai@^3.7.0: - version "3.7.0" - resolved "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz" - integrity sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g== - slash@^3.0.0: version "3.0.0" resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" @@ -1844,6 +1629,11 @@ superstruct@^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.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.npmjs.org/supports-color/-/supports-color-8.1.1.tgz" @@ -1908,11 +1698,6 @@ tr46@~0.0.3: resolved "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz" integrity sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o= -traverse-chain@~0.1.0: - version "0.1.0" - resolved "https://registry.npmjs.org/traverse-chain/-/traverse-chain-0.1.0.tgz" - integrity sha1-YdvC1Ttp/2CRoSoWj9fUMxB+QPE= - ts-mocha@^9.0.2: version "9.0.2" resolved "https://registry.npmjs.org/ts-mocha/-/ts-mocha-9.0.2.tgz" @@ -1975,11 +1760,6 @@ tsutils@^3.21.0: dependencies: tslib "^1.8.1" -tweetnacl@^1.0.0: - 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" @@ -2022,7 +1802,7 @@ utf-8-validate@^5.0.2: dependencies: node-gyp-build "^4.3.0" -uuid@^8.3.0, uuid@^8.3.2: +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== @@ -2091,6 +1871,11 @@ ws@^7.4.5: resolved "https://registry.npmjs.org/ws/-/ws-7.5.7.tgz" integrity sha512-KMvVuFzpKBuiIXW3E4u3mySRO2/mCHSyZDJQM5NQ9Q9KHWHWh0NHgfbRMLLrceUK5qAL4ytALJbpRMjixFZh8A== +ws@^8.5.0: + version "8.17.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.17.0.tgz#d145d18eca2ed25aaf791a183903f7be5e295fea" + integrity sha512-uJq6108EgZMAl20KagGkzCKfMEjxmKvZHG7Tlq0Z6nOky7YF7aq4mOx6xK8TJ/i1LeK4Qus7INktacctDgY8Ow== + y18n@^5.0.5: version "5.0.8" resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" From b81f0ccc5b7a061ff4cd78d96c2bf9677bca5ce1 Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sat, 18 May 2024 10:27:39 +0400 Subject: [PATCH 02/11] fix nft-voter tests --- programs/nft-voter/tests/program_test/token_metadata_test.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/programs/nft-voter/tests/program_test/token_metadata_test.rs b/programs/nft-voter/tests/program_test/token_metadata_test.rs index 52ec6179..08c94ea8 100644 --- a/programs/nft-voter/tests/program_test/token_metadata_test.rs +++ b/programs/nft-voter/tests/program_test/token_metadata_test.rs @@ -139,7 +139,7 @@ impl TokenMetadataTest { payer: payer, update_authority: payer, system_program: system_program::ID, - token_program: self.program_id, + token_program: spl_token::id(), rent: None, }; From 8f7893a0ee50a4e2faa0564d9073d25ae861b25d Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sat, 18 May 2024 11:30:18 +0400 Subject: [PATCH 03/11] fix gateway tests --- programs/gateway/tests/configure_registrar.rs | 7 +++---- .../tests/fixtures/solana_gateway_program.so | Bin 161600 -> 130832 bytes 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/programs/gateway/tests/configure_registrar.rs b/programs/gateway/tests/configure_registrar.rs index 59f9e871..26b154a4 100644 --- a/programs/gateway/tests/configure_registrar.rs +++ b/programs/gateway/tests/configure_registrar.rs @@ -4,7 +4,6 @@ use anchor_lang::prelude::Pubkey; use program_test::gateway_voter_test::GatewayVoterTest; use gpl_civic_gateway::error::GatewayError; -use solana_program::instruction::InstructionError; use solana_program_test::*; use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; @@ -12,7 +11,7 @@ use crate::program_test::tools::NopOverride; use crate::{ program_test::governance_test::RealmCookie, program_test::predecessor_plugin_test::PredecessorPluginTest, - program_test::tools::{assert_anchor_err, assert_gateway_err, assert_ix_err}, + program_test::tools::{assert_anchor_err, assert_gateway_err}, }; #[tokio::test] @@ -197,7 +196,7 @@ async fn test_configure_registrar_with_invalid_spl_gov_program_id_error( .unwrap(); // Assert - assert_anchor_err(err, anchor_lang::error::ErrorCode::ConstraintOwner); + assert_gateway_err(err, GatewayError::InvalidRealmForRegistrar); Ok(()) } @@ -225,7 +224,7 @@ async fn test_configure_registrar_with_invalid_realm_error() -> Result<(), Trans .err() .unwrap(); - assert_ix_err(err, InstructionError::Custom(2004)); + assert_gateway_err(err, GatewayError::InvalidRealmForRegistrar); Ok(()) } diff --git a/programs/gateway/tests/fixtures/solana_gateway_program.so b/programs/gateway/tests/fixtures/solana_gateway_program.so index 152ae95096291618fb10c417c343c54010c0b1ad..63b733ecc98d90bc5568a17c1baf7b89cfdd7f07 100755 GIT binary patch literal 130832 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 literal 161600 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 z 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 TOZ)fx^6I3@o6_Z6j{pBZcH^A# From 1ef41c5a094afc800814bd376fb6be0c5b1c5e27 Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sun, 19 May 2024 12:16:32 +0400 Subject: [PATCH 04/11] add close_voter tests and transfer_fees tests --- .../token-voter/src/instructions/deposit.rs | 8 +- programs/token-voter/src/lib.rs | 5 + programs/token-voter/tests/close_voter.rs | 178 ++++++ programs/token-voter/tests/deposit.rs | 68 ++- .../tests/program_test/program_test_bench.rs | 134 +++-- .../tests/program_test/token_voter_test.rs | 123 +++- programs/token-voter/tests/withdraw.rs | 539 +++--------------- 7 files changed, 512 insertions(+), 543 deletions(-) create mode 100644 programs/token-voter/tests/close_voter.rs diff --git a/programs/token-voter/src/instructions/deposit.rs b/programs/token-voter/src/instructions/deposit.rs index 72ce0004..1f3d4790 100644 --- a/programs/token-voter/src/instructions/deposit.rs +++ b/programs/token-voter/src/instructions/deposit.rs @@ -1,5 +1,5 @@ use { - crate::{error::*, state::*, tools::spl_token::transfer_checked_spl_tokens}, + crate::{error::*, state::*, tools::spl_token::{transfer_checked_spl_tokens, get_current_mint_fee}}, anchor_lang::{prelude::*, solana_program::sysvar::instructions as tx_instructions}, anchor_spl::{associated_token::AssociatedToken, token_interface::{Mint, TokenAccount, TokenInterface}}, spl_governance::state::token_owner_record, }; @@ -106,6 +106,8 @@ pub fn deposit<'key, 'accounts, 'remaining, 'info>( } }; + let deposit_amount = amount.checked_sub(get_current_mint_fee(&ctx.accounts.mint.to_account_info(), amount)?).unwrap(); + // Get the exchange rate entry associated with this deposit. // fails if registrat.voting_mint_configs does not exist. let mint_idx = registrar.voting_mint_config_index(ctx.accounts.deposit_token.mint)?; @@ -122,7 +124,7 @@ pub fn deposit<'key, 'accounts, 'remaining, 'info>( match d_entry { Some(d_entry) => { - d_entry.amount_deposited_native = d_entry.amount_deposited_native.checked_add(amount).unwrap(); + d_entry.amount_deposited_native = d_entry.amount_deposited_native.checked_add(deposit_amount).unwrap(); // Deposit is only valid as of the current slot d_entry.deposit_slot_hash = current_slot_hash; @@ -131,7 +133,7 @@ pub fn deposit<'key, 'accounts, 'remaining, 'info>( None => { let deposit_entry = DepositEntry { deposit_slot_hash: current_slot_hash, - amount_deposited_native: amount, + amount_deposited_native: deposit_amount, voting_mint_config_idx: mint_idx as u8, is_used: true, reserved: [0;38] diff --git a/programs/token-voter/src/lib.rs b/programs/token-voter/src/lib.rs index 4b68d12f..a589a5e2 100644 --- a/programs/token-voter/src/lib.rs +++ b/programs/token-voter/src/lib.rs @@ -15,6 +15,7 @@ extern crate static_assertions; declare_id!("3JhBg9bSPcfWGFa3t8LH7ooVtrjm45yCkHpxYXMXstUM"); + #[program] pub mod token_voter { use super::*; @@ -23,6 +24,7 @@ pub mod token_voter { log_version(); instructions::create_registrar(ctx, max_mints) } + pub fn create_voter_weight_record(ctx: Context) -> Result<()> { log_version(); instructions::create_voter_weight_record(ctx) @@ -46,6 +48,7 @@ pub mod token_voter { deposit_entry_index: u8, amount: u64, ) -> Result<()> { + log_version(); instructions::deposit(ctx, deposit_entry_index, amount) } @@ -54,12 +57,14 @@ pub mod token_voter { deposit_entry_index: u8, amount: u64, ) -> Result<()> { + log_version(); instructions::withdraw(ctx, deposit_entry_index, amount) } pub fn close_voter<'key, 'accounts, 'remaining, 'info>( ctx: Context<'key, 'accounts, 'remaining, 'info, CloseVoter<'info>>, ) -> Result<()> { + log_version(); instructions::close_voter(ctx) } } diff --git a/programs/token-voter/tests/close_voter.rs b/programs/token-voter/tests/close_voter.rs new file mode 100644 index 00000000..e607a69a --- /dev/null +++ b/programs/token-voter/tests/close_voter.rs @@ -0,0 +1,178 @@ +use std::borrow::BorrowMut; + +use program_test::token_voter_test::TokenVoterTest; +use program_test::tools::*; +use solana_program_test::*; +use solana_sdk::transport::TransportError; +use token_voter::error::TokenVoterError; + +mod program_test; + +#[tokio::test] +async fn test_close_with_token_extensions() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + + let realm_cookie = token_voter_test + .governance + .with_realm_token_extension() + .await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let mut users_iter = token_voter_test.users.iter(); + let first_user_cookie = users_iter.next().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &second_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; + + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token_2022::id(), + 0, + amount_deposited, + ) + .await?; + + token_voter_test.bench.advance_clock().await; + + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &second_mint_cookie, + &spl_token_2022::id(), + 1, + amount_deposited, + ) + .await?; + + token_voter_test.bench.advance_clock().await; + + let err = token_voter_test + .close_voter_account( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_voter_test.mints, + &spl_token_2022::id(), + ) + .await + .err() + .unwrap(); + assert_token_voter_err(err, TokenVoterError::VotingTokenNonZero); + + token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token_2022::id(), + 0, + amount_deposited, + ) + .await?; + + token_voter_test.bench.advance_clock().await; + + let err = token_voter_test + .close_voter_account( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_voter_test.mints, + &spl_token_2022::id(), + ) + .await + .err() + .unwrap(); + assert_token_voter_err(err, TokenVoterError::VotingTokenNonZero); + + token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &second_mint_cookie, + &spl_token_2022::id(), + 1, + amount_deposited, + ) + .await?; + token_voter_test.bench.advance_clock().await; + + token_voter_test + .close_voter_account( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_voter_test.mints, + &spl_token_2022::id(), + ) + .await?; + + // Assert + // voter_data should be None. + let voter_data = token_voter_test + .bench + .borrow_mut() + .context + .borrow_mut() + .banks_client + .get_account(voter_cookie.address) + .await + .unwrap(); + + assert_eq!( + voter_data, + None + ); + + Ok(()) +} diff --git a/programs/token-voter/tests/deposit.rs b/programs/token-voter/tests/deposit.rs index 8cbdd7e3..a4ef8012 100644 --- a/programs/token-voter/tests/deposit.rs +++ b/programs/token-voter/tests/deposit.rs @@ -3,11 +3,13 @@ use program_test::token_voter_test::TokenVoterTest; use program_test::tools::*; use solana_program_test::*; use solana_sdk::instruction::InstructionError; +use solana_sdk::signer::Signer; use solana_sdk::transport::TransportError; use token_voter::error::TokenVoterError; - +use crate::program_test::program_test_bench::MintType; mod program_test; + #[tokio::test] async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> { // Arrange @@ -91,6 +93,66 @@ async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> Ok(()) } +#[tokio::test] +async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + + let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie_transfer_fees = token_voter_test.bench.with_mint(&MintType::SplTokenExtensionsWithTransferFees, None).await.unwrap(); + let _first_user_cookie_token_account = token_voter_test.bench.with_tokens(&first_mint_cookie_transfer_fees, &first_user_cookie.key.pubkey(), 100, &MintType::SplTokenExtensionsWithTransferFees).await; + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie_transfer_fees, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let amount_deposited = 100_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie_transfer_fees, + &spl_token_2022::id(), + 0, + amount_deposited, + ) + .await?; + token_voter_test.bench.advance_clock().await; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + let vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie_transfer_fees, &spl_token_2022::id()).await; + assert_eq!(voter_data.registrar, registrar_cookie.address); + assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, vault_balance); + + Ok(()) +} + #[tokio::test] async fn test_deposit_entry() -> Result<(), TransportError> { // Arrange @@ -394,9 +456,9 @@ async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { assert_eq!(second_deposit_entry.amount_deposited_native, amount_deposited); assert_eq!(voter_data.deposits.len(), 2); - let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie).await; + let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie, &spl_token::id()).await; assert_eq!(first_vault_balance, amount_deposited); - let second_vault_balance = token_voter_test.vault_balance(&voter_cookie, &second_mint_cookie).await; + let second_vault_balance = token_voter_test.vault_balance(&voter_cookie, &second_mint_cookie, &spl_token::id()).await; assert_eq!(second_vault_balance, amount_deposited); diff --git a/programs/token-voter/tests/program_test/program_test_bench.rs b/programs/token-voter/tests/program_test/program_test_bench.rs index b6da321e..b7802f5b 100644 --- a/programs/token-voter/tests/program_test/program_test_bench.rs +++ b/programs/token-voter/tests/program_test/program_test_bench.rs @@ -5,6 +5,7 @@ use anchor_lang::{ AccountDeserialize, }; +use anchor_spl::associated_token; use borsh::BorshDeserialize; use solana_program::system_program; use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; @@ -21,7 +22,7 @@ use solana_sdk::{ transport::TransportError, }; use spl_associated_token_account::get_associated_token_address_with_program_id; -use spl_token_2022::extension::{BaseStateWithExtensions, ExtensionType, StateWithExtensionsOwned}; +use spl_token_2022::extension::ExtensionType; use spl_token_client::token::ExtensionInitializationParams; use crate::program_test::tools::clone_keypair; @@ -470,23 +471,25 @@ impl ProgramTestBench { let mint_rent = self.rent.minimum_balance(space); - let instructions = [ - system_instruction::create_account( - &self.context.borrow().payer.pubkey(), - &mint_keypair.pubkey(), - mint_rent, - space as u64, - &spl_token_2022::id(), - ), - spl_token_2022::instruction::initialize_mint( - &spl_token_2022::id(), - &mint_keypair.pubkey(), - mint_authority, - freeze_authority, - 0, - ) - .unwrap(), - ]; + let mut instructions = vec![system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &mint_keypair.pubkey(), + mint_rent, + space as u64, + &spl_token_2022::id(), + )]; + + for params in extension_initialization_params { + instructions.push(params.instruction(&spl_token_2022::id(), &mint_keypair.pubkey()).unwrap()); + } + + instructions.push(spl_token_2022::instruction::initialize_mint( + &spl_token_2022::id(), + &mint_keypair.pubkey(), + mint_authority, + freeze_authority, + 0, + ).unwrap()); self.process_transaction(&instructions, Some(&[mint_keypair])) .await @@ -574,6 +577,7 @@ impl ProgramTestBench { amount: u64, mint_type: &MintType, ) -> Result { + let token_account_keypair = Keypair::new(); self.create_token_account( @@ -590,6 +594,7 @@ impl ProgramTestBench { &token_account_keypair.pubkey(), amount, mint_type, + owner, ) .await?; Ok(TokenAccountCookie { @@ -604,29 +609,44 @@ impl ProgramTestBench { token_account: &Pubkey, amount: u64, mint_type: &MintType, + owner: &Pubkey, ) -> Result<(), BanksClientError> { - let token_program_id = match mint_type { + match mint_type { MintType::SplToken => { - spl_token::id() + let mint_instruction = spl_token_2022::instruction::mint_to( + &spl_token::id(), + token_mint, + token_account, + &token_mint_authority.pubkey(), + &[], + amount, + ) + .unwrap(); + + self.process_transaction(&[mint_instruction], Some(&[token_mint_authority])) + .await } _ => { - spl_token_2022::id() - } - }; - - let mint_instruction = spl_token_2022::instruction::mint_to( - &token_program_id, - token_mint, - token_account, - &token_mint_authority.pubkey(), - &[], - amount, - ) - .unwrap(); + let associated_token_account_pubkey = associated_token::get_associated_token_address_with_program_id( + &owner, + &token_mint, + &spl_token_2022::id(), + ); + let mint_instruction = spl_token_2022::instruction::mint_to( + &spl_token_2022::id(), + token_mint, + &associated_token_account_pubkey, + &token_mint_authority.pubkey(), + &[], + amount, + ) + .unwrap(); - self.process_transaction(&[mint_instruction], Some(&[token_mint_authority])) - .await + self.process_transaction(&[mint_instruction], Some(&[token_mint_authority])) + .await + } + } } #[allow(dead_code)] @@ -637,7 +657,7 @@ impl ProgramTestBench { owner: &Pubkey, mint_type: &MintType, ) -> Result<(), BanksClientError> { - let instructions = match mint_type { + match mint_type { MintType::SplToken => { let create_account_instruction = system_instruction::create_account( &self.context.borrow().payer.pubkey(), @@ -654,43 +674,22 @@ impl ProgramTestBench { owner, ) .unwrap(); - vec![create_account_instruction, initialize_account_instruction] + + self.process_transaction(&[create_account_instruction, initialize_account_instruction], Some(&[token_account_keypair])) + .await } _ => { - let mint_account = self.get_account(token_mint).await; - let mint_info = StateWithExtensionsOwned::::unpack( - mint_account.unwrap().data, - ) - .unwrap(); - let extension_types = mint_info.get_extension_types().unwrap(); - let space = - ExtensionType::try_calculate_account_len::( - &extension_types, - ) - .unwrap(); - let mint_rent = self.rent.minimum_balance(space); - - let create_account_instruction = system_instruction::create_account( + let create_ata_account = spl_associated_token_account::instruction::create_associated_token_account( &self.context.borrow().payer.pubkey(), - &token_account_keypair.pubkey(), - mint_rent, - space as u64, - &spl_token::id(), - ); - - let initialize_account_instruction = spl_token::instruction::initialize_account( - &spl_token::id(), - &token_account_keypair.pubkey(), - token_mint, owner, - ) - .unwrap(); - vec![create_account_instruction, initialize_account_instruction] + token_mint, + &spl_token_2022::id(), + ); + self.process_transaction(&[create_ata_account], None) + .await } - }; + } - self.process_transaction(&instructions, Some(&[token_account_keypair])) - .await } #[allow(dead_code)] @@ -812,7 +811,6 @@ impl ProgramTestBench { #[allow(dead_code)] pub async fn get_anchor_account(&self, address: Pubkey) -> T { let data = self.get_account_data(address).await; - // println!("{:?}", data); let mut data_slice: &[u8] = &data; AccountDeserialize::try_deserialize(&mut data_slice).unwrap() } diff --git a/programs/token-voter/tests/program_test/token_voter_test.rs b/programs/token-voter/tests/program_test/token_voter_test.rs index 2b242725..320dbda9 100644 --- a/programs/token-voter/tests/program_test/token_voter_test.rs +++ b/programs/token-voter/tests/program_test/token_voter_test.rs @@ -2,26 +2,32 @@ use std::sync::{Arc, RwLock}; use anchor_lang::{prelude::Pubkey, system_program::System, Id}; -use anchor_spl::{associated_token::{self, AssociatedToken}, token_interface::TokenAccount}; -use solana_sdk::sysvar::instructions; +use anchor_spl::{ + associated_token::{self, AssociatedToken}, + token_interface::TokenAccount, +}; +use solana_sdk::{instruction::AccountMeta, sysvar::instructions}; use token_voter::state::*; +use crate::program_test::governance_test::GovernanceTest; +use crate::program_test::program_test_bench::ProgramTestBench; +use anchor_lang::ToAccountMetas; +use solana_program::program_pack::Pack; use solana_program_test::{BanksClientError, ProgramTest}; use solana_sdk::instruction::Instruction; use solana_sdk::signature::Keypair; use solana_sdk::signer::Signer; - -use crate::program_test::governance_test::GovernanceTest; -use crate::program_test::program_test_bench::ProgramTestBench; - use crate::program_test::governance_test::RealmCookie; use crate::program_test::tools::NopOverride; use crate::program_test::governance_test::TokenOwnerRecordCookie; -use super::{program_test_bench::{MintCookie, MintType}, LoggerWrapper, ProgramOutput}; +use super::{ + program_test_bench::{MintCookie, MintType}, + LoggerWrapper, ProgramOutput, +}; #[derive(Debug, PartialEq)] pub struct RegistrarCookie { @@ -75,7 +81,10 @@ impl TokenVoterTest { #[allow(dead_code)] pub async fn start_new() -> Self { let mut program_test = ProgramTest::new("token_voter", token_voter::id(), None); - let (mints, users) = ProgramTestBench::add_mints_and_user_cookies_spl_token(&mut program_test, MintType::SplToken); + let (mints, users) = ProgramTestBench::add_mints_and_user_cookies_spl_token( + &mut program_test, + MintType::SplToken, + ); GovernanceTest::add_program(&mut program_test); let program_id = token_voter::id(); @@ -114,7 +123,10 @@ impl TokenVoterTest { #[allow(dead_code)] pub async fn start_new_token_extensions() -> Self { let mut program_test = ProgramTest::new("token_voter", token_voter::id(), None); - let (mints, users) = ProgramTestBench::add_mints_and_user_cookies_spl_token(&mut program_test, MintType::SplTokenExtensions); + let (mints, users) = ProgramTestBench::add_mints_and_user_cookies_spl_token( + &mut program_test, + MintType::SplTokenExtensions, + ); GovernanceTest::add_program(&mut program_test); let program_id = token_voter::id(); @@ -613,6 +625,84 @@ impl TokenVoterTest { Ok(()) } + #[allow(dead_code)] + pub async fn close_voter_account( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &VoterCookie, + user_cookie: &UserCookie, + mint_cookies: &Vec, + token_program: &Pubkey, + ) -> Result<(), BanksClientError> { + self.close_voter_account_using_ix( + registrar_cookie, + voter_cookie, + user_cookie, + mint_cookies, + token_program, + NopOverride, + None, + ) + .await + } + + #[allow(dead_code)] + pub async fn close_voter_account_using_ix( + &self, + registrar_cookie: &RegistrarCookie, + voter_cookie: &VoterCookie, + user_cookie: &UserCookie, + mint_cookies: &Vec, + token_program: &Pubkey, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result<(), BanksClientError> { + let data = anchor_lang::InstructionData::data(&token_voter::instruction::CloseVoter {}); + + let accounts = token_voter::accounts::CloseVoter { + registrar: registrar_cookie.address, + voter: voter_cookie.address, + sol_destination: user_cookie.key.pubkey(), + voter_authority: user_cookie.key.pubkey(), + token_program: *token_program, + }; + + let remaining_accounts: Vec<_> = mint_cookies + .iter() + .map(|mint_cookie| { + let user_mint_ata = associated_token::get_associated_token_address_with_program_id( + &voter_cookie.address, + &mint_cookie.address, + token_program, + ); + AccountMeta::new(user_mint_ata, false) + }) + .collect(); + + let all_accounts: Vec<_> = accounts + .to_account_metas(None) + .into_iter() + .chain(remaining_accounts.into_iter()) + .collect(); + + let mut configure_mint_config_ix = Instruction { + program_id: token_voter::id(), + accounts: all_accounts, + data, + }; + + instruction_override(&mut configure_mint_config_ix); + + let default_signers = &[&user_cookie.key]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[configure_mint_config_ix], Some(signers)) + .await?; + + Ok(()) + } + #[allow(dead_code)] pub async fn get_registrar_account(&self, registrar: &Pubkey) -> Registrar { self.bench.get_anchor_account::(*registrar).await @@ -639,8 +729,8 @@ impl TokenVoterTest { } #[allow(dead_code)] - pub async fn vault_balance(&self, voter: &VoterCookie, mint: &MintCookie) -> u64 { - let vault = self.vault_address(voter.address, mint); + pub async fn vault_balance(&self, voter: &VoterCookie, mint: &MintCookie, token_program_id: &Pubkey) -> u64 { + let vault = self.associated_token_address(voter.address, mint, token_program_id); self.bench .get_anchor_account::(vault) .await @@ -656,7 +746,14 @@ impl TokenVoterTest { .amount_deposited_native } - pub fn vault_address(&self, address: Pubkey, mint: &MintCookie) -> Pubkey { - spl_associated_token_account::get_associated_token_address(&address, &&mint.address) + #[allow(dead_code)] + pub async fn token_balance(&self, token_account: &Pubkey) -> u64 { + let token_account_data = self.bench.get_account(token_account).await.unwrap(); + let account_info: spl_token::state::Account = + spl_token::state::Account::unpack_from_slice(token_account_data.data.as_slice()).unwrap(); + account_info.amount + } + pub fn associated_token_address(&self, address: Pubkey, mint: &MintCookie, token_program_id: &Pubkey,) -> Pubkey { + spl_associated_token_account::get_associated_token_address_with_program_id(&address, &&mint.address, token_program_id) } } diff --git a/programs/token-voter/tests/withdraw.rs b/programs/token-voter/tests/withdraw.rs index a911a449..7fdee8a2 100644 --- a/programs/token-voter/tests/withdraw.rs +++ b/programs/token-voter/tests/withdraw.rs @@ -54,6 +54,11 @@ async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { ) .await?; + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie, &spl_token_2022::id()).await; + + assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, first_vault_balance); + assert_eq!(first_vault_balance, amount_deposited); token_voter_test.bench.advance_clock().await; @@ -78,6 +83,9 @@ async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, 0); assert_eq!(voter_data.deposits.len(), 1); + let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie, &spl_token_2022::id()).await; + assert_eq!(first_vault_balance, 0); + Ok(()) } @@ -226,474 +234,93 @@ async fn test_withdraw_fail_to_withdraw_in_same_slot() -> Result<(), TransportEr Ok(()) } -// #[tokio::test] -// async fn test_configure_voter_weights_multi_deposit() -> Result<(), TransportError> { -// // Arrange -// let mut token_voter_test = TokenVoterTest::start_new().await; - -// let realm_cookie = token_voter_test.governance.with_realm().await?; - -// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; -// let governance_program_cookie = token_voter_test.with_governance_program(None).await; - -// let mut users_iter = token_voter_test.users.iter(); -// let first_user_cookie = users_iter.next().unwrap(); - -// let mut mint_iter = token_voter_test.mints.iter(); -// let first_mint_cookie = mint_iter.next().unwrap(); -// let second_mint_cookie = mint_iter.next().unwrap(); - - - -// let voter_cookie = token_voter_test -// .with_voter(®istrar_cookie, &first_user_cookie) -// .await?; - -// let max_voter_weight_record_cookie = token_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// let _voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &first_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let _second_voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &second_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let token_owner_record_cookie = token_voter_test -// .governance -// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; - -// let amount_deposited = 3_u64; -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// ) -// .await?; - -// token_voter_test.bench.advance_clock().await; - -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// ) -// .await?; -// token_voter_test.bench.advance_clock().await; - -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// ) -// .await?; - -// // Assert -// let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; - -// assert_eq!(voter_data.registrar, registrar_cookie.address); -// let mut deposit_entries = voter_data.deposits.iter(); -// let first_deposit_entry = deposit_entries.next().unwrap(); -// assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited * 3); -// assert_eq!(voter_data.deposits.len(), 1); - -// let registrar = token_voter_test -// .get_registrar_account(®istrar_cookie.address) -// .await; - -// assert_eq!(registrar.voting_mint_configs.len(), 2); -// assert_eq!( -// registrar.voting_mint_configs.first().unwrap().mint, -// first_mint_cookie.address -// ); - -// let max_voter_weight_record = token_voter_test -// .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) -// .await; - -// // supply is 100 * 2 -// assert_eq!(max_voter_weight_record.max_voter_weight, 200); - -// assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); -// assert_eq!(max_voter_weight_record.realm, realm_cookie.address); -// assert_eq!( -// max_voter_weight_record.governing_token_mint, -// realm_cookie.account.community_mint -// ); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_configure_voter_weights_multi_token() -> Result<(), TransportError> { -// // Arrange -// let mut token_voter_test = TokenVoterTest::start_new().await; - -// let realm_cookie = token_voter_test.governance.with_realm().await?; - -// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; -// let governance_program_cookie = token_voter_test.with_governance_program(None).await; - -// let mut users_iter = token_voter_test.users.iter(); -// let first_user_cookie = users_iter.next().unwrap(); - -// let mut mint_iter = token_voter_test.mints.iter(); -// let first_mint_cookie = mint_iter.next().unwrap(); -// let second_mint_cookie = mint_iter.next().unwrap(); - - - -// let voter_cookie = token_voter_test -// .with_voter(®istrar_cookie, &first_user_cookie) -// .await?; - -// let max_voter_weight_record_cookie = token_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// let _voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &first_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let _second_voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &second_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let token_owner_record_cookie = token_voter_test -// .governance -// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; - -// let amount_deposited = 10_u64; -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// ) -// .await?; - -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &second_mint_cookie, -// &spl_token::id(), -// 1, -// amount_deposited, -// ) -// .await?; - -// // Assert -// let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; - -// assert_eq!(voter_data.registrar, registrar_cookie.address); - -// let mut deposit_entries = voter_data.deposits.iter(); -// let first_deposit_entry = deposit_entries.next().unwrap(); -// let second_deposit_entry = deposit_entries.next().unwrap(); -// assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited); -// assert_eq!(second_deposit_entry.amount_deposited_native, amount_deposited); -// assert_eq!(voter_data.deposits.len(), 2); - -// let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie).await; -// assert_eq!(first_vault_balance, amount_deposited); -// let second_vault_balance = token_voter_test.vault_balance(&voter_cookie, &second_mint_cookie).await; -// assert_eq!(second_vault_balance, amount_deposited); - - -// let registrar = token_voter_test -// .get_registrar_account(®istrar_cookie.address) -// .await; - -// assert_eq!(registrar.voting_mint_configs.len(), 2); -// assert_eq!( -// registrar.voting_mint_configs.first().unwrap().mint, -// first_mint_cookie.address -// ); - -// let max_voter_weight_record = token_voter_test -// .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) -// .await; - -// // supply is 100 * 2 -// assert_eq!(max_voter_weight_record.max_voter_weight, 200); - -// assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); -// assert_eq!(max_voter_weight_record.realm, realm_cookie.address); -// assert_eq!( -// max_voter_weight_record.governing_token_mint, -// realm_cookie.account.community_mint -// ); - -// Ok(()) -// } - -// #[tokio::test] -// async fn test_configure_voter_weights_invalid_deposit_entry_index() -> Result<(), TransportError> { -// // Arrange -// let mut token_voter_test = TokenVoterTest::start_new().await; - -// let realm_cookie = token_voter_test.governance.with_realm().await?; - -// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; -// let governance_program_cookie = token_voter_test.with_governance_program(None).await; - -// let mut users_iter = token_voter_test.users.iter(); -// let first_user_cookie = users_iter.next().unwrap(); - -// let mut mint_iter = token_voter_test.mints.iter(); -// let first_mint_cookie = mint_iter.next().unwrap(); -// let second_mint_cookie = mint_iter.next().unwrap(); - - - -// let voter_cookie = token_voter_test -// .with_voter(®istrar_cookie, &first_user_cookie) -// .await?; - -// let max_voter_weight_record_cookie = token_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// let _voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &first_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let _second_voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &second_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let token_owner_record_cookie = token_voter_test -// .governance -// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; - -// let amount_deposited = 5_u64; -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// ) -// .await?; - -// let err = token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 2, -// amount_deposited, -// ) -// .await -// .err() -// .unwrap(); - -// // Deposit entry entered out of bounds -// assert_token_voter_err(err, TokenVoterError::OutOfBoundsDepositEntryIndex); - -// Ok(()) -// } - - -// #[tokio::test] -// async fn test_configure_voter_weights_insufficient_funds() -> Result<(), TransportError> { -// // Arrange -// let mut token_voter_test = TokenVoterTest::start_new().await; - -// let realm_cookie = token_voter_test.governance.with_realm().await?; - -// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; -// let governance_program_cookie = token_voter_test.with_governance_program(None).await; - -// let mut users_iter = token_voter_test.users.iter(); -// let first_user_cookie = users_iter.next().unwrap(); - -// let mut mint_iter = token_voter_test.mints.iter(); -// let first_mint_cookie = mint_iter.next().unwrap(); +#[tokio::test] +async fn test_withdraw_multi_deposit_and_withdraw() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + let realm_cookie = token_voter_test.governance.with_realm().await?; -// let voter_cookie = token_voter_test -// .with_voter(®istrar_cookie, &first_user_cookie) -// .await?; + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; -// let max_voter_weight_record_cookie = token_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie = token_voter_test.mints.first().unwrap(); -// let _voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &first_mint_cookie, -// 0, // no digit shift -// ) -// .await?; + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; -// let token_owner_record_cookie = token_voter_test -// .governance -// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; -// let amount_deposited = 20; + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; -// let err = token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// ) -// .await -// .err() -// .unwrap(); + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + let amount_deposited = 5_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; -// // Insufficient funds it throws Custom(1) error -// assert_ix_err(err, InstructionError::Custom(1)); + token_voter_test.bench.advance_clock().await; -// Ok(()) -// } + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + ) + .await?; -// #[tokio::test] -// async fn test_configure_voter_weights_with_invalid_registrar_error() -> Result<(), TransportError> { -// // Arrange -// let mut token_voter_test = TokenVoterTest::start_new().await; -// let realm_cookie = token_voter_test.governance.with_realm().await?; + token_voter_test.bench.advance_clock().await; -// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited * 2, + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; -// let second_realm_cookie = token_voter_test.governance.with_realm().await?; + assert_eq!(voter_data.registrar, registrar_cookie.address); + println!("{:?}", voter_data); + assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, 0); + assert_eq!(voter_data.deposits.len(), 1); -// let second_registrar_cookie = token_voter_test.with_registrar(&second_realm_cookie).await?; -// let governance_program_cookie = token_voter_test.with_governance_program(None).await; - -// let mut users_iter = token_voter_test.users.iter(); -// let first_user_cookie = users_iter.next().unwrap(); - -// let mut mint_iter = token_voter_test.mints.iter(); -// let first_mint_cookie = mint_iter.next().unwrap(); - - - -// let voter_cookie = token_voter_test -// .with_voter(®istrar_cookie, &first_user_cookie) -// .await?; - -// let max_voter_weight_record_cookie = token_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; - -// let _voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// &first_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let token_owner_record_cookie = token_voter_test -// .governance -// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; - -// let amount_deposited = 20; - -// let err = token_voter_test -// .deposit_entry( -// &second_registrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// ) -// .await -// .err() -// .unwrap(); - -// // Assert - -// // PDA doesn't match and hence the error is ConstraintSeeds -// assert_anchor_err(err, ErrorCode::ConstraintSeeds); - -// Ok(()) -// } \ No newline at end of file + Ok(()) +} \ No newline at end of file From 05c23f9ec9831e65b052f37cf90d4039e2f5e5f9 Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sun, 19 May 2024 12:18:27 +0400 Subject: [PATCH 05/11] add token-voter to localnet --- Anchor.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Anchor.toml b/Anchor.toml index 61c3ebf2..4e303a40 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -11,6 +11,7 @@ anchor_version = "0.30.0" nft_voter = "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw" gateway = "GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk" solana-gateway-program = "gatem74V238djXdzWnJf94Wo1DcnuGkfijbf3AuBhfs" +token_voter = "3JhBg9bSPcfWGFa3t8LH7ooVtrjm45yCkHpxYXMXstUM" [registry] url = "https://anchor.projectserum.com" From a469b8b9aa5efd3e36fbfc370d9e74b1756c4c0d Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sun, 19 May 2024 13:37:53 +0400 Subject: [PATCH 06/11] add resize ixn --- Cargo.lock | 323 ++++++++++++++++-- .../src/instructions/configure_mint_config.rs | 17 +- programs/token-voter/src/instructions/mod.rs | 3 + .../src/instructions/resize_registrar.rs | 86 +++++ programs/token-voter/src/lib.rs | 5 + .../src/state/voting_mint_config.rs | 13 +- 6 files changed, 396 insertions(+), 51 deletions(-) create mode 100644 programs/token-voter/src/instructions/resize_registrar.rs diff --git a/Cargo.lock b/Cargo.lock index 39696bf7..c5e481b2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -117,38 +117,90 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "anchor-attribute-access-control" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" +dependencies = [ + "anchor-syn 0.26.0", + "anyhow", + "proc-macro2", + "quote", + "regex", + "syn 1.0.109", +] + [[package]] name = "anchor-attribute-access-control" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd7368e171b3a317885dc08ec0f74eed9d0ad6c726cc819593aed81440dca926" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "anchor-attribute-account" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3bcd731f21048a032be27c7791701120e44f3f6371358fc4261a7f716283d29" +dependencies = [ + "anchor-syn 0.26.0", + "anyhow", + "bs58 0.4.0", + "proc-macro2", + "quote", + "rustversion", + "syn 1.0.109", +] + [[package]] name = "anchor-attribute-account" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f527df85a8cba3f2bea04e46ed71b66e525ea378c7fec538aa205f4520b73e31" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", "bs58 0.5.1", "proc-macro2", "quote", "syn 1.0.109", ] +[[package]] +name = "anchor-attribute-constant" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" +dependencies = [ + "anchor-syn 0.26.0", + "proc-macro2", + "syn 1.0.109", +] + [[package]] name = "anchor-attribute-constant" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb1dc1845cf8636c2e046a274ca074dabd3884ac8ed11cc4ed64b7e8ef5a318" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" +dependencies = [ + "anchor-syn 0.26.0", + "proc-macro2", "quote", "syn 1.0.109", ] @@ -159,7 +211,20 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f382e41514c59a77ffa7bb1a47df9a0359564a749b6934485c742c11962e540" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" +dependencies = [ + "anchor-syn 0.26.0", + "anyhow", + "proc-macro2", "quote", "syn 1.0.109", ] @@ -170,7 +235,34 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "473a122aeed3f6b666438236338d2ef7833ee5fdc5688e1baa80185d61088a53" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-interface" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6700a6f5c888a9c33fe8afc0c64fd8575fa28d05446037306d0f96102ae4480" +dependencies = [ + "anchor-syn 0.26.0", + "anyhow", + "heck 0.3.3", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-program" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" +dependencies = [ + "anchor-syn 0.26.0", + "anyhow", "proc-macro2", "quote", "syn 1.0.109", @@ -183,7 +275,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f88c7ffe2eb40aeac43ffd0d74a6671581158aedfaa0552330a2ef92fa5c889" dependencies = [ "anchor-lang-idl", - "anchor-syn", + "anchor-syn 0.30.0", "anyhow", "bs58 0.5.1", "heck 0.3.3", @@ -193,13 +285,39 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "anchor-attribute-state" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" +dependencies = [ + "anchor-syn 0.26.0", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" +dependencies = [ + "anchor-syn 0.26.0", + "anyhow", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "anchor-derive-accounts" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed9b97c99dcec135aae0ff908c14bcfcd3e78cfc16a0c6f245135038f0e6d390" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", "quote", "syn 1.0.109", ] @@ -210,7 +328,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbece98f6ad9c37070edc0841326c9623a249346cd74f433e7cef69b14f7f31d" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", "borsh-derive-internal 0.10.3", "proc-macro2", "quote", @@ -228,19 +346,43 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "anchor-lang" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "662ceafe667448ee4199a4be2ee83b6bb76da28566eee5cea05f96ab38255af8" +dependencies = [ + "anchor-attribute-access-control 0.26.0", + "anchor-attribute-account 0.26.0", + "anchor-attribute-constant 0.26.0", + "anchor-attribute-error 0.26.0", + "anchor-attribute-event 0.26.0", + "anchor-attribute-interface", + "anchor-attribute-program 0.26.0", + "anchor-attribute-state", + "anchor-derive-accounts 0.26.0", + "arrayref", + "base64 0.13.1", + "bincode", + "borsh 0.9.3", + "bytemuck", + "solana-program", + "thiserror", +] + [[package]] name = "anchor-lang" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e41feb9c1cd9f4b0fad1c004fc8f289183f3ce27e9db38fa6e434470c716fb1e" dependencies = [ - "anchor-attribute-access-control", - "anchor-attribute-account", - "anchor-attribute-constant", - "anchor-attribute-error", - "anchor-attribute-event", - "anchor-attribute-program", - "anchor-derive-accounts", + "anchor-attribute-access-control 0.30.0", + "anchor-attribute-account 0.30.0", + "anchor-attribute-constant 0.30.0", + "anchor-attribute-error 0.30.0", + "anchor-attribute-event 0.30.0", + "anchor-attribute-program 0.30.0", + "anchor-derive-accounts 0.30.0", "anchor-derive-serde", "anchor-derive-space", "anchor-lang-idl", @@ -260,20 +402,32 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b29da81eae478b1bb846749b06b8a2cb9c6f9ed26ca793b0c916793fdf36adab" dependencies = [ - "anchor-syn", + "anchor-syn 0.30.0", "anyhow", "regex", "serde", "serde_json", ] +[[package]] +name = "anchor-spl" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f32390ce8356f54c0f0245ea156f8190717e37285b8bf4f406a613dc4b954cde" +dependencies = [ + "anchor-lang 0.26.0", + "solana-program", + "spl-associated-token-account 1.1.3", + "spl-token 3.5.0", +] + [[package]] name = "anchor-spl" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dcee54a30b27ea8317ca647759b5d9701a8c7caaaa0c922c6d3c306a7278a7a" dependencies = [ - "anchor-lang", + "anchor-lang 0.30.0", "spl-associated-token-account 3.0.2", "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "spl-token 4.0.0", @@ -282,6 +436,25 @@ dependencies = [ "spl-token-metadata-interface 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "anchor-syn" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0418bcb5daac3b8cb1b60d8fdb1d468ca36f5509f31fb51179326fae1028fdcc" +dependencies = [ + "anyhow", + "bs58 0.3.1", + "heck 0.3.3", + "proc-macro2", + "proc-macro2-diagnostics", + "quote", + "serde", + "serde_json", + "sha2 0.9.9", + "syn 1.0.109", + "thiserror", +] + [[package]] name = "anchor-syn" version = "0.30.0" @@ -833,6 +1006,12 @@ dependencies = [ "alloc-stdlib", ] +[[package]] +name = "bs58" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" + [[package]] name = "bs58" version = "0.4.0" @@ -1804,8 +1983,8 @@ dependencies = [ name = "gpl-civic-gateway" version = "0.2.0" dependencies = [ - "anchor-lang", - "anchor-spl", + "anchor-lang 0.30.0", + "anchor-spl 0.30.0", "arrayref", "borsh 0.10.3", "enum_dispatch", @@ -1828,8 +2007,8 @@ dependencies = [ name = "gpl-nft-voter" version = "0.3.0" dependencies = [ - "anchor-lang", - "anchor-spl", + "anchor-lang 0.30.0", + "anchor-spl 0.30.0", "arrayref", "borsh 0.10.3", "itertools", @@ -1846,8 +2025,8 @@ dependencies = [ name = "gpl-realm-voter" version = "0.0.1" dependencies = [ - "anchor-lang", - "anchor-spl", + "anchor-lang 0.30.0", + "anchor-spl 0.30.0", "arrayref", "borsh 0.10.3", "solana-program", @@ -1862,16 +2041,16 @@ dependencies = [ name = "gpl-token-haver" version = "0.0.1" dependencies = [ - "anchor-lang", - "anchor-spl", + "anchor-lang 0.26.0", + "anchor-spl 0.26.0", "arrayref", - "borsh", + "borsh 0.9.3", "solana-program", "solana-program-test", "solana-sdk", - "spl-governance", - "spl-governance-tools", - "spl-token", + "spl-governance 3.1.1", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 3.5.0", ] [[package]] @@ -3128,6 +3307,19 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "proc-macro2-diagnostics" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", + "version_check", + "yansi", +] + [[package]] name = "qstring" version = "0.7.2" @@ -5098,6 +5290,22 @@ dependencies = [ "der", ] +[[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 0.3.3", + "num-traits", + "solana-program", + "spl-token 3.5.0", + "spl-token-2022 0.6.1", + "thiserror", +] + [[package]] name = "spl-associated-token-account" version = "2.3.0" @@ -5232,6 +5440,26 @@ dependencies = [ "thiserror", ] +[[package]] +name = "spl-governance" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7a42340af2f3334ee1ee718e6d68b939c98cab4ceb381429f952c72d68e1ebf" +dependencies = [ + "arrayref", + "bincode", + "borsh 0.9.3", + "num-derive 0.3.3", + "num-traits", + "serde", + "serde_derive", + "solana-program", + "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 3.5.0", + "thiserror", +] + [[package]] name = "spl-governance" version = "4.0.0" @@ -5350,6 +5578,15 @@ dependencies = [ "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-memo" version = "4.0.0" @@ -5563,6 +5800,24 @@ dependencies = [ "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 0.3.3", + "num-traits", + "num_enum 0.5.11", + "solana-program", + "solana-zk-token-sdk", + "spl-memo 3.0.1", + "spl-token 3.5.0", + "thiserror", +] + [[package]] name = "spl-token-2022" version = "1.0.0" @@ -6183,8 +6438,8 @@ name = "token-voter" version = "0.1.0" dependencies = [ "ahash 0.8.7", - "anchor-lang", - "anchor-spl", + "anchor-lang 0.30.0", + "anchor-spl 0.30.0", "arrayref", "borsh 0.10.3", "env_logger", @@ -6959,6 +7214,12 @@ dependencies = [ "rustix", ] +[[package]] +name = "yansi" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" + [[package]] name = "yasna" version = "0.5.2" diff --git a/programs/token-voter/src/instructions/configure_mint_config.rs b/programs/token-voter/src/instructions/configure_mint_config.rs index e13e51b1..4e8428fe 100644 --- a/programs/token-voter/src/instructions/configure_mint_config.rs +++ b/programs/token-voter/src/instructions/configure_mint_config.rs @@ -64,7 +64,7 @@ pub fn configure_mint_config( ); let token_supply = mint.supply; - let supply_with_digit_shift = digit_shift_native(digit_shift, token_supply)?; + let supply_with_digit_shift = VotingMintConfig::compute_digit_shift_native(digit_shift, token_supply)?; let voting_mint_config = VotingMintConfig { mint: mint.key(), digit_shift, @@ -94,18 +94,3 @@ pub fn configure_mint_config( Ok(()) } - -/// Converts an amount in this voting mints's native currency -/// to the base vote weight -/// by applying the digit_shift factor. -pub fn digit_shift_native(digit_shift: i8, amount_native: u64) -> Result { - let compute = || -> Option { - let val = if digit_shift < 0 { - (amount_native as u128).checked_div(10u128.pow((-digit_shift) as u32))? - } else { - (amount_native as u128).checked_mul(10u128.pow(digit_shift as u32))? - }; - u64::try_from(val).ok() - }; - compute().ok_or_else(|| error!(TokenVoterError::VoterWeightOverflow)) -} diff --git a/programs/token-voter/src/instructions/mod.rs b/programs/token-voter/src/instructions/mod.rs index e5766ab3..0a2c0c7a 100644 --- a/programs/token-voter/src/instructions/mod.rs +++ b/programs/token-voter/src/instructions/mod.rs @@ -4,6 +4,9 @@ mod configure_mint_config; pub use create_registrar::*; mod create_registrar; +pub use resize_registrar::*; +mod resize_registrar; + pub use create_voter_weight_record::*; mod create_voter_weight_record; diff --git a/programs/token-voter/src/instructions/resize_registrar.rs b/programs/token-voter/src/instructions/resize_registrar.rs new file mode 100644 index 00000000..b03cb862 --- /dev/null +++ b/programs/token-voter/src/instructions/resize_registrar.rs @@ -0,0 +1,86 @@ +use { + crate::{error::*, state::*}, + anchor_lang::prelude::*, + anchor_spl::token_interface::Mint, + spl_governance::state::realm, +}; + +/// Resizes Registrar storing Realm Voter configuration for spl-governance Realm +/// This instruction can only be ran if the max_mint is higher than currently used voting_mint_configs length +#[derive(Accounts)] +#[instruction(max_mints: u8)] +pub struct ResizeRegistrar<'info> { + /// The Realm Voter Registrar + /// There can only be a single registrar per governance Realm and governing mint of the Realm + #[account( + mut, + seeds = [b"registrar".as_ref(), realm.key().as_ref(), governing_token_mint.key().as_ref()], + bump, + realloc = Registrar::get_space(max_mints), + realloc::payer = payer, + realloc::zero = false, + )] + pub registrar: Account<'info, Registrar>, + + /// The program id of the spl-governance program the realm belongs to + /// CHECK: Can be any instance of spl-governance and it's not known at the compilation time + #[account(executable)] + pub governance_program_id: UncheckedAccount<'info>, + + /// An spl-governance Realm + /// + /// Realm is validated in the instruction: + /// - Realm is owned by the governance_program_id + /// - governing_token_mint must be the community or council mint + /// - realm_authority is realm.authority + /// CHECK: Owned by spl-governance instance specified in governance_program_id + #[account(owner = governance_program_id.key())] + pub realm: UncheckedAccount<'info>, + + /// Either the realm community mint or the council mint. + /// It must match Realm.community_mint or Realm.config.council_mint + /// + /// Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity + /// for the voting population and the tokens of that are no longer used + pub governing_token_mint: InterfaceAccount<'info, Mint>, + + /// realm_authority must sign and match Realm.authority + pub realm_authority: Signer<'info>, + + #[account(mut)] + pub payer: Signer<'info>, + + pub system_program: Program<'info, System>, +} + +/// Resizes a Registrar which stores Realms voter configuration for the given Realm +/// +/// max_mints is used to allocate account size for the maximum number of configured mint instances +pub fn resize_registrar(ctx: Context, max_mints: u8) -> Result<()> { + let registrar = &mut ctx.accounts.registrar; + + require_gt!( + max_mints as usize, + registrar.voting_mint_configs.len(), + TokenVoterError::InvalidRealmAuthority + ); + + registrar.max_mints = max_mints; + + // Verify that realm_authority is the expected authority of the Realm + // and that the mint matches one of the realm mints too + let realm = realm::get_realm_data_for_governing_token_mint( + ®istrar.governance_program_id, + &ctx.accounts.realm, + ®istrar.governing_token_mint, + )?; + + require_eq!( + realm.authority.unwrap(), + ctx.accounts.realm_authority.key(), + TokenVoterError::InvalidRealmAuthority + ); + + + Ok(()) +} diff --git a/programs/token-voter/src/lib.rs b/programs/token-voter/src/lib.rs index a589a5e2..eda0da3a 100644 --- a/programs/token-voter/src/lib.rs +++ b/programs/token-voter/src/lib.rs @@ -25,6 +25,11 @@ pub mod token_voter { instructions::create_registrar(ctx, max_mints) } + pub fn resize_registrar(ctx: Context, max_mints: u8) -> Result<()> { + log_version(); + instructions::resize_registrar(ctx, max_mints) + } + pub fn create_voter_weight_record(ctx: Context) -> Result<()> { log_version(); instructions::create_voter_weight_record(ctx) diff --git a/programs/token-voter/src/state/voting_mint_config.rs b/programs/token-voter/src/state/voting_mint_config.rs index 31e4787b..8751e543 100644 --- a/programs/token-voter/src/state/voting_mint_config.rs +++ b/programs/token-voter/src/state/voting_mint_config.rs @@ -24,18 +24,23 @@ impl VotingMintConfig { /// Converts an amount in this voting mints's native currency /// to the base vote weight /// by applying the digit_shift factor. - pub fn digit_shift_native(&self, amount_native: u64) -> Result { + pub fn compute_digit_shift_native(digit_shift: i8, amount_native: u64) -> Result { let compute = || -> Option { - let val = if self.digit_shift < 0 { - (amount_native as u128).checked_div(10u128.pow((-self.digit_shift) as u32))? + let val = if digit_shift < 0 { + (amount_native as u128).checked_div(10u128.pow((-digit_shift) as u32))? } else { - (amount_native as u128).checked_mul(10u128.pow(self.digit_shift as u32))? + (amount_native as u128).checked_mul(10u128.pow(digit_shift as u32))? }; u64::try_from(val).ok() }; compute().ok_or_else(|| error!(TokenVoterError::VoterWeightOverflow)) } + /// Same function as above but with self + pub fn digit_shift_native(&self, amount_native: u64) -> Result { + Self::compute_digit_shift_native(self.digit_shift, amount_native) + } + /// Whether this voting mint is configured. pub fn in_use(&self) -> bool { self.mint != Pubkey::default() From 776580c67efe10a15bd6e6de6bf754b2db5927d3 Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Mon, 20 May 2024 10:19:00 +0400 Subject: [PATCH 07/11] add transfer_hook enabled tests --- Cargo.lock | 2 + programs/token-voter/Cargo.toml | 5 +- programs/token-voter/tests/close_voter.rs | 6 +- .../tests/configure_voter_weights.rs | 4 +- .../tests/create_max_voter_weight_record.rs | 3 +- .../token-voter/tests/create_registrar.rs | 2 +- programs/token-voter/tests/deposit.rs | 282 +++++++++++++++--- .../fixtures/spl_transfer_hook_example.so | Bin 0 -> 116048 bytes .../tests/program_test/governance_test.rs | 164 +++++++++- .../tests/program_test/program_test_bench.rs | 215 ++++++++++++- .../tests/program_test/token_voter_test.rs | 64 +++- programs/token-voter/tests/withdraw.rs | 264 ++++++++++++++-- 12 files changed, 905 insertions(+), 106 deletions(-) create mode 100755 programs/token-voter/tests/fixtures/spl_transfer_hook_example.so diff --git a/Cargo.lock b/Cargo.lock index c5e481b2..b12bce33 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -6451,9 +6451,11 @@ dependencies = [ "spl-governance 4.0.0 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-tlv-account-resolution 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "spl-token 3.5.0", "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", "spl-token-client", + "spl-transfer-hook-example", "spl-transfer-hook-interface 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", "static_assertions", ] diff --git a/programs/token-voter/Cargo.toml b/programs/token-voter/Cargo.toml index 096e19ad..d94f22d8 100644 --- a/programs/token-voter/Cargo.toml +++ b/programs/token-voter/Cargo.toml @@ -22,11 +22,14 @@ anchor-spl = "0.30.0" arrayref = "0.3.7" solana-program = "1.18.12" # spl-governance = { version = "4.0.0", features = ["no-entrypoint"] } +# spl-transfer-hook-interface = { version = "0.6.3" } spl-governance = { git = "https://github.com/crypt0miester/solana-program-library.git", branch = "gib-bounty-jlFb5", default-features = false, features = ["no-entrypoint"] } +spl-transfer-hook-example = { git = "https://github.com/crypt0miester/solana-program-library.git", branch = "gib-bounty-jlFb5", default-features = false, features = ["no-entrypoint"] } +spl-tlv-account-resolution = { version = "0.6.3" } +spl-transfer-hook-interface = { version = "0.6.3" } spl-governance-tools = "0.1.4" spl-token = { version = "3.5", features = [ "no-entrypoint" ] } spl-token-2022 = { version = "3.0.2", features = [ "no-entrypoint" ] } -spl-transfer-hook-interface = { version = "0.6.3" } ahash = "=0.8.7" static_assertions = "1.1" spl-governance-addin-api = "0.1.4" diff --git a/programs/token-voter/tests/close_voter.rs b/programs/token-voter/tests/close_voter.rs index e607a69a..68856252 100644 --- a/programs/token-voter/tests/close_voter.rs +++ b/programs/token-voter/tests/close_voter.rs @@ -11,7 +11,7 @@ mod program_test; #[tokio::test] async fn test_close_with_token_extensions() -> Result<(), TransportError> { // Arrange - let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; let realm_cookie = token_voter_test .governance @@ -72,6 +72,7 @@ async fn test_close_with_token_extensions() -> Result<(), TransportError> { &spl_token_2022::id(), 0, amount_deposited, + None ) .await?; @@ -87,6 +88,7 @@ async fn test_close_with_token_extensions() -> Result<(), TransportError> { &spl_token_2022::id(), 1, amount_deposited, + None ) .await?; @@ -115,6 +117,7 @@ async fn test_close_with_token_extensions() -> Result<(), TransportError> { &spl_token_2022::id(), 0, amount_deposited, + None ) .await?; @@ -143,6 +146,7 @@ async fn test_close_with_token_extensions() -> Result<(), TransportError> { &spl_token_2022::id(), 1, amount_deposited, + None ) .await?; token_voter_test.bench.advance_clock().await; diff --git a/programs/token-voter/tests/configure_voter_weights.rs b/programs/token-voter/tests/configure_voter_weights.rs index a1092749..59b9df2f 100644 --- a/programs/token-voter/tests/configure_voter_weights.rs +++ b/programs/token-voter/tests/configure_voter_weights.rs @@ -9,8 +9,8 @@ mod program_test; #[tokio::test] async fn test_configure_voter_weights_with_token_extensions() -> Result<(), TransportError> { // Arrange - let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; - + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; + let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/create_max_voter_weight_record.rs b/programs/token-voter/tests/create_max_voter_weight_record.rs index 87d3c533..8081cc79 100644 --- a/programs/token-voter/tests/create_max_voter_weight_record.rs +++ b/programs/token-voter/tests/create_max_voter_weight_record.rs @@ -9,8 +9,7 @@ mod program_test; #[tokio::test] async fn test_create_max_voter_weight_record_with_token_extensions() -> Result<(), TransportError> { // Arrange - let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; - + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/create_registrar.rs b/programs/token-voter/tests/create_registrar.rs index 820f80a4..c4c5a171 100644 --- a/programs/token-voter/tests/create_registrar.rs +++ b/programs/token-voter/tests/create_registrar.rs @@ -13,7 +13,7 @@ use program_test::tools::{assert_anchor_err, assert_ix_err, assert_token_voter_e #[tokio::test] async fn test_create_registrar_with_token_extensions() -> Result<(), TransportError> { // Arrange - let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; diff --git a/programs/token-voter/tests/deposit.rs b/programs/token-voter/tests/deposit.rs index a4ef8012..b1cdbd2a 100644 --- a/programs/token-voter/tests/deposit.rs +++ b/programs/token-voter/tests/deposit.rs @@ -1,21 +1,25 @@ +use crate::program_test::program_test_bench::MintType; use anchor_lang::error::ErrorCode; +use anchor_spl::associated_token; use program_test::token_voter_test::TokenVoterTest; use program_test::tools::*; use solana_program_test::*; use solana_sdk::instruction::InstructionError; +use solana_sdk::pubkey::Pubkey; use solana_sdk::signer::Signer; use solana_sdk::transport::TransportError; use token_voter::error::TokenVoterError; -use crate::program_test::program_test_bench::MintType; mod program_test; - #[tokio::test] async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> { // Arrange - let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + let realm_cookie = token_voter_test + .governance + .with_realm_token_extension() + .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; @@ -43,7 +47,8 @@ async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 10_u64; token_voter_test .deposit_entry( @@ -55,6 +60,7 @@ async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> &spl_token_2022::id(), 0, amount_deposited, + None, ) .await?; @@ -63,7 +69,10 @@ async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> assert_eq!(voter_data.registrar, registrar_cookie.address); // println!("{:?}", voter_data); - assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, amount_deposited); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + amount_deposited + ); assert_eq!(voter_data.deposits.len(), 1); let registrar = token_voter_test @@ -93,19 +102,169 @@ async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> Ok(()) } +#[tokio::test] +async fn test_deposit_entry_with_token_extension_transfer_hooks() -> Result<(), TransportError> { + // Arrange + let transfer_hook_program_id = Pubkey::new_unique(); + let mut token_voter_test = + TokenVoterTest::start_new_token_extensions(Some(&transfer_hook_program_id)).await; + + let realm_cookie = token_voter_test + .governance + .with_realm_token_extension() + .await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie_transfer_hook = token_voter_test + .bench + .with_mint( + &MintType::SplTokenExtensionsWithTransferHook, + Some(&transfer_hook_program_id), + ) + .await + .unwrap(); + let _first_user_cookie_token_account = token_voter_test + .bench + .with_tokens( + &first_mint_cookie_transfer_hook, + &first_user_cookie.key.pubkey(), + 100, + &MintType::SplTokenExtensionsWithTransferHook, + ) + .await; + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie_transfer_hook, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; + + let amount_deposited = 10_u64; + let vault = associated_token::get_associated_token_address_with_program_id( + &voter_cookie.address, + &first_mint_cookie_transfer_hook.address, + &spl_token_2022::id(), + ); + let deposit_token = associated_token::get_associated_token_address_with_program_id( + &first_user_cookie.key.pubkey(), + &first_mint_cookie_transfer_hook.address, + &spl_token_2022::id(), + ); + token_voter_test.bench.advance_clock().await; + let additional_account_metas = token_voter_test + .bench + .initialize_transfer_hook_account_metas( + &first_mint_cookie_transfer_hook.address, + &first_mint_cookie_transfer_hook.mint_authority, + &first_user_cookie.key, + &transfer_hook_program_id, + &deposit_token, + &vault, + &Pubkey::new_unique(), + amount_deposited, + ) + .await; + token_voter_test.bench.advance_clock().await; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie_transfer_hook, + &spl_token_2022::id(), + 0, + amount_deposited, + Some(additional_account_metas.to_vec()), + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + // println!("{:?}", voter_data); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + amount_deposited + ); + assert_eq!(voter_data.deposits.len(), 1); + + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.voting_mint_configs.len(), 1); + assert_eq!( + registrar.voting_mint_configs.first().unwrap().mint, + first_mint_cookie_transfer_hook.address + ); + + let max_voter_weight_record = token_voter_test + .get_max_voter_weight_record(&max_voter_weight_record_cookie.address) + .await; + + // supply is 100 + assert_eq!(max_voter_weight_record.max_voter_weight, 100); + + assert_eq!(max_voter_weight_record.max_voter_weight_expiry, None); + assert_eq!(max_voter_weight_record.realm, realm_cookie.address); + assert_eq!( + max_voter_weight_record.governing_token_mint, + realm_cookie.account.community_mint + ); + + Ok(()) +} + #[tokio::test] async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), TransportError> { // Arrange - let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + let realm_cookie = token_voter_test + .governance + .with_realm_token_extension() + .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; let first_user_cookie = token_voter_test.users.first().unwrap(); - let first_mint_cookie_transfer_fees = token_voter_test.bench.with_mint(&MintType::SplTokenExtensionsWithTransferFees, None).await.unwrap(); - let _first_user_cookie_token_account = token_voter_test.bench.with_tokens(&first_mint_cookie_transfer_fees, &first_user_cookie.key.pubkey(), 100, &MintType::SplTokenExtensionsWithTransferFees).await; + let first_mint_cookie_transfer_fees = token_voter_test + .bench + .with_mint(&MintType::SplTokenExtensionsWithTransferFees, None) + .await + .unwrap(); + let _first_user_cookie_token_account = token_voter_test + .bench + .with_tokens( + &first_mint_cookie_transfer_fees, + &first_user_cookie.key.pubkey(), + 100, + &MintType::SplTokenExtensionsWithTransferFees, + ) + .await; let voter_cookie = token_voter_test .with_voter(®istrar_cookie, first_user_cookie) @@ -127,7 +286,8 @@ async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), T let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 100_u64; token_voter_test .deposit_entry( @@ -139,6 +299,7 @@ async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), T &spl_token_2022::id(), 0, amount_deposited, + None, ) .await?; token_voter_test.bench.advance_clock().await; @@ -146,9 +307,18 @@ async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), T // Assert let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; - let vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie_transfer_fees, &spl_token_2022::id()).await; + let vault_balance = token_voter_test + .vault_balance( + &voter_cookie, + &first_mint_cookie_transfer_fees, + &spl_token_2022::id(), + ) + .await; assert_eq!(voter_data.registrar, registrar_cookie.address); - assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, vault_balance); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + vault_balance + ); Ok(()) } @@ -186,7 +356,8 @@ async fn test_deposit_entry() -> Result<(), TransportError> { let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 10_u64; token_voter_test .deposit_entry( @@ -198,6 +369,7 @@ async fn test_deposit_entry() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await?; @@ -206,7 +378,10 @@ async fn test_deposit_entry() -> Result<(), TransportError> { assert_eq!(voter_data.registrar, registrar_cookie.address); // println!("{:?}", voter_data); - assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, amount_deposited); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + amount_deposited + ); assert_eq!(voter_data.deposits.len(), 1); let registrar = token_voter_test @@ -245,7 +420,7 @@ async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; - + let mut users_iter = token_voter_test.users.iter(); let first_user_cookie = users_iter.next().unwrap(); @@ -253,8 +428,6 @@ async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { let first_mint_cookie = mint_iter.next().unwrap(); let second_mint_cookie = mint_iter.next().unwrap(); - - let voter_cookie = token_voter_test .with_voter(®istrar_cookie, &first_user_cookie) .await?; @@ -285,7 +458,8 @@ async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 3_u64; token_voter_test @@ -298,6 +472,7 @@ async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await?; @@ -313,6 +488,7 @@ async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await?; token_voter_test.bench.advance_clock().await; @@ -327,6 +503,7 @@ async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await?; @@ -336,7 +513,10 @@ async fn test_deposit_entry_multi_deposit() -> Result<(), TransportError> { assert_eq!(voter_data.registrar, registrar_cookie.address); let mut deposit_entries = voter_data.deposits.iter(); let first_deposit_entry = deposit_entries.next().unwrap(); - assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited * 3); + assert_eq!( + first_deposit_entry.amount_deposited_native, + amount_deposited * 3 + ); assert_eq!(voter_data.deposits.len(), 1); let registrar = token_voter_test @@ -375,7 +555,7 @@ async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; - + let mut users_iter = token_voter_test.users.iter(); let first_user_cookie = users_iter.next().unwrap(); @@ -383,8 +563,6 @@ async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { let first_mint_cookie = mint_iter.next().unwrap(); let second_mint_cookie = mint_iter.next().unwrap(); - - let voter_cookie = token_voter_test .with_voter(®istrar_cookie, &first_user_cookie) .await?; @@ -415,7 +593,8 @@ async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 10_u64; token_voter_test @@ -428,6 +607,7 @@ async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await?; @@ -441,6 +621,7 @@ async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { &spl_token::id(), 1, amount_deposited, + None, ) .await?; @@ -448,20 +629,29 @@ async fn test_deposit_entry_multi_token() -> Result<(), TransportError> { let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; assert_eq!(voter_data.registrar, registrar_cookie.address); - + let mut deposit_entries = voter_data.deposits.iter(); let first_deposit_entry = deposit_entries.next().unwrap(); let second_deposit_entry = deposit_entries.next().unwrap(); - assert_eq!(first_deposit_entry.amount_deposited_native, amount_deposited); - assert_eq!(second_deposit_entry.amount_deposited_native, amount_deposited); + assert_eq!( + first_deposit_entry.amount_deposited_native, + amount_deposited + ); + assert_eq!( + second_deposit_entry.amount_deposited_native, + amount_deposited + ); assert_eq!(voter_data.deposits.len(), 2); - let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie, &spl_token::id()).await; + let first_vault_balance = token_voter_test + .vault_balance(&voter_cookie, &first_mint_cookie, &spl_token::id()) + .await; assert_eq!(first_vault_balance, amount_deposited); - let second_vault_balance = token_voter_test.vault_balance(&voter_cookie, &second_mint_cookie, &spl_token::id()).await; + let second_vault_balance = token_voter_test + .vault_balance(&voter_cookie, &second_mint_cookie, &spl_token::id()) + .await; assert_eq!(second_vault_balance, amount_deposited); - let registrar = token_voter_test .get_registrar_account(®istrar_cookie.address) .await; @@ -498,7 +688,7 @@ async fn test_deposit_entry_invalid_deposit_entry_index() -> Result<(), Transpor let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; - + let mut users_iter = token_voter_test.users.iter(); let first_user_cookie = users_iter.next().unwrap(); @@ -506,8 +696,6 @@ async fn test_deposit_entry_invalid_deposit_entry_index() -> Result<(), Transpor let first_mint_cookie = mint_iter.next().unwrap(); let second_mint_cookie = mint_iter.next().unwrap(); - - let voter_cookie = token_voter_test .with_voter(®istrar_cookie, &first_user_cookie) .await?; @@ -538,7 +726,8 @@ async fn test_deposit_entry_invalid_deposit_entry_index() -> Result<(), Transpor let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 5_u64; token_voter_test @@ -551,6 +740,7 @@ async fn test_deposit_entry_invalid_deposit_entry_index() -> Result<(), Transpor &spl_token::id(), 0, amount_deposited, + None, ) .await?; @@ -564,6 +754,7 @@ async fn test_deposit_entry_invalid_deposit_entry_index() -> Result<(), Transpor &spl_token::id(), 2, amount_deposited, + None, ) .await .err() @@ -575,7 +766,6 @@ async fn test_deposit_entry_invalid_deposit_entry_index() -> Result<(), Transpor Ok(()) } - #[tokio::test] async fn test_deposit_entry_insufficient_funds() -> Result<(), TransportError> { // Arrange @@ -585,15 +775,13 @@ async fn test_deposit_entry_insufficient_funds() -> Result<(), TransportError> { let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; - + let mut users_iter = token_voter_test.users.iter(); let first_user_cookie = users_iter.next().unwrap(); let mut mint_iter = token_voter_test.mints.iter(); let first_mint_cookie = mint_iter.next().unwrap(); - - let voter_cookie = token_voter_test .with_voter(®istrar_cookie, &first_user_cookie) .await?; @@ -614,7 +802,8 @@ async fn test_deposit_entry_insufficient_funds() -> Result<(), TransportError> { let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 20; @@ -628,6 +817,7 @@ async fn test_deposit_entry_insufficient_funds() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await .err() @@ -650,17 +840,17 @@ async fn test_deposit_entry_with_invalid_registrar_error() -> Result<(), Transpo let second_realm_cookie = token_voter_test.governance.with_realm().await?; - let second_registrar_cookie = token_voter_test.with_registrar(&second_realm_cookie).await?; + let second_registrar_cookie = token_voter_test + .with_registrar(&second_realm_cookie) + .await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; - + let mut users_iter = token_voter_test.users.iter(); let first_user_cookie = users_iter.next().unwrap(); let mut mint_iter = token_voter_test.mints.iter(); let first_mint_cookie = mint_iter.next().unwrap(); - - let voter_cookie = token_voter_test .with_voter(®istrar_cookie, &first_user_cookie) .await?; @@ -681,7 +871,8 @@ async fn test_deposit_entry_with_invalid_registrar_error() -> Result<(), Transpo let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 20; @@ -695,6 +886,7 @@ async fn test_deposit_entry_with_invalid_registrar_error() -> Result<(), Transpo &spl_token::id(), 0, amount_deposited, + None, ) .await .err() @@ -706,4 +898,4 @@ async fn test_deposit_entry_with_invalid_registrar_error() -> Result<(), Transpo assert_anchor_err(err, ErrorCode::ConstraintSeeds); Ok(()) -} \ No newline at end of file +} diff --git a/programs/token-voter/tests/fixtures/spl_transfer_hook_example.so b/programs/token-voter/tests/fixtures/spl_transfer_hook_example.so new file mode 100755 index 0000000000000000000000000000000000000000..ff8151f791c208a4d6094bdc2e246ebe4426fff5 GIT binary patch literal 116048 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 k5z3jSx}tGwVfrZD^|s$+!yH>;y Result { + // let token_account_cookie = self + // .bench + // .with_token_account(&realm_cookie.account.community_mint, &MintType::SplToken) + // .await?; + + // let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); + // let governing_token_mint = council_mint_cookie.address; + + // let proposal_owner_record_key = get_token_owner_record_address( + // &self.program_id, + // &realm_cookie.address, + // &governing_token_mint, + // &token_owner, + // ); + + // let create_tor_ix = create_token_owner_record( + // &self.program_id, + // &realm_cookie.address, + // &self.bench.payer.pubkey(), + // &governing_token_mint, + // &self.bench.payer.pubkey(), + // ); + + // self.bench + // .process_transaction(&[create_tor_ix], None) + // .await?; + + // let deposit_ix = deposit_governing_tokens( + // &self.program_id, + // &realm_cookie.address, + // &governing_token_account_cookie.address, + // &token_owner, + // &token_owner, + // &self.bench.payer.pubkey(), + // 1, + // &governing_token_mint, + // false, + // ); + + // self.bench.process_transaction(&[deposit_ix], None).await?; + + // let governance_key = get_governance_address( + // &self.program_id, + // &realm_cookie.address, + // &token_account_cookie.address, + // ); + + // let create_governance_ix = create_governance( + // &self.program_id, + // &realm_cookie.address, + // &token_account_cookie.address, + // &proposal_owner_record_key, + // &self.bench.payer.pubkey(), + // &realm_cookie.realm_authority.pubkey(), + // None, + // spl_governance::state::governance::GovernanceConfig { + // min_community_weight_to_create_proposal: 1, + // transactions_hold_up_time: 10, + // min_council_weight_to_create_proposal: 1, + // community_vote_threshold: VoteThreshold::YesVotePercentage(60), + // voting_base_time: 600, + // community_vote_tipping: VoteTipping::Strict, + // council_vote_threshold: VoteThreshold::YesVotePercentage(60), + // council_veto_vote_threshold: VoteThreshold::Disabled, + // council_vote_tipping: VoteTipping::Disabled, + // community_veto_vote_threshold: VoteThreshold::Disabled, + // voting_cool_off_time: 0, + // deposit_exempt_proposal_count: 10, + // }, + // ); + + // self.bench + // .process_transaction( + // &[create_governance_ix], + // Some(&[&realm_cookie.realm_authority]), + // ) + // .await?; + + // let proposal_governing_token_mint = realm_cookie.account.community_mint; + // let proposal_seed = Pubkey::new_unique(); + + // let proposal_key = get_proposal_address( + // &self.program_id, + // &governance_key, + // &proposal_governing_token_mint, + // &proposal_seed, + // ); + + // let create_proposal_ix = create_proposal( + // &self.program_id, + // &governance_key, + // &proposal_owner_record_key, + // &token_owner, + // &self.bench.payer.pubkey(), + // None, + // &realm_cookie.address, + // String::from("Proposal #1"), + // String::from("Proposal #1 link"), + // &proposal_governing_token_mint, + // spl_governance::state::proposal::VoteType::SingleChoice, + // vec!["Yes".to_string()], + // true, + // &proposal_seed, + // ); + + // let sign_off_proposal_ix = sign_off_proposal( + // &self.program_id, + // &realm_cookie.address, + // &governance_key, + // &proposal_key, + // &token_owner, + // Some(&proposal_owner_record_key), + // ); + + // self.bench + // .process_transaction(&[create_proposal_ix, sign_off_proposal_ix], None) + // .await?; + + // let account = ProposalV2 { + // account_type: GovernanceAccountType::GovernanceV2, + // governing_token_mint: proposal_governing_token_mint, + // state: ProposalState::Voting, + // governance: governance_key, + // token_owner_record: proposal_owner_record_key, + // signatories_count: 1, + // signatories_signed_off_count: 1, + // vote_type: spl_governance::state::proposal::VoteType::SingleChoice, + // options: vec![], + // deny_vote_weight: Some(1), + // veto_vote_weight: 0, + // abstain_vote_weight: None, + // start_voting_at: None, + // draft_at: 1, + // signing_off_at: None, + // voting_at: None, + // voting_at_slot: None, + // voting_completed_at: None, + // executing_at: None, + // closed_at: None, + // execution_flags: spl_governance::state::enums::InstructionExecutionFlags::None, + // max_vote_weight: None, + // max_voting_time: None, + // reserved: [0; 64], + // name: String::from("Proposal #1"), + // description_link: String::from("Proposal #1 link"), + // reserved1: 0, + // vote_threshold: None, + // }; + + // Ok(ProposalCookie { + // address: proposal_key, + // account, + // }) + // } #[allow(dead_code)] pub async fn with_token_owner_record( &mut self, diff --git a/programs/token-voter/tests/program_test/program_test_bench.rs b/programs/token-voter/tests/program_test/program_test_bench.rs index b7802f5b..c1736f34 100644 --- a/programs/token-voter/tests/program_test/program_test_bench.rs +++ b/programs/token-voter/tests/program_test/program_test_bench.rs @@ -1,29 +1,19 @@ use std::cell::RefCell; -use anchor_lang::{ - prelude::{Pubkey, Rent}, - AccountDeserialize, -}; +use anchor_lang::{prelude::{Pubkey, Rent}, AccountDeserialize}; use anchor_spl::associated_token; use borsh::BorshDeserialize; use solana_program::system_program; use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; use solana_sdk::{ - account::{Account, ReadableAccount}, - borsh1::try_from_slice_unchecked, - instruction::Instruction, - program_option::COption, - program_pack::Pack, - signature::Keypair, - signer::Signer, - system_instruction, - transaction::Transaction, - transport::TransportError, + account::{Account, ReadableAccount}, borsh1::try_from_slice_unchecked, instruction::{AccountMeta, Instruction}, program_option::COption, program_pack::Pack, signature::Keypair, signer::Signer, system_instruction, sysvar, transaction::Transaction, transport::TransportError }; use spl_associated_token_account::get_associated_token_address_with_program_id; +use spl_tlv_account_resolution::{account::ExtraAccountMeta, seeds::Seed, state::ExtraAccountMetaList}; use spl_token_2022::extension::ExtensionType; use spl_token_client::token::ExtensionInitializationParams; +use spl_transfer_hook_interface::{get_extra_account_metas_address, instruction::{initialize_extra_account_meta_list, update_extra_account_meta_list}}; use crate::program_test::tools::clone_keypair; @@ -495,6 +485,203 @@ impl ProgramTestBench { .await } + #[allow(dead_code)] + pub async fn initialize_transfer_hook_account_metas( + &self, + mint_address: &Pubkey, + mint_authority: &Keypair, + payer: &Keypair, + program_id: &Pubkey, + source: &Pubkey, + destination: &Pubkey, + writable_pubkey: &Pubkey, + amount: u64, + ) -> Vec { + let extra_account_metas_address = + get_extra_account_metas_address(&mint_address, &program_id); + + let init_extra_account_metas = [ + ExtraAccountMeta::new_with_pubkey(&sysvar::instructions::id(), false, false).unwrap(), + ExtraAccountMeta::new_with_pubkey(&mint_authority.pubkey(), false, false).unwrap(), + ExtraAccountMeta::new_with_seeds( + &[ + Seed::Literal { + bytes: b"seed-prefix".to_vec(), + }, + Seed::AccountKey { index: 0 }, + ], + false, + true, + ) + .unwrap(), + ExtraAccountMeta::new_with_seeds( + &[ + Seed::InstructionData { + index: 8, // After instruction discriminator + length: 8, // `u64` (amount) + }, + Seed::AccountKey { index: 2 }, + ], + false, + true, + ) + .unwrap(), + ExtraAccountMeta::new_with_pubkey(&writable_pubkey, false, true).unwrap(), + ]; + + let extra_pda_1 = Pubkey::find_program_address( + &[ + b"seed-prefix", // Literal prefix + source.as_ref(), // Account at index 0 + ], + &program_id, + ) + .0; + let extra_pda_2 = Pubkey::find_program_address( + &[ + &amount.to_le_bytes(), // Instruction data bytes 8 to 16 + destination.as_ref(), // Account at index 2 + ], + &program_id, + ) + .0; + + let extra_account_metas = [ + AccountMeta::new(extra_account_metas_address, false), + AccountMeta::new(*program_id, false), + AccountMeta::new_readonly(sysvar::instructions::id(), false), + AccountMeta::new_readonly(mint_authority.pubkey(), false), + AccountMeta::new(extra_pda_1, false), + AccountMeta::new(extra_pda_2, false), + AccountMeta::new(*writable_pubkey, false), + ]; + + let rent_lamports = self.rent.minimum_balance( + ExtraAccountMetaList::size_of(init_extra_account_metas.len()).unwrap(), + ); + + let instructions = + &[ + system_instruction::transfer( + &payer.pubkey(), + &extra_account_metas_address, + rent_lamports, + ), + initialize_extra_account_meta_list( + &program_id, + &extra_account_metas_address, + &mint_address, + &mint_authority.pubkey(), + &init_extra_account_metas, + ), + ]; + self + .process_transaction(instructions, Some(&[&payer, &mint_authority])) + .await + .unwrap(); + + extra_account_metas.to_vec() + } + + #[allow(dead_code)] + pub async fn update_transfer_hook_account_metas( + &self, + mint_address: &Pubkey, + mint_authority: &Keypair, + payer: &Keypair, + program_id: &Pubkey, + source: &Pubkey, + destination: &Pubkey, + updated_writable_pubkey: &Pubkey, + amount: u64, + ) -> Vec { + let extra_account_metas_address = + get_extra_account_metas_address(&mint_address, &program_id); + + let updated_extra_account_metas = [ + ExtraAccountMeta::new_with_pubkey(&sysvar::instructions::id(), false, false).unwrap(), + ExtraAccountMeta::new_with_pubkey(&mint_authority.pubkey(), false, false).unwrap(), + ExtraAccountMeta::new_with_seeds( + &[ + Seed::Literal { + bytes: b"updated-seed-prefix".to_vec(), + }, + Seed::AccountKey { index: 0 }, + ], + false, + true, + ) + .unwrap(), + ExtraAccountMeta::new_with_seeds( + &[ + Seed::InstructionData { + index: 8, // After instruction discriminator + length: 8, // `u64` (amount) + }, + Seed::AccountKey { index: 2 }, + ], + false, + true, + ) + .unwrap(), + ExtraAccountMeta::new_with_pubkey(&updated_writable_pubkey, false, true).unwrap(), + ]; + + let extra_pda_1 = Pubkey::find_program_address( + &[ + b"updated-seed-prefix", // Literal prefix + source.as_ref(), // Account at index 0 + ], + &program_id, + ) + .0; + let extra_pda_2 = Pubkey::find_program_address( + &[ + &amount.to_le_bytes(), // Instruction data bytes 8 to 16 + destination.as_ref(), // Account at index 2 + ], + &program_id, + ) + .0; + + let extra_account_metas = [ + AccountMeta::new(extra_account_metas_address, false), + AccountMeta::new(*program_id, false), + AccountMeta::new_readonly(sysvar::instructions::id(), false), + AccountMeta::new_readonly(mint_authority.pubkey(), false), + AccountMeta::new(extra_pda_1, false), + AccountMeta::new(extra_pda_2, false), + AccountMeta::new(*updated_writable_pubkey, false), + ]; + + let rent_lamports = self.rent.minimum_balance( + ExtraAccountMetaList::size_of(updated_extra_account_metas.len()).unwrap(), + ); + + let instructions = + &[ + system_instruction::transfer( + &payer.pubkey(), + &extra_account_metas_address, + rent_lamports, + ), + update_extra_account_meta_list( + &program_id, + &extra_account_metas_address, + &mint_address, + &mint_authority.pubkey(), + &updated_extra_account_metas, + ), + ]; + + self + .process_transaction(instructions, Some(&[&payer, &mint_authority])) + .await + .unwrap(); + + extra_account_metas.to_vec() + } + #[allow(dead_code)] pub async fn create_mint_token_extension_with_transfer_hook( &self, diff --git a/programs/token-voter/tests/program_test/token_voter_test.rs b/programs/token-voter/tests/program_test/token_voter_test.rs index 320dbda9..7621cd7c 100644 --- a/programs/token-voter/tests/program_test/token_voter_test.rs +++ b/programs/token-voter/tests/program_test/token_voter_test.rs @@ -13,7 +13,7 @@ use crate::program_test::governance_test::GovernanceTest; use crate::program_test::program_test_bench::ProgramTestBench; use anchor_lang::ToAccountMetas; use solana_program::program_pack::Pack; -use solana_program_test::{BanksClientError, ProgramTest}; +use solana_program_test::{processor, BanksClientError, ProgramTest}; use solana_sdk::instruction::Instruction; use solana_sdk::signature::Keypair; use solana_sdk::signer::Signer; @@ -85,7 +85,6 @@ impl TokenVoterTest { &mut program_test, MintType::SplToken, ); - GovernanceTest::add_program(&mut program_test); let program_id = token_voter::id(); @@ -120,14 +119,25 @@ impl TokenVoterTest { } } + #[allow(dead_code)] - pub async fn start_new_token_extensions() -> Self { + pub async fn start_new_token_extensions( + transfer_hook_program_id: Option<&Pubkey>,) -> Self { let mut program_test = ProgramTest::new("token_voter", token_voter::id(), None); let (mints, users) = ProgramTestBench::add_mints_and_user_cookies_spl_token( &mut program_test, MintType::SplTokenExtensions, ); + if transfer_hook_program_id.is_some() { + program_test.set_compute_max_units(500_000); + program_test.add_program( + "spl_transfer_hook_example", + *transfer_hook_program_id.unwrap(), + processor!(spl_transfer_hook_example::processor::process), + ); + }; + GovernanceTest::add_program(&mut program_test); let program_id = token_voter::id(); @@ -462,6 +472,8 @@ impl TokenVoterTest { token_program: &Pubkey, deposit_entry_index: u8, amount: u64, + // additional accounts for transfer_hooks to work + additional_account_meta: Option>, ) -> Result<(), BanksClientError> { self.deposit_entry_using_ix( registrar_cookie, @@ -474,6 +486,7 @@ impl TokenVoterTest { amount, NopOverride, None, + additional_account_meta ) .await } @@ -491,6 +504,8 @@ impl TokenVoterTest { amount: u64, instruction_override: F, signers_override: Option<&[&Keypair]>, + // additional accounts for transfer_hooks to work + additional_account_meta: Option>, ) -> Result<(), BanksClientError> { let data = anchor_lang::InstructionData::data(&token_voter::instruction::Deposit { deposit_entry_index, @@ -506,7 +521,7 @@ impl TokenVoterTest { &mint_cookie.address, token_program, ); - let accounts = token_voter::accounts::Deposit { + let mut accounts = token_voter::accounts::Deposit { registrar: registrar_cookie.address, voter: voter_cookie.address, voter_weight_record: voter_cookie.voter_weight_record, @@ -519,21 +534,28 @@ impl TokenVoterTest { instructions: instructions::id(), system_program: System::id(), associated_token_program: AssociatedToken::id(), + } + .to_account_metas(None); + + if let Some(additional_account_meta) = additional_account_meta { + accounts = accounts + .into_iter() + .chain(additional_account_meta.into_iter()) + .collect(); }; - - let mut configure_mint_config_ix = Instruction { + let mut deposit_ix = Instruction { program_id: token_voter::id(), - accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + accounts, data, }; - instruction_override(&mut configure_mint_config_ix); + instruction_override(&mut deposit_ix); let default_signers = &[&user_cookie.key]; let signers = signers_override.unwrap_or(default_signers); self.bench - .process_transaction(&[configure_mint_config_ix], Some(signers)) + .process_transaction(&[deposit_ix], Some(signers)) .await?; Ok(()) @@ -550,6 +572,8 @@ impl TokenVoterTest { token_program: &Pubkey, deposit_entry_index: u8, amount: u64, + // additional accounts for transfer_hooks to work + additional_account_meta: Option>, ) -> Result<(), BanksClientError> { self.withdraw_deposit_entry_using_ix( registrar_cookie, @@ -562,6 +586,7 @@ impl TokenVoterTest { amount, NopOverride, None, + additional_account_meta ) .await } @@ -579,6 +604,8 @@ impl TokenVoterTest { amount: u64, instruction_override: F, signers_override: Option<&[&Keypair]>, + // additional accounts for transfer_hooks to work + additional_account_meta: Option>, ) -> Result<(), BanksClientError> { let data = anchor_lang::InstructionData::data(&token_voter::instruction::Withdraw { deposit_entry_index, @@ -594,7 +621,7 @@ impl TokenVoterTest { &mint_cookie.address, token_program, ); - let accounts = token_voter::accounts::Withdraw { + let mut accounts = token_voter::accounts::Withdraw { registrar: registrar_cookie.address, voter: voter_cookie.address, voter_weight_record: voter_cookie.voter_weight_record, @@ -606,20 +633,29 @@ impl TokenVoterTest { token_program: *token_program, system_program: System::id(), associated_token_program: AssociatedToken::id(), + } + .to_account_metas(None); + + if let Some(additional_account_meta) = additional_account_meta { + accounts = accounts + .into_iter() + .chain(additional_account_meta.into_iter()) + .collect(); }; - let mut configure_mint_config_ix = Instruction { + + let mut withdraw_ix = Instruction { program_id: token_voter::id(), - accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), + accounts: accounts, data, }; - instruction_override(&mut configure_mint_config_ix); + instruction_override(&mut withdraw_ix); let default_signers = &[&user_cookie.key]; let signers = signers_override.unwrap_or(default_signers); self.bench - .process_transaction(&[configure_mint_config_ix], Some(signers)) + .process_transaction(&[withdraw_ix], Some(signers)) .await?; Ok(()) diff --git a/programs/token-voter/tests/withdraw.rs b/programs/token-voter/tests/withdraw.rs index 7fdee8a2..37ffddb5 100644 --- a/programs/token-voter/tests/withdraw.rs +++ b/programs/token-voter/tests/withdraw.rs @@ -1,17 +1,206 @@ +use crate::program_test::program_test_bench::MintType; +use anchor_spl::associated_token; use program_test::token_voter_test::TokenVoterTest; use program_test::tools::*; use solana_program_test::*; +use solana_sdk::instruction::InstructionError; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signer::Signer; use solana_sdk::transport::TransportError; use token_voter::error::TokenVoterError; mod program_test; +#[tokio::test] +async fn test_withdraw_with_token_extensions_transfer_hooks() -> Result<(), TransportError> { + // Arrange + let transfer_hook_program_id = Pubkey::new_unique(); + let mut token_voter_test = + TokenVoterTest::start_new_token_extensions(Some(&transfer_hook_program_id)).await; + + let realm_cookie = token_voter_test + .governance + .with_realm_token_extension() + .await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let first_mint_cookie_transfer_hook = token_voter_test + .bench + .with_mint( + &MintType::SplTokenExtensionsWithTransferHook, + Some(&transfer_hook_program_id), + ) + .await + .unwrap(); + let _first_user_cookie_token_account = token_voter_test + .bench + .with_tokens( + &first_mint_cookie_transfer_hook, + &first_user_cookie.key.pubkey(), + 100, + &MintType::SplTokenExtensionsWithTransferHook, + ) + .await; + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie_transfer_hook, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; + + let amount_deposited = 10_u64; + let vault = associated_token::get_associated_token_address_with_program_id( + &voter_cookie.address, + &first_mint_cookie_transfer_hook.address, + &spl_token_2022::id(), + ); + let deposit_token = associated_token::get_associated_token_address_with_program_id( + &first_user_cookie.key.pubkey(), + &first_mint_cookie_transfer_hook.address, + &spl_token_2022::id(), + ); + token_voter_test.bench.advance_clock().await; + let additional_account_metas = token_voter_test + .bench + .initialize_transfer_hook_account_metas( + &first_mint_cookie_transfer_hook.address, + &first_mint_cookie_transfer_hook.mint_authority, + &first_user_cookie.key, + &transfer_hook_program_id, + &deposit_token, + &vault, + &Pubkey::new_unique(), + amount_deposited, + ) + .await; + token_voter_test.bench.advance_clock().await; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie_transfer_hook, + &spl_token_2022::id(), + 0, + amount_deposited, + Some(additional_account_metas.to_vec()), + ) + .await?; + + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + let first_vault_balance = token_voter_test + .vault_balance( + &voter_cookie, + &first_mint_cookie_transfer_hook, + &spl_token_2022::id(), + ) + .await; + + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + first_vault_balance + ); + assert_eq!(first_vault_balance, amount_deposited); + + token_voter_test.bench.advance_clock().await; + + let err = token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie_transfer_hook, + &spl_token_2022::id(), + 0, + amount_deposited, + None, + ) + .await + .err() + .unwrap(); + + assert_ix_err(err, InstructionError::Custom(2110272652)); + + let additional_account_metas = token_voter_test + .bench + .update_transfer_hook_account_metas( + &first_mint_cookie_transfer_hook.address, + &first_mint_cookie_transfer_hook.mint_authority, + &first_user_cookie.key, + &transfer_hook_program_id, + &vault, + &deposit_token, + &Pubkey::new_unique(), + amount_deposited, + ) + .await; + + token_voter_test + .withdraw_deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie_transfer_hook, + &spl_token_2022::id(), + 0, + amount_deposited, + Some(additional_account_metas), + ) + .await?; + + // Assert + let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; + + assert_eq!(voter_data.registrar, registrar_cookie.address); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + 0 + ); + assert_eq!(voter_data.deposits.len(), 1); + + let first_vault_balance = token_voter_test + .vault_balance( + &voter_cookie, + &first_mint_cookie_transfer_hook, + &spl_token_2022::id(), + ) + .await; + assert_eq!(first_vault_balance, 0); + Ok(()) +} + #[tokio::test] async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { // Arrange - let mut token_voter_test = TokenVoterTest::start_new_token_extensions().await; + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + let realm_cookie = token_voter_test + .governance + .with_realm_token_extension() + .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; @@ -39,7 +228,8 @@ async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 10_u64; token_voter_test .deposit_entry( @@ -51,13 +241,19 @@ async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { &spl_token_2022::id(), 0, amount_deposited, + None, ) .await?; let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; - let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie, &spl_token_2022::id()).await; - - assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, first_vault_balance); + let first_vault_balance = token_voter_test + .vault_balance(&voter_cookie, &first_mint_cookie, &spl_token_2022::id()) + .await; + + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + first_vault_balance + ); assert_eq!(first_vault_balance, amount_deposited); token_voter_test.bench.advance_clock().await; @@ -72,24 +268,29 @@ async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { &spl_token_2022::id(), 0, amount_deposited, + None ) .await?; - + // Assert let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; assert_eq!(voter_data.registrar, registrar_cookie.address); // println!("{:?}", voter_data); - assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, 0); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + 0 + ); assert_eq!(voter_data.deposits.len(), 1); - let first_vault_balance = token_voter_test.vault_balance(&voter_cookie, &first_mint_cookie, &spl_token_2022::id()).await; + let first_vault_balance = token_voter_test + .vault_balance(&voter_cookie, &first_mint_cookie, &spl_token_2022::id()) + .await; assert_eq!(first_vault_balance, 0); Ok(()) } - #[tokio::test] async fn test_withdraw() -> Result<(), TransportError> { // Arrange @@ -123,7 +324,8 @@ async fn test_withdraw() -> Result<(), TransportError> { let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 10_u64; token_voter_test .deposit_entry( @@ -135,10 +337,10 @@ async fn test_withdraw() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await?; - token_voter_test.bench.advance_clock().await; token_voter_test @@ -151,15 +353,19 @@ async fn test_withdraw() -> Result<(), TransportError> { &spl_token::id(), 0, amount_deposited, + None, ) .await?; - + // Assert let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; assert_eq!(voter_data.registrar, registrar_cookie.address); println!("{:?}", voter_data); - assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, 0); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + 0 + ); assert_eq!(voter_data.deposits.len(), 1); Ok(()) @@ -198,7 +404,8 @@ async fn test_withdraw_fail_to_withdraw_in_same_slot() -> Result<(), TransportEr let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 10_u64; token_voter_test .deposit_entry( @@ -210,6 +417,7 @@ async fn test_withdraw_fail_to_withdraw_in_same_slot() -> Result<(), TransportEr &spl_token::id(), 0, amount_deposited, + None, ) .await?; @@ -223,18 +431,18 @@ async fn test_withdraw_fail_to_withdraw_in_same_slot() -> Result<(), TransportEr &spl_token::id(), 0, amount_deposited, + None, ) - .await - .err() - .unwrap(); - + .await + .err() + .unwrap(); + // Assert assert_token_voter_err(err, TokenVoterError::CannotWithdraw); Ok(()) } - #[tokio::test] async fn test_withdraw_multi_deposit_and_withdraw() -> Result<(), TransportError> { // Arrange @@ -268,7 +476,8 @@ async fn test_withdraw_multi_deposit_and_withdraw() -> Result<(), TransportError let token_owner_record_cookie = token_voter_test .governance - .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie).await?; + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; let amount_deposited = 5_u64; token_voter_test .deposit_entry( @@ -280,6 +489,7 @@ async fn test_withdraw_multi_deposit_and_withdraw() -> Result<(), TransportError &spl_token::id(), 0, amount_deposited, + None, ) .await?; @@ -295,10 +505,10 @@ async fn test_withdraw_multi_deposit_and_withdraw() -> Result<(), TransportError &spl_token::id(), 0, amount_deposited, + None, ) .await?; - token_voter_test.bench.advance_clock().await; token_voter_test @@ -311,16 +521,20 @@ async fn test_withdraw_multi_deposit_and_withdraw() -> Result<(), TransportError &spl_token::id(), 0, amount_deposited * 2, + None, ) .await?; - + // Assert let voter_data = token_voter_test.get_voter(&voter_cookie.address).await; assert_eq!(voter_data.registrar, registrar_cookie.address); println!("{:?}", voter_data); - assert_eq!(voter_data.deposits.first().unwrap().amount_deposited_native, 0); + assert_eq!( + voter_data.deposits.first().unwrap().amount_deposited_native, + 0 + ); assert_eq!(voter_data.deposits.len(), 1); Ok(()) -} \ No newline at end of file +} From 0bca501421b14f062fbf6e679f9e1ab891730f6d Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Mon, 20 May 2024 18:07:00 +0400 Subject: [PATCH 08/11] add cast_token_vote tests --- programs/token-voter/tests/cast_token_vote.rs | 321 ++++++++++++++++ .../tests/program_test/governance_test.rs | 351 ++++++++---------- .../tests/program_test/token_voter_test.rs | 1 + .../token-voter/tests/program_test/tools.rs | 15 + 4 files changed, 502 insertions(+), 186 deletions(-) create mode 100644 programs/token-voter/tests/cast_token_vote.rs diff --git a/programs/token-voter/tests/cast_token_vote.rs b/programs/token-voter/tests/cast_token_vote.rs new file mode 100644 index 00000000..85b19752 --- /dev/null +++ b/programs/token-voter/tests/cast_token_vote.rs @@ -0,0 +1,321 @@ +use crate::program_test::program_test_bench::MintType; +use anchor_lang::error::ErrorCode; +use anchor_spl::associated_token; +use anchor_spl::token_interface::spl_token_metadata_interface::borsh::BorshDeserialize; +use program_test::token_voter_test::TokenVoterTest; +use program_test::tools::*; +use solana_program_test::*; +use solana_sdk::instruction::InstructionError; +use solana_sdk::pubkey::Pubkey; +use solana_sdk::signature::Keypair; +use solana_sdk::signer::Signer; +use solana_sdk::transport::TransportError; +use token_voter::error::TokenVoterError; +mod program_test; +use crate::program_test::program_test_bench::TokenAccountCookie; + +#[tokio::test] +async fn test_cast_token_vote() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + let token_account_keypair = Keypair::new(); + let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); + + token_voter_test.governance.bench.create_token_account( + &token_account_keypair, + &council_mint_cookie.address, + &first_user_cookie.key.pubkey(), + &MintType::SplToken, + ) + .await?; + token_voter_test.governance.bench.mint_tokens( + &council_mint_cookie.address, + &council_mint_cookie.mint_authority, + &token_account_keypair.pubkey(), + 100, + &MintType::SplToken, + &first_user_cookie.key.pubkey(), + ) + .await?; + + let _token_account_cookie = TokenAccountCookie { + address: token_account_keypair.pubkey(), + }; + + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + second_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; + + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token::id(), + 0, + amount_deposited, + None, + ) + .await?; + + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &second_mint_cookie, + &spl_token::id(), + 1, + amount_deposited, + None, + ) + .await?; + + let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie).await?; + + token_voter_test + .governance + .cast_vote( + &realm_cookie, + &proposal_cookie, + &voter_cookie, + &first_user_cookie.key, + &first_user_cookie.key, + &max_voter_weight_record_cookie.address, + &token_owner_record_cookie, + ) + .await?; + + token_voter_test.bench.advance_clock().await; + + let err = token_voter_test + .governance + .cast_vote( + &realm_cookie, + &proposal_cookie, + &voter_cookie, + &first_user_cookie.key, + &first_user_cookie.key, + &max_voter_weight_record_cookie.address, + &token_owner_record_cookie, + ) + .await + .err() + .unwrap(); + + // Token Owner already voted on the Proposal + assert_ix_err_transport(err, InstructionError::Custom(519)); + + let voter_weight_record = token_voter_test + .get_voter_weight_record(&voter_cookie.voter_weight_record) + .await; + + let proposal_data = token_voter_test.bench.get_account_data(proposal_cookie.address).await; + let mut data_slice: &[u8] = &proposal_data; + let proposal_state: spl_governance::state::proposal::ProposalV2 = + spl_governance::state::proposal::ProposalV2::deserialize(&mut data_slice).unwrap(); + // println!("proposal_state: {:?}", proposal_state.options[0]); + assert_eq!(proposal_state.options[0].vote_weight, voter_weight_record.voter_weight); + assert_eq!(proposal_state.deny_vote_weight.unwrap(), 0); + Ok(()) +} + +// #[tokio::test] +// async fn test_cast_token_vote_token_extension() -> Result<(), TransportError> { +// // Arrange +// let mut token_voter_test = TokenVoterTest::start_new().await; + +// let realm_cookie = token_voter_test.governance.with_realm().await?; + +// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; +// let governance_program_cookie = token_voter_test.with_governance_program(None).await; + +// let first_user_cookie = token_voter_test.users.first().unwrap(); + +// let mut mint_iter = token_voter_test.mints.iter(); +// let first_mint_cookie = mint_iter.next().unwrap(); +// let second_mint_cookie = mint_iter.next().unwrap(); + +// let voter_cookie = token_voter_test +// .with_voter(®istrar_cookie, first_user_cookie) +// .await?; + +// let max_voter_weight_record_cookie = token_voter_test +// .with_max_voter_weight_record(®istrar_cookie) +// .await?; +// let token_account_keypair = Keypair::new(); +// let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); + +// token_voter_test.governance.bench.create_token_account( +// &token_account_keypair, +// &council_mint_cookie.address, +// &first_user_cookie.key.pubkey(), +// &MintType::SplToken, +// ) +// .await?; +// token_voter_test.governance.bench.mint_tokens( +// &council_mint_cookie.address, +// &council_mint_cookie.mint_authority, +// &token_account_keypair.pubkey(), +// 100, +// &MintType::SplToken, +// &first_user_cookie.key.pubkey(), +// ) +// .await?; + +// let _token_account_cookie = TokenAccountCookie { +// address: token_account_keypair.pubkey(), +// }; + + +// let _voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// first_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let _second_voting_mint_config = token_voter_test +// .configure_mint_config( +// ®istrar_cookie, +// &governance_program_cookie, +// &max_voter_weight_record_cookie, +// second_mint_cookie, +// 0, // no digit shift +// ) +// .await?; + +// let token_owner_record_cookie = token_voter_test +// .governance +// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) +// .await?; + +// let amount_deposited = 10_u64; +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &first_mint_cookie, +// &spl_token::id(), +// 0, +// amount_deposited, +// None, +// ) +// .await?; + +// token_voter_test +// .deposit_entry( +// ®istrar_cookie, +// &voter_cookie, +// &first_user_cookie, +// &token_owner_record_cookie, +// &second_mint_cookie, +// &spl_token::id(), +// 1, +// amount_deposited, +// None, +// ) +// .await?; + +// let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie).await?; + +// token_voter_test +// .governance +// .cast_vote( +// &realm_cookie, +// &proposal_cookie, +// &voter_cookie, +// &first_user_cookie.key, +// &first_user_cookie.key, +// &max_voter_weight_record_cookie.address, +// &token_owner_record_cookie, +// ) +// .await?; + +// token_voter_test.bench.advance_clock().await; + +// let err = token_voter_test +// .governance +// .cast_vote( +// &realm_cookie, +// &proposal_cookie, +// &voter_cookie, +// &first_user_cookie.key, +// &first_user_cookie.key, +// &max_voter_weight_record_cookie.address, +// &token_owner_record_cookie, +// ) +// .await +// .err() +// .unwrap(); + +// // Token Owner already voted on the Proposal +// assert_ix_err_transport(err, InstructionError::Custom(519)); + +// let voter_weight_record = token_voter_test +// .get_voter_weight_record(&voter_cookie.voter_weight_record) +// .await; + +// let proposal_data = token_voter_test.bench.get_account_data(proposal_cookie.address).await; +// let mut data_slice: &[u8] = &proposal_data; +// let proposal_state: spl_governance::state::proposal::ProposalV2 = +// spl_governance::state::proposal::ProposalV2::deserialize(&mut data_slice).unwrap(); +// println!("proposal_state: {:?}", proposal_state.options[0]); +// assert_eq!(proposal_state.options[0].vote_weight, voter_weight_record.voter_weight); +// assert_eq!(proposal_state.deny_vote_weight.unwrap(), 0); + +// // Assert +// assert_eq!(0, 1); + +// Ok(()) +// } \ No newline at end of file diff --git a/programs/token-voter/tests/program_test/governance_test.rs b/programs/token-voter/tests/program_test/governance_test.rs index abe81b0f..127bcbd3 100644 --- a/programs/token-voter/tests/program_test/governance_test.rs +++ b/programs/token-voter/tests/program_test/governance_test.rs @@ -6,7 +6,7 @@ use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; use spl_governance::{ instruction::{ create_governance, create_proposal, create_realm, create_token_owner_record, - deposit_governing_tokens, relinquish_vote, sign_off_proposal, + deposit_governing_tokens, relinquish_vote, sign_off_proposal, AddSignatoryAuthority, }, state::{ enums::{ @@ -14,12 +14,13 @@ use spl_governance::{ VoteTipping, }, governance::get_governance_address, - proposal::{get_proposal_address, ProposalV2}, + proposal::{self, get_proposal_address, ProposalV2}, realm::{get_realm_address, GoverningTokenConfigAccountArgs, RealmConfig, RealmV2}, realm_config::GoverningTokenType, token_owner_record::{ get_token_owner_record_address, TokenOwnerRecordV2, TOKEN_OWNER_RECORD_LAYOUT_VERSION, }, + vote_record, }, }; @@ -28,7 +29,10 @@ use crate::program_test::{ tools::clone_keypair, }; -use super::{program_test_bench::{MintType, TokenAccountCookie}, token_voter_test::{UserCookie, VoterCookie}}; +use super::{ + program_test_bench::{MintType, TokenAccountCookie}, + token_voter_test::{UserCookie, VoterCookie}, +}; #[allow(dead_code)] pub struct RealmCookie { @@ -161,8 +165,14 @@ impl GovernanceTest { pub async fn with_realm_token_extension(&mut self) -> Result { let realm_authority = Keypair::new(); - let community_mint_cookie = self.bench.with_mint(&MintType::SplTokenExtensions, None).await?; - let council_mint_cookie = self.bench.with_mint(&MintType::SplTokenExtensions, None).await?; + let community_mint_cookie = self + .bench + .with_mint(&MintType::SplTokenExtensions, None) + .await?; + let council_mint_cookie = self + .bench + .with_mint(&MintType::SplTokenExtensions, None) + .await?; self.next_id += 1; let realm_name = format!("Realm #{}", self.next_id).to_string(); @@ -314,7 +324,7 @@ impl GovernanceTest { .await?; let proposal_governing_token_mint = realm_cookie.account.community_mint; - let proposal_seed = Pubkey::new_unique(); + let proposal_seed: Pubkey = Pubkey::new_unique(); let proposal_key = get_proposal_address( &self.program_id, @@ -390,168 +400,6 @@ impl GovernanceTest { }) } - // #[allow(dead_code)] - // pub async fn with_proposal_with_token_voter( - // &mut self, - // realm_cookie: &RealmCookie, - // token_voter_mint: &MintCookie, - // voter_cookie: &VoterCookie, - // governing_token_account_cookie: &TokenAccountCookie, - // ) -> Result { - // let token_account_cookie = self - // .bench - // .with_token_account(&realm_cookie.account.community_mint, &MintType::SplToken) - // .await?; - - // let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); - // let governing_token_mint = council_mint_cookie.address; - - // let proposal_owner_record_key = get_token_owner_record_address( - // &self.program_id, - // &realm_cookie.address, - // &governing_token_mint, - // &token_owner, - // ); - - // let create_tor_ix = create_token_owner_record( - // &self.program_id, - // &realm_cookie.address, - // &self.bench.payer.pubkey(), - // &governing_token_mint, - // &self.bench.payer.pubkey(), - // ); - - // self.bench - // .process_transaction(&[create_tor_ix], None) - // .await?; - - // let deposit_ix = deposit_governing_tokens( - // &self.program_id, - // &realm_cookie.address, - // &governing_token_account_cookie.address, - // &token_owner, - // &token_owner, - // &self.bench.payer.pubkey(), - // 1, - // &governing_token_mint, - // false, - // ); - - // self.bench.process_transaction(&[deposit_ix], None).await?; - - // let governance_key = get_governance_address( - // &self.program_id, - // &realm_cookie.address, - // &token_account_cookie.address, - // ); - - // let create_governance_ix = create_governance( - // &self.program_id, - // &realm_cookie.address, - // &token_account_cookie.address, - // &proposal_owner_record_key, - // &self.bench.payer.pubkey(), - // &realm_cookie.realm_authority.pubkey(), - // None, - // spl_governance::state::governance::GovernanceConfig { - // min_community_weight_to_create_proposal: 1, - // transactions_hold_up_time: 10, - // min_council_weight_to_create_proposal: 1, - // community_vote_threshold: VoteThreshold::YesVotePercentage(60), - // voting_base_time: 600, - // community_vote_tipping: VoteTipping::Strict, - // council_vote_threshold: VoteThreshold::YesVotePercentage(60), - // council_veto_vote_threshold: VoteThreshold::Disabled, - // council_vote_tipping: VoteTipping::Disabled, - // community_veto_vote_threshold: VoteThreshold::Disabled, - // voting_cool_off_time: 0, - // deposit_exempt_proposal_count: 10, - // }, - // ); - - // self.bench - // .process_transaction( - // &[create_governance_ix], - // Some(&[&realm_cookie.realm_authority]), - // ) - // .await?; - - // let proposal_governing_token_mint = realm_cookie.account.community_mint; - // let proposal_seed = Pubkey::new_unique(); - - // let proposal_key = get_proposal_address( - // &self.program_id, - // &governance_key, - // &proposal_governing_token_mint, - // &proposal_seed, - // ); - - // let create_proposal_ix = create_proposal( - // &self.program_id, - // &governance_key, - // &proposal_owner_record_key, - // &token_owner, - // &self.bench.payer.pubkey(), - // None, - // &realm_cookie.address, - // String::from("Proposal #1"), - // String::from("Proposal #1 link"), - // &proposal_governing_token_mint, - // spl_governance::state::proposal::VoteType::SingleChoice, - // vec!["Yes".to_string()], - // true, - // &proposal_seed, - // ); - - // let sign_off_proposal_ix = sign_off_proposal( - // &self.program_id, - // &realm_cookie.address, - // &governance_key, - // &proposal_key, - // &token_owner, - // Some(&proposal_owner_record_key), - // ); - - // self.bench - // .process_transaction(&[create_proposal_ix, sign_off_proposal_ix], None) - // .await?; - - // let account = ProposalV2 { - // account_type: GovernanceAccountType::GovernanceV2, - // governing_token_mint: proposal_governing_token_mint, - // state: ProposalState::Voting, - // governance: governance_key, - // token_owner_record: proposal_owner_record_key, - // signatories_count: 1, - // signatories_signed_off_count: 1, - // vote_type: spl_governance::state::proposal::VoteType::SingleChoice, - // options: vec![], - // deny_vote_weight: Some(1), - // veto_vote_weight: 0, - // abstain_vote_weight: None, - // start_voting_at: None, - // draft_at: 1, - // signing_off_at: None, - // voting_at: None, - // voting_at_slot: None, - // voting_completed_at: None, - // executing_at: None, - // closed_at: None, - // execution_flags: spl_governance::state::enums::InstructionExecutionFlags::None, - // max_vote_weight: None, - // max_voting_time: None, - // reserved: [0; 64], - // name: String::from("Proposal #1"), - // description_link: String::from("Proposal #1 link"), - // reserved1: 0, - // vote_threshold: None, - // }; - - // Ok(ProposalCookie { - // address: proposal_key, - // account, - // }) - // } #[allow(dead_code)] pub async fn with_token_owner_record( &mut self, @@ -671,22 +519,153 @@ impl GovernanceTest { Ok(()) } - // #[allow(dead_code)] - // pub async fn get_proposal(&mut self, proposal_key: &Pubkey) -> ProposalV2 { - // let proposal_data = self.bench.get_account_data(proposal_key).await; - // let mut data_slice: &[u8] = &proposal_data; - // let proposal_state: ProposalV2 = - // anchor_lang::AnchorDeserialize::deserialize(&mut data_slice).unwrap(); - // proposal_state - // } - - // #[allow(dead_code)] - // pub async fn get_token_owner_record( - // &mut self, - // token_owner_record_key: &Pubkey, - // ) -> TokenOwnerRecordV2 { - // self.bench - // .get_borsh_account::(token_owner_record_key) - // .await - // } + #[allow(dead_code)] + pub async fn create_proposal( + &self, + realm_cookie: &RealmCookie, + authority: &Keypair, + voter: &VoterCookie, + payer: &Keypair, + token_owner_record_cookie: &TokenOwnerRecordCookie, + token_account_cookie: &TokenAccountCookie, + ) -> Result { + let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); + let governing_token_mint = council_mint_cookie.address; + let proposal_seed = Pubkey::new_unique(); + + let proposal = spl_governance::state::proposal::get_proposal_address( + &self.program_id, + &realm_cookie.address, + &governing_token_mint, + &proposal_seed, + ); + + let governance_key = get_governance_address( + &self.program_id, + &realm_cookie.address, + &token_account_cookie.address, + ); + + let instructions = vec![ + spl_governance::instruction::create_proposal( + &self.program_id, + &governance_key, + &token_owner_record_cookie.address, + &authority.pubkey(), + &payer.pubkey(), + Some(voter.voter_weight_record), + &realm_cookie.address, + "test proposal".into(), + "description".into(), + &governing_token_mint, + proposal::VoteType::SingleChoice, + vec!["yes".into()], + true, + &proposal_seed, + ), + spl_governance::instruction::add_signatory( + &self.program_id, + &governance_key, + &proposal, + &AddSignatoryAuthority::ProposalOwner { + token_owner_record: token_owner_record_cookie.address, + governance_authority: token_owner_record_cookie.account.governing_token_owner, + }, + // &AddSignatoryAuthority::None, + &payer.pubkey(), + &authority.pubkey(), + ), + spl_governance::instruction::sign_off_proposal( + &self.program_id, + &realm_cookie.address, + &governance_key, + &proposal, + &authority.pubkey(), + None, + ), + ]; + + let signer1 = Keypair::from_base58_string(&payer.to_base58_string()); + let signer2 = Keypair::from_base58_string(&authority.to_base58_string()); + + self.bench + .process_transaction(&instructions, Some(&[&signer1, &signer2])) + .await?; + + let account = ProposalV2 { + account_type: GovernanceAccountType::GovernanceV2, + governing_token_mint: governing_token_mint, + state: ProposalState::Voting, + governance: governance_key, + token_owner_record: token_owner_record_cookie.address, + signatories_count: 1, + signatories_signed_off_count: 1, + vote_type: spl_governance::state::proposal::VoteType::SingleChoice, + options: vec![], + deny_vote_weight: Some(1), + veto_vote_weight: 0, + abstain_vote_weight: None, + start_voting_at: None, + draft_at: 1, + signing_off_at: None, + voting_at: None, + voting_at_slot: None, + voting_completed_at: None, + executing_at: None, + closed_at: None, + execution_flags: spl_governance::state::enums::InstructionExecutionFlags::None, + max_vote_weight: None, + max_voting_time: None, + reserved: [0; 64], + name: String::from("Proposal #1"), + description_link: String::from("Proposal #1 link"), + reserved1: 0, + vote_threshold: None, + }; + + Ok(ProposalCookie { + address: proposal, + account, + }) + } + + #[allow(dead_code)] + pub async fn cast_vote( + &self, + realm_cookie: &RealmCookie, + proposal: &ProposalCookie, + voter: &VoterCookie, + authority: &Keypair, + payer: &Keypair, + max_voter_weight_record: &Pubkey, + token_owner_record_cookie: &TokenOwnerRecordCookie, + ) -> Result<(), TransportError> { + + let instructions = vec![spl_governance::instruction::cast_vote( + &self.program_id, + &realm_cookie.address, + &proposal.account.governance, + &proposal.address, + &proposal.account.token_owner_record, + &token_owner_record_cookie.address, + &authority.pubkey(), + &realm_cookie.account.community_mint, + &payer.pubkey(), + Some(voter.voter_weight_record), + Some(*max_voter_weight_record), + vote_record::Vote::Approve(vec![vote_record::VoteChoice { + rank: 0, + weight_percentage: 100, + }]), + )]; + + let signer1 = Keypair::from_base58_string(&payer.to_base58_string()); + let signer2 = Keypair::from_base58_string(&authority.to_base58_string()); + + self.bench + .process_transaction(&instructions, Some(&[&signer1, &signer2])) + .await?; + + Ok(()) + } } diff --git a/programs/token-voter/tests/program_test/token_voter_test.rs b/programs/token-voter/tests/program_test/token_voter_test.rs index 7621cd7c..8bb3c860 100644 --- a/programs/token-voter/tests/program_test/token_voter_test.rs +++ b/programs/token-voter/tests/program_test/token_voter_test.rs @@ -7,6 +7,7 @@ use anchor_spl::{ token_interface::TokenAccount, }; use solana_sdk::{instruction::AccountMeta, sysvar::instructions}; +use spl_governance::state::{proposal::ProposalV2, token_owner_record::TokenOwnerRecordV2}; use token_voter::state::*; use crate::program_test::governance_test::GovernanceTest; diff --git a/programs/token-voter/tests/program_test/tools.rs b/programs/token-voter/tests/program_test/tools.rs index 7736e19b..8264040d 100644 --- a/programs/token-voter/tests/program_test/tools.rs +++ b/programs/token-voter/tests/program_test/tools.rs @@ -78,3 +78,18 @@ pub fn assert_ix_err(banks_client_error: BanksClientError, ix_error: Instruction _ => panic!("{:?} Is not InstructionError", tx_error), }; } + +#[allow(dead_code)] +pub fn assert_ix_err_transport( + banks_client_error: TransportError, + ix_error: InstructionError +) { + let tx_error = banks_client_error.unwrap(); + + match tx_error { + TransactionError::InstructionError(_, instruction_error) => { + assert_eq!(instruction_error, ix_error); + } + _ => panic!("{:?} Is not InstructionError", tx_error), + }; +} From 645d81930afbeb056bd3c8545ebbc68b2b32c3b2 Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Tue, 21 May 2024 11:01:39 +0400 Subject: [PATCH 09/11] add resize tests and casting votes tests --- programs/token-voter/src/error.rs | 3 + .../src/instructions/resize_registrar.rs | 2 +- programs/token-voter/tests/cast_token_vote.rs | 505 ++++++++++++------ programs/token-voter/tests/close_voter.rs | 4 +- .../tests/configure_voter_weights.rs | 3 +- .../tests/create_max_voter_weight_record.rs | 3 +- .../token-voter/tests/create_registrar.rs | 2 +- programs/token-voter/tests/deposit.rs | 8 +- .../tests/program_test/governance_test.rs | 138 +---- .../tests/program_test/program_test_bench.rs | 265 ++++++--- .../tests/program_test/token_voter_test.rs | 71 ++- .../token-voter/tests/resize_registrar.rs | 100 ++++ programs/token-voter/tests/withdraw.rs | 5 +- 13 files changed, 737 insertions(+), 372 deletions(-) create mode 100644 programs/token-voter/tests/resize_registrar.rs diff --git a/programs/token-voter/src/error.rs b/programs/token-voter/src/error.rs index a7bdc69d..8f59e255 100644 --- a/programs/token-voter/src/error.rs +++ b/programs/token-voter/src/error.rs @@ -187,4 +187,7 @@ pub enum TokenVoterError { #[msg("Index is out of Voting Mint Config bounds")] OutOfBoundsVotingMintConfigIndex, + + #[msg("Resizing Max Mints cannot be smaller than Configure Mint Configs")] + InvalidResizeMaxMints, } diff --git a/programs/token-voter/src/instructions/resize_registrar.rs b/programs/token-voter/src/instructions/resize_registrar.rs index b03cb862..6665c0be 100644 --- a/programs/token-voter/src/instructions/resize_registrar.rs +++ b/programs/token-voter/src/instructions/resize_registrar.rs @@ -62,7 +62,7 @@ pub fn resize_registrar(ctx: Context, max_mints: u8) -> Result< require_gt!( max_mints as usize, registrar.voting_mint_configs.len(), - TokenVoterError::InvalidRealmAuthority + TokenVoterError::InvalidResizeMaxMints ); registrar.max_mints = max_mints; diff --git a/programs/token-voter/tests/cast_token_vote.rs b/programs/token-voter/tests/cast_token_vote.rs index 85b19752..f4f5ba4e 100644 --- a/programs/token-voter/tests/cast_token_vote.rs +++ b/programs/token-voter/tests/cast_token_vote.rs @@ -1,16 +1,12 @@ use crate::program_test::program_test_bench::MintType; -use anchor_lang::error::ErrorCode; -use anchor_spl::associated_token; use anchor_spl::token_interface::spl_token_metadata_interface::borsh::BorshDeserialize; use program_test::token_voter_test::TokenVoterTest; use program_test::tools::*; use solana_program_test::*; use solana_sdk::instruction::InstructionError; -use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Keypair; use solana_sdk::signer::Signer; use solana_sdk::transport::TransportError; -use token_voter::error::TokenVoterError; mod program_test; use crate::program_test::program_test_bench::TokenAccountCookie; @@ -25,7 +21,7 @@ async fn test_cast_token_vote() -> Result<(), TransportError> { let governance_program_cookie = token_voter_test.with_governance_program(None).await; let first_user_cookie = token_voter_test.users.first().unwrap(); - + let mut mint_iter = token_voter_test.mints.iter(); let first_mint_cookie = mint_iter.next().unwrap(); let second_mint_cookie = mint_iter.next().unwrap(); @@ -45,6 +41,7 @@ async fn test_cast_token_vote() -> Result<(), TransportError> { &council_mint_cookie.address, &first_user_cookie.key.pubkey(), &MintType::SplToken, + true ) .await?; token_voter_test.governance.bench.mint_tokens( @@ -54,13 +51,13 @@ async fn test_cast_token_vote() -> Result<(), TransportError> { 100, &MintType::SplToken, &first_user_cookie.key.pubkey(), + false, ) .await?; let _token_account_cookie = TokenAccountCookie { address: token_account_keypair.pubkey(), }; - let _voting_mint_config = token_voter_test .configure_mint_config( @@ -116,7 +113,7 @@ async fn test_cast_token_vote() -> Result<(), TransportError> { ) .await?; - let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie).await?; + let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie, &MintType::SplToken).await?; token_voter_test .governance @@ -151,6 +148,172 @@ async fn test_cast_token_vote() -> Result<(), TransportError> { // Token Owner already voted on the Proposal assert_ix_err_transport(err, InstructionError::Custom(519)); + let voter_weight_record = token_voter_test + .get_voter_weight_record(&voter_cookie.voter_weight_record) + .await; + + let proposal_data = token_voter_test.bench.get_account_data(proposal_cookie.address).await; + let mut data_slice: &[u8] = &proposal_data; + let proposal_state: spl_governance::state::proposal::ProposalV2 = + spl_governance::state::proposal::ProposalV2::deserialize(&mut data_slice).unwrap(); + assert_eq!(proposal_state.options[0].vote_weight, voter_weight_record.voter_weight); + assert_eq!(proposal_state.deny_vote_weight.unwrap(), 0); + Ok(()) +} + +#[tokio::test] +async fn test_cast_token_vote_token_extension() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; + + let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); + + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + let token_account_keypair = Keypair::new(); + let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); + + token_voter_test.governance.bench.create_token_account( + &token_account_keypair, + &council_mint_cookie.address, + &first_user_cookie.key.pubkey(), + &MintType::SplTokenExtensions, + true + ) + .await?; + token_voter_test.governance.bench.mint_tokens( + &council_mint_cookie.address, + &council_mint_cookie.mint_authority, + &token_account_keypair.pubkey(), + 100, + &MintType::SplTokenExtensions, + &first_user_cookie.key.pubkey(), + true, + ) + .await?; + + token_voter_test + .governance + .bench + .mint_tokens( + &first_mint_cookie.address, + &first_mint_cookie.mint_authority, + &token_account_keypair.pubkey(), + 100, + &MintType::SplTokenExtensions, + &first_user_cookie.key.pubkey(), + false, + ) + .await?; + + let _token_account_cookie = TokenAccountCookie { + address: token_account_keypair.pubkey(), + }; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + second_mint_cookie, + 0, // no digit shift + ) + .await?; + + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; + + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token_2022::id(), + 0, + amount_deposited, + None, + ) + .await?; + + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &second_mint_cookie, + &spl_token_2022::id(), + 1, + amount_deposited, + None, + ) + .await?; + + let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie, &MintType::SplTokenExtensions).await?; + + token_voter_test + .governance + .cast_vote( + &realm_cookie, + &proposal_cookie, + &voter_cookie, + &first_user_cookie.key, + &first_user_cookie.key, + &max_voter_weight_record_cookie.address, + &token_owner_record_cookie, + ) + .await?; + + token_voter_test.bench.advance_clock().await; + + let err = token_voter_test + .governance + .cast_vote( + &realm_cookie, + &proposal_cookie, + &voter_cookie, + &first_user_cookie.key, + &first_user_cookie.key, + &max_voter_weight_record_cookie.address, + &token_owner_record_cookie, + ) + .await + .err() + .unwrap(); + + // Assert + // Token Owner already voted on the Proposal + assert_ix_err_transport(err, InstructionError::Custom(519)); + let voter_weight_record = token_voter_test .get_voter_weight_record(&voter_cookie.voter_weight_record) .await; @@ -162,160 +325,192 @@ async fn test_cast_token_vote() -> Result<(), TransportError> { // println!("proposal_state: {:?}", proposal_state.options[0]); assert_eq!(proposal_state.options[0].vote_weight, voter_weight_record.voter_weight); assert_eq!(proposal_state.deny_vote_weight.unwrap(), 0); + Ok(()) } -// #[tokio::test] -// async fn test_cast_token_vote_token_extension() -> Result<(), TransportError> { -// // Arrange -// let mut token_voter_test = TokenVoterTest::start_new().await; +#[tokio::test] +async fn test_cast_token_vote_token_extension_transfer_fees() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; + + let realm_cookie = token_voter_test + .governance + .with_realm_token_extension(&MintType::SplTokenExtensionsWithTransferFees) + .await?; + + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; -// let realm_cookie = token_voter_test.governance.with_realm().await?; + let first_user_cookie = token_voter_test.users.first().unwrap(); + + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); -// let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; -// let governance_program_cookie = token_voter_test.with_governance_program(None).await; + let voter_cookie = token_voter_test + .with_voter(®istrar_cookie, first_user_cookie) + .await?; -// let first_user_cookie = token_voter_test.users.first().unwrap(); + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + let token_account_keypair = Keypair::new(); + let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); -// let mut mint_iter = token_voter_test.mints.iter(); -// let first_mint_cookie = mint_iter.next().unwrap(); -// let second_mint_cookie = mint_iter.next().unwrap(); - -// let voter_cookie = token_voter_test -// .with_voter(®istrar_cookie, first_user_cookie) -// .await?; - -// let max_voter_weight_record_cookie = token_voter_test -// .with_max_voter_weight_record(®istrar_cookie) -// .await?; -// let token_account_keypair = Keypair::new(); -// let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); - -// token_voter_test.governance.bench.create_token_account( -// &token_account_keypair, -// &council_mint_cookie.address, -// &first_user_cookie.key.pubkey(), -// &MintType::SplToken, -// ) -// .await?; -// token_voter_test.governance.bench.mint_tokens( -// &council_mint_cookie.address, -// &council_mint_cookie.mint_authority, -// &token_account_keypair.pubkey(), -// 100, -// &MintType::SplToken, -// &first_user_cookie.key.pubkey(), -// ) -// .await?; - -// let _token_account_cookie = TokenAccountCookie { -// address: token_account_keypair.pubkey(), -// }; + token_voter_test + .governance + .bench + .create_token_account( + &token_account_keypair, + &council_mint_cookie.address, + &first_user_cookie.key.pubkey(), + &MintType::SplTokenExtensionsWithTransferFees, + true, + ) + .await?; + token_voter_test + .governance + .bench + .mint_tokens( + &council_mint_cookie.address, + &council_mint_cookie.mint_authority, + &token_account_keypair.pubkey(), + 100, + &MintType::SplTokenExtensionsWithTransferFees, + &first_user_cookie.key.pubkey(), + true, + ) + .await?; + token_voter_test + .governance + .bench + .mint_tokens( + &first_mint_cookie.address, + &first_mint_cookie.mint_authority, + &token_account_keypair.pubkey(), + 100, + &MintType::SplTokenExtensionsWithTransferFees, + &first_user_cookie.key.pubkey(), + false, + ) + .await?; + + let _token_account_cookie = TokenAccountCookie { + address: token_account_keypair.pubkey(), + }; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + first_mint_cookie, + 0, // no digit shift + ) + .await?; + + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + second_mint_cookie, + 0, // no digit shift + ) + .await?; -// let _voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// first_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let _second_voting_mint_config = token_voter_test -// .configure_mint_config( -// ®istrar_cookie, -// &governance_program_cookie, -// &max_voter_weight_record_cookie, -// second_mint_cookie, -// 0, // no digit shift -// ) -// .await?; - -// let token_owner_record_cookie = token_voter_test -// .governance -// .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) -// .await?; - -// let amount_deposited = 10_u64; -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &first_mint_cookie, -// &spl_token::id(), -// 0, -// amount_deposited, -// None, -// ) -// .await?; - -// token_voter_test -// .deposit_entry( -// ®istrar_cookie, -// &voter_cookie, -// &first_user_cookie, -// &token_owner_record_cookie, -// &second_mint_cookie, -// &spl_token::id(), -// 1, -// amount_deposited, -// None, -// ) -// .await?; - -// let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie).await?; - -// token_voter_test -// .governance -// .cast_vote( -// &realm_cookie, -// &proposal_cookie, -// &voter_cookie, -// &first_user_cookie.key, -// &first_user_cookie.key, -// &max_voter_weight_record_cookie.address, -// &token_owner_record_cookie, -// ) -// .await?; - -// token_voter_test.bench.advance_clock().await; - -// let err = token_voter_test -// .governance -// .cast_vote( -// &realm_cookie, -// &proposal_cookie, -// &voter_cookie, -// &first_user_cookie.key, -// &first_user_cookie.key, -// &max_voter_weight_record_cookie.address, -// &token_owner_record_cookie, -// ) -// .await -// .err() -// .unwrap(); - -// // Token Owner already voted on the Proposal -// assert_ix_err_transport(err, InstructionError::Custom(519)); - -// let voter_weight_record = token_voter_test -// .get_voter_weight_record(&voter_cookie.voter_weight_record) -// .await; - -// let proposal_data = token_voter_test.bench.get_account_data(proposal_cookie.address).await; -// let mut data_slice: &[u8] = &proposal_data; -// let proposal_state: spl_governance::state::proposal::ProposalV2 = -// spl_governance::state::proposal::ProposalV2::deserialize(&mut data_slice).unwrap(); -// println!("proposal_state: {:?}", proposal_state.options[0]); -// assert_eq!(proposal_state.options[0].vote_weight, voter_weight_record.voter_weight); -// assert_eq!(proposal_state.deny_vote_weight.unwrap(), 0); - -// // Assert -// assert_eq!(0, 1); - -// Ok(()) -// } \ No newline at end of file + let token_owner_record_cookie = token_voter_test + .governance + .with_token_owner_record_using_user_cookie(&realm_cookie, &first_user_cookie) + .await?; + + let amount_deposited = 10_u64; + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &first_mint_cookie, + &spl_token_2022::id(), + 0, + amount_deposited, + None, + ) + .await?; + + token_voter_test + .deposit_entry( + ®istrar_cookie, + &voter_cookie, + &first_user_cookie, + &token_owner_record_cookie, + &second_mint_cookie, + &spl_token_2022::id(), + 1, + amount_deposited, + None, + ) + .await?; + + let proposal_cookie = token_voter_test + .governance + .with_proposal(&realm_cookie, &MintType::SplTokenExtensionsWithTransferFees) + .await?; + + token_voter_test + .governance + .cast_vote( + &realm_cookie, + &proposal_cookie, + &voter_cookie, + &first_user_cookie.key, + &first_user_cookie.key, + &max_voter_weight_record_cookie.address, + &token_owner_record_cookie, + ) + .await?; + + token_voter_test.bench.advance_clock().await; + + let err = token_voter_test + .governance + .cast_vote( + &realm_cookie, + &proposal_cookie, + &voter_cookie, + &first_user_cookie.key, + &first_user_cookie.key, + &max_voter_weight_record_cookie.address, + &token_owner_record_cookie, + ) + .await + .err() + .unwrap(); + + // Token Owner already voted on the Proposal + assert_ix_err_transport(err, InstructionError::Custom(519)); + + let voter_weight_record = token_voter_test + .get_voter_weight_record(&voter_cookie.voter_weight_record) + .await; + + let proposal_data = token_voter_test + .bench + .get_account_data(proposal_cookie.address) + .await; + let mut data_slice: &[u8] = &proposal_data; + let proposal_state: spl_governance::state::proposal::ProposalV2 = + spl_governance::state::proposal::ProposalV2::deserialize(&mut data_slice).unwrap(); + + assert_eq!( + proposal_state.options[0].vote_weight, + voter_weight_record.voter_weight + ); + assert_eq!(proposal_state.deny_vote_weight.unwrap(), 0); + + + Ok(()) +} diff --git a/programs/token-voter/tests/close_voter.rs b/programs/token-voter/tests/close_voter.rs index 68856252..20bdfbb7 100644 --- a/programs/token-voter/tests/close_voter.rs +++ b/programs/token-voter/tests/close_voter.rs @@ -5,7 +5,7 @@ use program_test::tools::*; use solana_program_test::*; use solana_sdk::transport::TransportError; use token_voter::error::TokenVoterError; - +use crate::program_test::program_test_bench::MintType; mod program_test; #[tokio::test] @@ -15,7 +15,7 @@ async fn test_close_with_token_extensions() -> Result<(), TransportError> { let realm_cookie = token_voter_test .governance - .with_realm_token_extension() + .with_realm_token_extension(&MintType::SplTokenExtensions) .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/configure_voter_weights.rs b/programs/token-voter/tests/configure_voter_weights.rs index 59b9df2f..64c28dcb 100644 --- a/programs/token-voter/tests/configure_voter_weights.rs +++ b/programs/token-voter/tests/configure_voter_weights.rs @@ -3,6 +3,7 @@ use program_test::tools::*; use solana_program_test::*; use solana_sdk::pubkey::Pubkey; use solana_sdk::transport::TransportError; +use crate::program_test::program_test_bench::MintType; mod program_test; @@ -11,7 +12,7 @@ async fn test_configure_voter_weights_with_token_extensions() -> Result<(), Tran // Arrange let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; diff --git a/programs/token-voter/tests/create_max_voter_weight_record.rs b/programs/token-voter/tests/create_max_voter_weight_record.rs index 8081cc79..2a3d0ee5 100644 --- a/programs/token-voter/tests/create_max_voter_weight_record.rs +++ b/programs/token-voter/tests/create_max_voter_weight_record.rs @@ -3,6 +3,7 @@ use program_test::tools::assert_ix_err; use solana_program::instruction::InstructionError; use solana_program_test::*; use solana_sdk::transport::TransportError; +use crate::program_test::program_test_bench::MintType; mod program_test; @@ -10,7 +11,7 @@ mod program_test; async fn test_create_max_voter_weight_record_with_token_extensions() -> Result<(), TransportError> { // Arrange let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/create_registrar.rs b/programs/token-voter/tests/create_registrar.rs index c4c5a171..b83d3fe7 100644 --- a/programs/token-voter/tests/create_registrar.rs +++ b/programs/token-voter/tests/create_registrar.rs @@ -15,7 +15,7 @@ async fn test_create_registrar_with_token_extensions() -> Result<(), TransportEr // Arrange let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension().await?; + let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; // Act let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/deposit.rs b/programs/token-voter/tests/deposit.rs index b1cdbd2a..3baa2e43 100644 --- a/programs/token-voter/tests/deposit.rs +++ b/programs/token-voter/tests/deposit.rs @@ -18,7 +18,7 @@ async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> let realm_cookie = token_voter_test .governance - .with_realm_token_extension() + .with_realm_token_extension(&MintType::SplTokenExtensions) .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -111,7 +111,7 @@ async fn test_deposit_entry_with_token_extension_transfer_hooks() -> Result<(), let realm_cookie = token_voter_test .governance - .with_realm_token_extension() + .with_realm_token_extension(&MintType::SplTokenExtensions) .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -133,6 +133,7 @@ async fn test_deposit_entry_with_token_extension_transfer_hooks() -> Result<(), &first_user_cookie.key.pubkey(), 100, &MintType::SplTokenExtensionsWithTransferHook, + false ) .await; @@ -244,7 +245,7 @@ async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), T let realm_cookie = token_voter_test .governance - .with_realm_token_extension() + .with_realm_token_extension(&MintType::SplTokenExtensions) .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -263,6 +264,7 @@ async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), T &first_user_cookie.key.pubkey(), 100, &MintType::SplTokenExtensionsWithTransferFees, + false ) .await; diff --git a/programs/token-voter/tests/program_test/governance_test.rs b/programs/token-voter/tests/program_test/governance_test.rs index 127bcbd3..6bb47e41 100644 --- a/programs/token-voter/tests/program_test/governance_test.rs +++ b/programs/token-voter/tests/program_test/governance_test.rs @@ -6,7 +6,7 @@ use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; use spl_governance::{ instruction::{ create_governance, create_proposal, create_realm, create_token_owner_record, - deposit_governing_tokens, relinquish_vote, sign_off_proposal, AddSignatoryAuthority, + deposit_governing_tokens, relinquish_vote, sign_off_proposal, }, state::{ enums::{ @@ -14,7 +14,7 @@ use spl_governance::{ VoteTipping, }, governance::get_governance_address, - proposal::{self, get_proposal_address, ProposalV2}, + proposal::{get_proposal_address, ProposalV2}, realm::{get_realm_address, GoverningTokenConfigAccountArgs, RealmConfig, RealmV2}, realm_config::GoverningTokenType, token_owner_record::{ @@ -30,7 +30,7 @@ use crate::program_test::{ }; use super::{ - program_test_bench::{MintType, TokenAccountCookie}, + program_test_bench::MintType, token_voter_test::{UserCookie, VoterCookie}, }; @@ -162,16 +162,16 @@ impl GovernanceTest { } #[allow(dead_code)] - pub async fn with_realm_token_extension(&mut self) -> Result { + pub async fn with_realm_token_extension(&mut self, mint_type: &MintType) -> Result { let realm_authority = Keypair::new(); let community_mint_cookie = self .bench - .with_mint(&MintType::SplTokenExtensions, None) + .with_mint(mint_type, None) .await?; let council_mint_cookie = self .bench - .with_mint(&MintType::SplTokenExtensions, None) + .with_mint(mint_type, None) .await?; self.next_id += 1; @@ -238,10 +238,11 @@ impl GovernanceTest { pub async fn with_proposal( &mut self, realm_cookie: &RealmCookie, + mint_type: &MintType, ) -> Result { let token_account_cookie = self .bench - .with_token_account(&realm_cookie.account.community_mint, &MintType::SplToken) + .with_token_account(&realm_cookie.account.community_mint, mint_type, true) .await?; let token_owner = self.bench.payer.pubkey(); @@ -250,7 +251,7 @@ impl GovernanceTest { let governing_token_account_cookie = self .bench - .with_tokens(council_mint_cookie, &token_owner, 1, &MintType::SplToken) + .with_tokens(council_mint_cookie, &token_owner, 2, mint_type, true) .await?; let proposal_owner_record_key = get_token_owner_record_address( @@ -271,6 +272,11 @@ impl GovernanceTest { self.bench .process_transaction(&[create_tor_ix], None) .await?; + + let is_token_2022 = match mint_type { + MintType::SplToken => false, + _ => true, + }; let deposit_ix = deposit_governing_tokens( &self.program_id, @@ -279,9 +285,9 @@ impl GovernanceTest { &token_owner, &token_owner, &self.bench.payer.pubkey(), - 1, + 2, &governing_token_mint, - false, + is_token_2022 ); self.bench.process_transaction(&[deposit_ix], None).await?; @@ -519,116 +525,6 @@ impl GovernanceTest { Ok(()) } - #[allow(dead_code)] - pub async fn create_proposal( - &self, - realm_cookie: &RealmCookie, - authority: &Keypair, - voter: &VoterCookie, - payer: &Keypair, - token_owner_record_cookie: &TokenOwnerRecordCookie, - token_account_cookie: &TokenAccountCookie, - ) -> Result { - let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); - let governing_token_mint = council_mint_cookie.address; - let proposal_seed = Pubkey::new_unique(); - - let proposal = spl_governance::state::proposal::get_proposal_address( - &self.program_id, - &realm_cookie.address, - &governing_token_mint, - &proposal_seed, - ); - - let governance_key = get_governance_address( - &self.program_id, - &realm_cookie.address, - &token_account_cookie.address, - ); - - let instructions = vec![ - spl_governance::instruction::create_proposal( - &self.program_id, - &governance_key, - &token_owner_record_cookie.address, - &authority.pubkey(), - &payer.pubkey(), - Some(voter.voter_weight_record), - &realm_cookie.address, - "test proposal".into(), - "description".into(), - &governing_token_mint, - proposal::VoteType::SingleChoice, - vec!["yes".into()], - true, - &proposal_seed, - ), - spl_governance::instruction::add_signatory( - &self.program_id, - &governance_key, - &proposal, - &AddSignatoryAuthority::ProposalOwner { - token_owner_record: token_owner_record_cookie.address, - governance_authority: token_owner_record_cookie.account.governing_token_owner, - }, - // &AddSignatoryAuthority::None, - &payer.pubkey(), - &authority.pubkey(), - ), - spl_governance::instruction::sign_off_proposal( - &self.program_id, - &realm_cookie.address, - &governance_key, - &proposal, - &authority.pubkey(), - None, - ), - ]; - - let signer1 = Keypair::from_base58_string(&payer.to_base58_string()); - let signer2 = Keypair::from_base58_string(&authority.to_base58_string()); - - self.bench - .process_transaction(&instructions, Some(&[&signer1, &signer2])) - .await?; - - let account = ProposalV2 { - account_type: GovernanceAccountType::GovernanceV2, - governing_token_mint: governing_token_mint, - state: ProposalState::Voting, - governance: governance_key, - token_owner_record: token_owner_record_cookie.address, - signatories_count: 1, - signatories_signed_off_count: 1, - vote_type: spl_governance::state::proposal::VoteType::SingleChoice, - options: vec![], - deny_vote_weight: Some(1), - veto_vote_weight: 0, - abstain_vote_weight: None, - start_voting_at: None, - draft_at: 1, - signing_off_at: None, - voting_at: None, - voting_at_slot: None, - voting_completed_at: None, - executing_at: None, - closed_at: None, - execution_flags: spl_governance::state::enums::InstructionExecutionFlags::None, - max_vote_weight: None, - max_voting_time: None, - reserved: [0; 64], - name: String::from("Proposal #1"), - description_link: String::from("Proposal #1 link"), - reserved1: 0, - vote_threshold: None, - }; - - Ok(ProposalCookie { - address: proposal, - account, - }) - } - #[allow(dead_code)] pub async fn cast_vote( &self, @@ -640,7 +536,7 @@ impl GovernanceTest { max_voter_weight_record: &Pubkey, token_owner_record_cookie: &TokenOwnerRecordCookie, ) -> Result<(), TransportError> { - + let instructions = vec![spl_governance::instruction::cast_vote( &self.program_id, &realm_cookie.address, diff --git a/programs/token-voter/tests/program_test/program_test_bench.rs b/programs/token-voter/tests/program_test/program_test_bench.rs index c1736f34..ea4c5469 100644 --- a/programs/token-voter/tests/program_test/program_test_bench.rs +++ b/programs/token-voter/tests/program_test/program_test_bench.rs @@ -1,19 +1,36 @@ use std::cell::RefCell; -use anchor_lang::{prelude::{Pubkey, Rent}, AccountDeserialize}; +use anchor_lang::{ + prelude::{Pubkey, Rent}, + AccountDeserialize, +}; use anchor_spl::associated_token; use borsh::BorshDeserialize; use solana_program::system_program; use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; use solana_sdk::{ - account::{Account, ReadableAccount}, borsh1::try_from_slice_unchecked, instruction::{AccountMeta, Instruction}, program_option::COption, program_pack::Pack, signature::Keypair, signer::Signer, system_instruction, sysvar, transaction::Transaction, transport::TransportError + account::{Account, ReadableAccount}, + borsh1::try_from_slice_unchecked, + instruction::{AccountMeta, Instruction}, + program_option::COption, + program_pack::Pack, + signature::Keypair, + signer::Signer, + system_instruction, sysvar, + transaction::Transaction, + transport::TransportError, }; use spl_associated_token_account::get_associated_token_address_with_program_id; -use spl_tlv_account_resolution::{account::ExtraAccountMeta, seeds::Seed, state::ExtraAccountMetaList}; +use spl_tlv_account_resolution::{ + account::ExtraAccountMeta, seeds::Seed, state::ExtraAccountMetaList, +}; use spl_token_2022::extension::ExtensionType; use spl_token_client::token::ExtensionInitializationParams; -use spl_transfer_hook_interface::{get_extra_account_metas_address, instruction::{initialize_extra_account_meta_list, update_extra_account_meta_list}}; +use spl_transfer_hook_interface::{ + get_extra_account_metas_address, + instruction::{initialize_extra_account_meta_list, update_extra_account_meta_list}, +}; use crate::program_test::tools::clone_keypair; @@ -166,14 +183,9 @@ impl ProgramTestBench { program_test: &mut ProgramTest, mint_type: MintType, ) -> (Vec, Vec) { - let (token_program_id, is_token_2022) = match mint_type { - MintType::SplToken => { - (spl_token::id(), false) - } - _ => { - (spl_token_2022::id(), true) - } + MintType::SplToken => (spl_token::id(), false), + _ => (spl_token_2022::id(), true), }; // Mints let mints: Vec = vec![ @@ -186,7 +198,7 @@ impl ProgramTestBench { quote_lot: 10 as f64, mint_authority: Keypair::new(), freeze_authority: None, - is_token_2022 + is_token_2022, }, // symbol: "MNGO".to_string() MintCookie { index: 1, @@ -197,7 +209,7 @@ impl ProgramTestBench { quote_lot: 0 as f64, mint_authority: Keypair::new(), freeze_authority: None, - is_token_2022 + is_token_2022, }, // symbol: "USDC".to_string() ]; // Add mints in loop @@ -470,16 +482,23 @@ impl ProgramTestBench { )]; for params in extension_initialization_params { - instructions.push(params.instruction(&spl_token_2022::id(), &mint_keypair.pubkey()).unwrap()); + instructions.push( + params + .instruction(&spl_token_2022::id(), &mint_keypair.pubkey()) + .unwrap(), + ); } - instructions.push(spl_token_2022::instruction::initialize_mint( - &spl_token_2022::id(), - &mint_keypair.pubkey(), - mint_authority, - freeze_authority, - 0, - ).unwrap()); + instructions.push( + spl_token_2022::instruction::initialize_mint( + &spl_token_2022::id(), + &mint_keypair.pubkey(), + mint_authority, + freeze_authority, + 0, + ) + .unwrap(), + ); self.process_transaction(&instructions, Some(&[mint_keypair])) .await @@ -560,23 +579,21 @@ impl ProgramTestBench { ExtraAccountMetaList::size_of(init_extra_account_metas.len()).unwrap(), ); - let instructions = - &[ - system_instruction::transfer( - &payer.pubkey(), - &extra_account_metas_address, - rent_lamports, - ), - initialize_extra_account_meta_list( - &program_id, - &extra_account_metas_address, - &mint_address, - &mint_authority.pubkey(), - &init_extra_account_metas, - ), - ]; - self - .process_transaction(instructions, Some(&[&payer, &mint_authority])) + let instructions = &[ + system_instruction::transfer( + &payer.pubkey(), + &extra_account_metas_address, + rent_lamports, + ), + initialize_extra_account_meta_list( + &program_id, + &extra_account_metas_address, + &mint_address, + &mint_authority.pubkey(), + &init_extra_account_metas, + ), + ]; + self.process_transaction(instructions, Some(&[&payer, &mint_authority])) .await .unwrap(); @@ -629,8 +646,8 @@ impl ProgramTestBench { let extra_pda_1 = Pubkey::find_program_address( &[ - b"updated-seed-prefix", // Literal prefix - source.as_ref(), // Account at index 0 + b"updated-seed-prefix", // Literal prefix + source.as_ref(), // Account at index 0 ], &program_id, ) @@ -658,24 +675,22 @@ impl ProgramTestBench { ExtraAccountMetaList::size_of(updated_extra_account_metas.len()).unwrap(), ); - let instructions = - &[ - system_instruction::transfer( - &payer.pubkey(), - &extra_account_metas_address, - rent_lamports, - ), - update_extra_account_meta_list( - &program_id, - &extra_account_metas_address, - &mint_address, - &mint_authority.pubkey(), - &updated_extra_account_metas, - ), - ]; + let instructions = &[ + system_instruction::transfer( + &payer.pubkey(), + &extra_account_metas_address, + rent_lamports, + ), + update_extra_account_meta_list( + &program_id, + &extra_account_metas_address, + &mint_address, + &mint_authority.pubkey(), + &updated_extra_account_metas, + ), + ]; - self - .process_transaction(instructions, Some(&[&payer, &mint_authority])) + self.process_transaction(instructions, Some(&[&payer, &mint_authority])) .await .unwrap(); @@ -741,6 +756,7 @@ impl ProgramTestBench { &self, token_mint: &Pubkey, mint_type: &MintType, + is_token_account: bool, ) -> Result { let token_account_keypair = Keypair::new(); @@ -749,6 +765,7 @@ impl ProgramTestBench { token_mint, &self.payer.pubkey(), mint_type, + is_token_account, ) .await?; Ok(TokenAccountCookie { @@ -763,8 +780,8 @@ impl ProgramTestBench { owner: &Pubkey, amount: u64, mint_type: &MintType, + is_token_account: bool, ) -> Result { - let token_account_keypair = Keypair::new(); self.create_token_account( @@ -772,6 +789,7 @@ impl ProgramTestBench { &mint_cookie.address, owner, mint_type, + is_token_account, ) .await?; @@ -782,6 +800,7 @@ impl ProgramTestBench { amount, mint_type, owner, + is_token_account, ) .await?; Ok(TokenAccountCookie { @@ -797,8 +816,8 @@ impl ProgramTestBench { amount: u64, mint_type: &MintType, owner: &Pubkey, + is_token_account: bool, ) -> Result<(), BanksClientError> { - match mint_type { MintType::SplToken => { let mint_instruction = spl_token_2022::instruction::mint_to( @@ -815,20 +834,31 @@ impl ProgramTestBench { .await } _ => { - let associated_token_account_pubkey = associated_token::get_associated_token_address_with_program_id( - &owner, - &token_mint, - &spl_token_2022::id(), - ); - let mint_instruction = spl_token_2022::instruction::mint_to( - &spl_token_2022::id(), - token_mint, - &associated_token_account_pubkey, - &token_mint_authority.pubkey(), - &[], - amount, - ) - .unwrap(); + let mint_instruction = if is_token_account { + spl_token_2022::instruction::mint_to( + &spl_token_2022::id(), + token_mint, + token_account, + &token_mint_authority.pubkey(), + &[], + amount, + ) + .unwrap() + } else { + spl_token_2022::instruction::mint_to( + &spl_token_2022::id(), + token_mint, + &associated_token::get_associated_token_address_with_program_id( + &owner, + &token_mint, + &spl_token_2022::id(), + ), + &token_mint_authority.pubkey(), + &[], + amount, + ) + .unwrap() + }; self.process_transaction(&[mint_instruction], Some(&[token_mint_authority])) .await @@ -843,8 +873,9 @@ impl ProgramTestBench { token_mint: &Pubkey, owner: &Pubkey, mint_type: &MintType, + is_token_account: bool, ) -> Result<(), BanksClientError> { - match mint_type { + match mint_type { MintType::SplToken => { let create_account_instruction = system_instruction::create_account( &self.context.borrow().payer.pubkey(), @@ -861,22 +892,88 @@ impl ProgramTestBench { owner, ) .unwrap(); - - self.process_transaction(&[create_account_instruction, initialize_account_instruction], Some(&[token_account_keypair])) + + self.process_transaction( + &[create_account_instruction, initialize_account_instruction], + Some(&[token_account_keypair]), + ) + .await + } + MintType::SplTokenExtensionsWithTransferFees => { + let extension_type_space = ExtensionType::try_calculate_account_len::< + spl_token_2022::state::Account, + >(&[ExtensionType::TransferFeeConfig]) + .unwrap(); + if is_token_account { + let create_account_instruction = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &token_account_keypair.pubkey(), + self.rent.minimum_balance(extension_type_space), + extension_type_space as u64, + &spl_token_2022::id(), + ); + + let initialize_account_instruction = + spl_token_2022::instruction::initialize_account( + &spl_token_2022::id(), + &token_account_keypair.pubkey(), + token_mint, + owner, + ) + .unwrap(); + self.process_transaction( + &[create_account_instruction, initialize_account_instruction], + Some(&[token_account_keypair]), + ) .await + } else { + let create_ata_account = + spl_associated_token_account::instruction::create_associated_token_account( + &self.context.borrow().payer.pubkey(), + owner, + token_mint, + &spl_token_2022::id(), + ); + self.process_transaction(&[create_ata_account], None).await + } } _ => { - let create_ata_account = spl_associated_token_account::instruction::create_associated_token_account( - &self.context.borrow().payer.pubkey(), - owner, - token_mint, - &spl_token_2022::id(), - ); - self.process_transaction(&[create_ata_account], None) + if is_token_account { + let create_account_instruction = system_instruction::create_account( + &self.context.borrow().payer.pubkey(), + &token_account_keypair.pubkey(), + self.rent + .minimum_balance(spl_token_2022::state::Account::get_packed_len()), + spl_token_2022::state::Account::get_packed_len() as u64, + &spl_token_2022::id(), + ); + + let initialize_account_instruction = + spl_token_2022::instruction::initialize_account( + &spl_token_2022::id(), + &token_account_keypair.pubkey(), + token_mint, + owner, + ) + .unwrap(); + + self.process_transaction( + &[create_account_instruction, initialize_account_instruction], + Some(&[token_account_keypair]), + ) .await + } else { + let create_ata_account = + spl_associated_token_account::instruction::create_associated_token_account( + &self.context.borrow().payer.pubkey(), + owner, + token_mint, + &spl_token_2022::id(), + ); + self.process_transaction(&[create_ata_account], None).await + } } } - } #[allow(dead_code)] diff --git a/programs/token-voter/tests/program_test/token_voter_test.rs b/programs/token-voter/tests/program_test/token_voter_test.rs index 8bb3c860..17710788 100644 --- a/programs/token-voter/tests/program_test/token_voter_test.rs +++ b/programs/token-voter/tests/program_test/token_voter_test.rs @@ -7,7 +7,6 @@ use anchor_spl::{ token_interface::TokenAccount, }; use solana_sdk::{instruction::AccountMeta, sysvar::instructions}; -use spl_governance::state::{proposal::ProposalV2, token_owner_record::TokenOwnerRecordV2}; use token_voter::state::*; use crate::program_test::governance_test::GovernanceTest; @@ -253,6 +252,76 @@ impl TokenVoterTest { }) } + #[allow(dead_code)] + pub async fn with_resize_registrar( + &mut self, + realm_cookie: &RealmCookie, + max_mints: u8, + ) -> Result { + self.with_resize_registrar_using_ix(realm_cookie,max_mints, NopOverride, None) + .await + } + + #[allow(dead_code)] + pub async fn with_resize_registrar_using_ix( + &mut self, + realm_cookie: &RealmCookie, + max_mints: u8, + instruction_override: F, + signers_override: Option<&[&Keypair]>, + ) -> Result { + let registrar_key = + get_registrar_address(&realm_cookie.address, &realm_cookie.account.community_mint); + + let data = anchor_lang::InstructionData::data(&token_voter::instruction::ResizeRegistrar { + max_mints, + }); + + let accounts = anchor_lang::ToAccountMetas::to_account_metas( + &token_voter::accounts::ResizeRegistrar { + registrar: registrar_key, + realm: realm_cookie.address, + governance_program_id: self.governance.program_id, + governing_token_mint: realm_cookie.account.community_mint, + realm_authority: realm_cookie.get_realm_authority().pubkey(), + payer: self.bench.payer.pubkey(), + system_program: solana_sdk::system_program::id(), + }, + None, + ); + + let mut resize_registrar_ix = Instruction { + program_id: token_voter::id(), + accounts, + data, + }; + + instruction_override(&mut resize_registrar_ix); + + let default_signers = &[&realm_cookie.realm_authority]; + let signers = signers_override.unwrap_or(default_signers); + + self.bench + .process_transaction(&[resize_registrar_ix], Some(signers)) + .await?; + + let account = Registrar { + governance_program_id: self.governance.program_id, + realm: realm_cookie.address, + governing_token_mint: realm_cookie.account.community_mint, + voting_mint_configs: vec![], + max_mints, + reserved: [0; 127], + }; + Ok(RegistrarCookie { + address: registrar_key, + mint: vec![], + account, + realm_authority: realm_cookie.get_realm_authority(), + max_mints, + }) + } + #[allow(dead_code)] pub async fn with_voter( &self, diff --git a/programs/token-voter/tests/resize_registrar.rs b/programs/token-voter/tests/resize_registrar.rs new file mode 100644 index 00000000..eb42e356 --- /dev/null +++ b/programs/token-voter/tests/resize_registrar.rs @@ -0,0 +1,100 @@ +mod program_test; +use program_test::token_voter_test::TokenVoterTest; + +use solana_program_test::*; +use solana_sdk::transport::TransportError; +use token_voter::error::TokenVoterError; +use crate::program_test::program_test_bench::MintType; +use solana_sdk::signer::Signer; +use crate::program_test::tools::assert_token_voter_err; + +#[tokio::test] +async fn test_resize_registrar() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + // Act + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + // Act + let registrar_cookie_resized = token_voter_test.with_resize_registrar(&realm_cookie, 2).await?; + + // Assert + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar, registrar_cookie_resized.account); + + Ok(()) +} + +#[tokio::test] +async fn test_resize_registrar_with_configured_mint() -> Result<(), TransportError> { + // Arrange + let mut token_voter_test = TokenVoterTest::start_new().await; + + let realm_cookie = token_voter_test.governance.with_realm().await?; + + // Act + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; + let governance_program_cookie = token_voter_test.with_governance_program(None).await; + + let first_user_cookie = token_voter_test.users.first().unwrap(); + let mut mint_iter = token_voter_test.mints.iter(); + let first_mint_cookie = mint_iter.next().unwrap(); + let second_mint_cookie = mint_iter.next().unwrap(); + + + let _first_user_cookie_token_account = token_voter_test + .bench + .with_tokens( + &first_mint_cookie, + &first_user_cookie.key.pubkey(), + 100, + &MintType::SplTokenExtensionsWithTransferFees, + false + ) + .await; + + let max_voter_weight_record_cookie = token_voter_test + .with_max_voter_weight_record(®istrar_cookie) + .await?; + + let _voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &first_mint_cookie, + 0, // no digit shift + ) + .await?; + let _second_voting_mint_config = token_voter_test + .configure_mint_config( + ®istrar_cookie, + &governance_program_cookie, + &max_voter_weight_record_cookie, + &second_mint_cookie, + 0, // no digit shift + ) + .await?; + + // Act + let err = token_voter_test.with_resize_registrar(&realm_cookie, 2).await + .err() + .unwrap(); + assert_token_voter_err(err, TokenVoterError::InvalidResizeMaxMints); + + let registrar_cookie_resized = token_voter_test.with_resize_registrar(&realm_cookie, 3).await?; + + // Assert + let registrar = token_voter_test + .get_registrar_account(®istrar_cookie.address) + .await; + + assert_eq!(registrar.max_mints, registrar_cookie_resized.account.max_mints); + + Ok(()) +} diff --git a/programs/token-voter/tests/withdraw.rs b/programs/token-voter/tests/withdraw.rs index 37ffddb5..f5526ccc 100644 --- a/programs/token-voter/tests/withdraw.rs +++ b/programs/token-voter/tests/withdraw.rs @@ -20,7 +20,7 @@ async fn test_withdraw_with_token_extensions_transfer_hooks() -> Result<(), Tran let realm_cookie = token_voter_test .governance - .with_realm_token_extension() + .with_realm_token_extension(&MintType::SplTokenExtensions) .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -42,6 +42,7 @@ async fn test_withdraw_with_token_extensions_transfer_hooks() -> Result<(), Tran &first_user_cookie.key.pubkey(), 100, &MintType::SplTokenExtensionsWithTransferHook, + false ) .await; @@ -199,7 +200,7 @@ async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { let realm_cookie = token_voter_test .governance - .with_realm_token_extension() + .with_realm_token_extension(&MintType::SplTokenExtensions) .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; From 9ea9511bd2187fe8753ba8548a9f9b3c03cacfb4 Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sat, 1 Jun 2024 11:29:11 +0400 Subject: [PATCH 10/11] add error clean ups and tools/spl_token removal of unused functions --- programs/token-voter/Cargo.toml | 2 +- programs/token-voter/src/error.rs | 86 +---- programs/token-voter/src/tools/spl_token.rs | 392 +------------------- 3 files changed, 5 insertions(+), 475 deletions(-) diff --git a/programs/token-voter/Cargo.toml b/programs/token-voter/Cargo.toml index d94f22d8..07915345 100644 --- a/programs/token-voter/Cargo.toml +++ b/programs/token-voter/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "token-voter" version = "0.1.0" -description = "Created with Anchor" +description = "SPL Governance plugin implementing token based governance power" edition = "2021" [lib] diff --git a/programs/token-voter/src/error.rs b/programs/token-voter/src/error.rs index 8f59e255..fc41c2f5 100644 --- a/programs/token-voter/src/error.rs +++ b/programs/token-voter/src/error.rs @@ -8,18 +8,12 @@ pub enum TokenVoterError { #[msg("Invalid Realm for Registrar")] InvalidRealmForRegistrar, - #[msg("Invalid Collection Size")] - InvalidCollectionSize, - #[msg("Invalid MaxVoterWeightRecord Realm")] InvalidMaxVoterWeightRecordRealm, #[msg("Invalid MaxVoterWeightRecord Mint")] InvalidMaxVoterWeightRecordMint, - #[msg("CastVote Is Not Allowed")] - CastVoteIsNotAllowed, - #[msg("Invalid VoterWeightRecord Realm")] InvalidVoterWeightRecordRealm, @@ -29,51 +23,6 @@ pub enum TokenVoterError { #[msg("Invalid TokenOwner for VoterWeightRecord")] InvalidTokenOwnerForVoterWeightRecord, - #[msg("Collection must be verified")] - CollectionMustBeVerified, - - #[msg("Voter does not own NFT")] - VoterDoesNotOwnNft, - - #[msg("Collection not found")] - CollectionNotFound, - - #[msg("Missing Metadata collection")] - MissingMetadataCollection, - - #[msg("Token Metadata doesn't match")] - TokenMetadataDoesNotMatch, - - #[msg("Invalid account owner")] - InvalidAccountOwner, - - #[msg("Invalid token metadata account")] - InvalidTokenMetadataAccount, - - #[msg("Duplicated NFT detected")] - DuplicatedNftDetected, - - #[msg("Invalid NFT amount")] - InvalidNftAmount, - - #[msg("NFT already voted")] - NftAlreadyVoted, - - #[msg("Invalid Proposal for NftVoteRecord")] - InvalidProposalForNftVoteRecord, - - #[msg("Invalid TokenOwner for NftVoteRecord")] - InvalidTokenOwnerForNftVoteRecord, - - #[msg("VoteRecord must be withdrawn")] - VoteRecordMustBeWithdrawn, - - #[msg("Invalid VoteRecord for NftVoteRecord")] - InvalidVoteRecordForNftVoteRecord, - - #[msg("VoterWeightRecord must be expired")] - VoterWeightRecordMustBeExpired, - #[msg("Mathematical Overflow")] Overflow, @@ -85,9 +34,6 @@ pub enum TokenVoterError { #[msg("Invalid Mint account owner")] SplTokenMintWithInvalidOwner, - /// Token Account is not initialized - #[msg("Token Account is not initialized")] - SplTokenAccountNotInitialized, /// Token Account doesn't exist #[msg("Token Account doesn't exist")] @@ -108,45 +54,15 @@ pub enum TokenVoterError { /// Token Mint account doesn't exist #[msg("Token Mint account doesn't exist")] SplTokenMintDoesNotExist, - - /// Current mint authority must sign transaction - #[msg("Current mint authority must sign transaction")] - MintAuthorityMustSign, - - /// Invalid mint authority - #[msg("Invalid mint authority")] - InvalidMintAuthority, - - /// Mint has no authority - #[msg("Mint has no authority")] - MintHasNoAuthority, - - /// Invalid token owner - #[msg("Invalid token owner")] - InvalidTokenOwner, - - /// Current token owner must sign transaction - #[msg("Current token owner must sign transaction")] - TokenOwnerMustSign, - + /// Account data is empty or invalid #[msg("Account Data is empty or invalid")] InvalidAccountData, - /// Invalid Governing Token Mint - #[msg("Invalid Governing Token Mint")] - InvalidGoverningTokenMint, - /// Math Overflow in VoterWeight #[msg("Math Overflow in VoterWeight")] VoterWeightOverflow, - #[msg("Invalid Proposal for NftVoteRecord")] - InvalidProposalForTokenVoteRecord, - - #[msg("Invalid TokenOwner for NftVoteRecord")] - InvalidTokenOwnerForTokenVoteRecord, - #[msg("Mint Not Found in Mint Configs")] MintNotFound, diff --git a/programs/token-voter/src/tools/spl_token.rs b/programs/token-voter/src/tools/spl_token.rs index aee1c553..93abc7a8 100644 --- a/programs/token-voter/src/tools/spl_token.rs +++ b/programs/token-voter/src/tools/spl_token.rs @@ -8,21 +8,17 @@ use { entrypoint::ProgramResult, msg, program::{invoke, invoke_signed}, - program_option::COption, program_pack::Pack, - system_instruction, sysvar::Sysvar, }, - spl_governance::tools::pack::unpack_coption_pubkey, spl_token::state::Multisig, spl_token_2022::{ cmp_pubkeys, extension::{ transfer_fee::TransferFeeConfig, transfer_hook, AccountType, BaseStateWithExtensions, - ExtensionType, PodStateWithExtensions, StateWithExtensions, + PodStateWithExtensions, StateWithExtensions, }, generic_token_account::GenericTokenAccount, - instruction::AuthorityType, pod::PodMint, state::{Account, Mint}, }, @@ -49,128 +45,6 @@ pub fn is_spl_token_2022(spl_token_program_id: &Pubkey) -> bool { return true; } -/// Creates and initializes SPL token account with PDA using the provided PDA -/// seeds -#[allow(clippy::too_many_arguments)] -pub fn create_spl_token_account_signed<'a>( - payer_info: &AccountInfo<'a>, - token_account_info: &AccountInfo<'a>, - token_account_address_seeds: &[&[u8]], - token_mint_info: &AccountInfo<'a>, - token_account_owner_info: &AccountInfo<'a>, - program_id: &Pubkey, - system_info: &AccountInfo<'a>, - spl_token_info: &AccountInfo<'a>, - rent_sysvar_info: &AccountInfo<'a>, - rent: &Rent, -) -> Result<()> { - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); - - // Get the token space for if the token has extensions. - let space = if is_spl_token_2022(spl_token_program_id) { - let mint_data = token_mint_info.data.borrow(); - - let state = PodStateWithExtensions::::unpack(&mint_data).map_err(|_| { - Into::::into(TokenVoterError::InvalidGoverningTokenMint) - })?; - let mint_extensions = state.get_extension_types()?; - let required_extensions = - ExtensionType::get_required_init_account_extensions(&mint_extensions); - ExtensionType::try_calculate_account_len::(&required_extensions)? - } else { - spl_token_2022::state::Account::get_packed_len() - }; - - let create_account_instruction = system_instruction::create_account( - payer_info.key, - token_account_info.key, - 1.max(rent.minimum_balance(space)), - space as u64, - spl_token_program_id, - ); - - let (account_address, bump_seed) = - Pubkey::find_program_address(token_account_address_seeds, program_id); - - if account_address != *token_account_info.key { - msg!( - "Create SPL Token Account with PDA: {:?} was requested while PDA: {:?} was expected", - token_account_info.key, - account_address - ); - return Err(ProgramError::InvalidSeeds.into()); - } - - let mut signers_seeds = token_account_address_seeds.to_vec(); - let bump = &[bump_seed]; - signers_seeds.push(bump); - - invoke_signed( - &create_account_instruction, - &[ - payer_info.clone(), - token_account_info.clone(), - system_info.clone(), - ], - &[&signers_seeds[..]], - )?; - - let initialize_account_instruction = spl_token_2022::instruction::initialize_account( - spl_token_program_id, - token_account_info.key, - token_mint_info.key, - token_account_owner_info.key, - )?; - - invoke( - &initialize_account_instruction, - &[ - payer_info.clone(), - token_account_info.clone(), - token_account_owner_info.clone(), - token_mint_info.clone(), - spl_token_info.clone(), - rent_sysvar_info.clone(), - ], - )?; - - Ok(()) -} - -/// Transfers SPL Tokens -pub fn transfer_spl_tokens<'a>( - source_info: &AccountInfo<'a>, - destination_info: &AccountInfo<'a>, - authority_info: &AccountInfo<'a>, - amount: u64, - spl_token_info: &AccountInfo<'a>, -) -> ProgramResult { - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); - // for previous instruction compatibility we do not use transfer_checked() here. - #[allow(deprecated)] - let transfer_instruction = spl_token_2022::instruction::transfer( - spl_token_program_id, - source_info.key, - destination_info.key, - authority_info.key, - &[], - amount, - ) - .unwrap(); - - invoke( - &transfer_instruction, - &[ - spl_token_info.clone(), - authority_info.clone(), - source_info.clone(), - destination_info.clone(), - ], - )?; - - Ok(()) -} - /// Transfers SPL Tokens pub fn transfer_checked_spl_tokens<'a>( source_info: &AccountInfo<'a>, @@ -181,7 +55,7 @@ pub fn transfer_checked_spl_tokens<'a>( mint_info: &AccountInfo<'a>, additional_accounts: &[AccountInfo<'a>], ) -> ProgramResult { - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + let spl_token_program_id = spl_token_info.owner; let mut transfer_instruction = spl_token_2022::instruction::transfer_checked( spl_token_program_id, @@ -237,92 +111,6 @@ pub fn transfer_checked_spl_tokens<'a>( Ok(()) } -/// Mint SPL Tokens -pub fn mint_spl_tokens_to<'a>( - mint_info: &AccountInfo<'a>, - destination_info: &AccountInfo<'a>, - mint_authority_info: &AccountInfo<'a>, - amount: u64, - spl_token_info: &AccountInfo<'a>, -) -> ProgramResult { - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); - - let mint_to_ix = spl_token_2022::instruction::mint_to( - spl_token_program_id, - mint_info.key, - destination_info.key, - mint_authority_info.key, - &[], - amount, - ) - .unwrap(); - - invoke( - &mint_to_ix, - &[ - spl_token_info.clone(), - mint_authority_info.clone(), - mint_info.clone(), - destination_info.clone(), - ], - )?; - - Ok(()) -} - -/// Transfers SPL Tokens from a token account owned by the provided PDA -/// authority with seeds -pub fn transfer_spl_tokens_signed<'a>( - source_info: &AccountInfo<'a>, - destination_info: &AccountInfo<'a>, - authority_info: &AccountInfo<'a>, - authority_seeds: &[&[u8]], - program_id: &Pubkey, - amount: u64, - spl_token_info: &AccountInfo<'a>, -) -> ProgramResult { - let (authority_address, bump_seed) = Pubkey::find_program_address(authority_seeds, program_id); - - if authority_address != *authority_info.key { - msg!( - "Transfer SPL Token with Authority PDA: {:?} was requested while PDA: {:?} was expected", - authority_info.key, - authority_address - ); - return Err(ProgramError::InvalidSeeds); - } - - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); - // for previous instruction compatibility we do not use transfer_checked() here. - #[allow(deprecated)] - let transfer_instruction = spl_token_2022::instruction::transfer( - spl_token_program_id, - source_info.key, - destination_info.key, - authority_info.key, - &[], - amount, - ) - .unwrap(); - - let mut signers_seeds = authority_seeds.to_vec(); - let bump = &[bump_seed]; - signers_seeds.push(bump); - - invoke_signed( - &transfer_instruction, - &[ - spl_token_info.clone(), - authority_info.clone(), - source_info.clone(), - destination_info.clone(), - ], - &[&signers_seeds[..]], - )?; - - Ok(()) -} - /// Transfers SPL Tokens checked from a token account owned by the provided PDA /// authority with seeds pub fn transfer_spl_tokens_signed_checked<'a>( @@ -347,7 +135,7 @@ pub fn transfer_spl_tokens_signed_checked<'a>( return Err(ProgramError::InvalidSeeds); } - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); + let spl_token_program_id = spl_token_info.owner; let mut transfer_instruction = spl_token_2022::instruction::transfer_checked( spl_token_program_id, @@ -412,57 +200,6 @@ pub fn transfer_spl_tokens_signed_checked<'a>( Ok(()) } -/// Burns SPL Tokens from a token account owned by the provided PDA authority -/// with seeds -pub fn burn_spl_tokens_signed<'a>( - token_account_info: &AccountInfo<'a>, - token_mint_info: &AccountInfo<'a>, - authority_info: &AccountInfo<'a>, - authority_seeds: &[&[u8]], - program_id: &Pubkey, - amount: u64, - spl_token_info: &AccountInfo<'a>, -) -> ProgramResult { - let (authority_address, bump_seed) = Pubkey::find_program_address(authority_seeds, program_id); - - if authority_address != *authority_info.key { - msg!( - "Burn SPL Token with Authority PDA: {:?} was requested while PDA: {:?} was expected", - authority_info.key, - authority_address - ); - return Err(ProgramError::InvalidSeeds); - } - - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); - let burn_ix = spl_token_2022::instruction::burn( - spl_token_program_id, - token_account_info.key, - token_mint_info.key, - authority_info.key, - &[], - amount, - ) - .unwrap(); - - let mut signers_seeds = authority_seeds.to_vec(); - let bump = &[bump_seed]; - signers_seeds.push(bump); - - invoke_signed( - &burn_ix, - &[ - spl_token_info.clone(), - token_account_info.clone(), - token_mint_info.clone(), - authority_info.clone(), - ], - &[&signers_seeds[..]], - )?; - - Ok(()) -} - /// Asserts the given account_info represents a valid SPL Token account which is /// initialized and belongs to spl_token program pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<()> { @@ -483,11 +220,6 @@ pub fn assert_is_valid_spl_token_account(account_info: &AccountInfo) -> Result<( Ok(()) } -/// Checks if the given account_info is spl-token token account -pub fn is_spl_token_account(account_info: &AccountInfo) -> bool { - assert_is_valid_spl_token_account(account_info).is_ok() -} - /// Asserts the given mint_info represents a valid SPL Token Mint account which /// is initialized and belongs to spl_token program pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<()> { @@ -515,33 +247,6 @@ pub fn assert_is_valid_spl_token_mint(mint_info: &AccountInfo) -> Result<()> { Ok(()) } -/// Checks if the given account_info is be spl-token mint account -pub fn is_spl_token_mint(mint_info: &AccountInfo) -> bool { - assert_is_valid_spl_token_mint(mint_info).is_ok() -} - -/// Computationally cheap method to get mint from a token account -/// It reads mint without deserializing full account data -pub fn get_spl_token_mint(token_account_info: &AccountInfo) -> Result { - assert_is_valid_spl_token_account(token_account_info)?; - - // TokeAccount layout: mint(32), owner(32), amount(8), ... - let data = token_account_info.try_borrow_data()?; - let mint_data = array_ref![data, 0, 32]; - Ok(Pubkey::new_from_array(*mint_data)) -} - -/// Computationally cheap method to get owner from a token account -/// It reads owner without deserializing full account data -pub fn get_spl_token_owner(token_account_info: &AccountInfo) -> Result { - assert_is_valid_spl_token_account(token_account_info)?; - - // TokeAccount layout: mint(32), owner(32), amount(8) - let data = token_account_info.try_borrow_data()?; - let owner_data = array_ref![data, 32, 32]; - Ok(Pubkey::new_from_array(*owner_data)) -} - /// Computationally cheap method to just get supply from a mint without /// unpacking the whole object pub fn get_spl_token_mint_supply(mint_info: &AccountInfo) -> Result { @@ -554,97 +259,6 @@ pub fn get_spl_token_mint_supply(mint_info: &AccountInfo) -> Result { Ok(u64::from_le_bytes(*bytes)) } -/// Computationally cheap method to just get authority from a mint without -/// unpacking the whole object -pub fn get_spl_token_mint_authority(mint_info: &AccountInfo) -> Result> { - assert_is_valid_spl_token_mint(mint_info)?; - // In token program, 36, 8, 1, 1 is the layout, where the first 36 is authority. - let data = mint_info.try_borrow_data().unwrap(); - let bytes = array_ref![data, 0, 36]; - - Ok(unpack_coption_pubkey(bytes)?) -} - -/// Asserts current mint authority matches the given authority and it's signer -/// of the transaction -pub fn assert_spl_token_mint_authority_is_signer( - mint_info: &AccountInfo, - mint_authority_info: &AccountInfo, -) -> Result<()> { - let mint_authority = get_spl_token_mint_authority(mint_info)?; - - if mint_authority.is_none() { - return Err(TokenVoterError::MintHasNoAuthority.into()); - } - - if !mint_authority.contains(mint_authority_info.key) { - return Err(TokenVoterError::InvalidMintAuthority.into()); - } - - if !mint_authority_info.is_signer { - return Err(TokenVoterError::MintAuthorityMustSign.into()); - } - - Ok(()) -} - -/// Asserts current token owner matches the given owner and it's signer of the -/// transaction -pub fn assert_spl_token_owner_is_signer( - token_info: &AccountInfo, - token_owner_info: &AccountInfo, -) -> Result<()> { - let token_owner = get_spl_token_owner(token_info)?; - - if token_owner != *token_owner_info.key { - return Err(TokenVoterError::InvalidTokenOwner.into()); - } - - if !token_owner_info.is_signer { - return Err(TokenVoterError::TokenOwnerMustSign.into()); - } - - Ok(()) -} - -/// Sets spl-token account (Mint or TokenAccount) authority -pub fn set_spl_token_account_authority<'a>( - account_info: &AccountInfo<'a>, - account_authority: &AccountInfo<'a>, - new_account_authority: &Pubkey, - authority_type: AuthorityType, - spl_token_info: &AccountInfo<'a>, -) -> Result<()> { - let spl_token_program_id = &get_spl_token_program_id(spl_token_info); - let set_authority_ix = spl_token_2022::instruction::set_authority( - spl_token_program_id, - account_info.key, - Some(new_account_authority), - authority_type, - account_authority.key, - &[], - )?; - - invoke( - &set_authority_ix, - &[ - account_info.clone(), - account_authority.clone(), - spl_token_info.clone(), - ], - )?; - - Ok(()) -} - -fn get_spl_token_program_id(spl_token_info: &AccountInfo) -> Pubkey { - if is_spl_token_2022(spl_token_info.key) { - spl_token_2022::id() - } else { - spl_token::id() - } -} - /// Computationally cheap method to just get supply off a mint without unpacking whole object pub fn get_mint_decimals(account_info: &AccountInfo) -> Result { // In token program, 36, 8, 1, 1, is the layout, where the first 1 is decimals u8. From 1a9d74739a27a86d3eaf7082acc628977eb0380a Mon Sep 17 00:00:00 2001 From: crypt0miester Date: Sat, 1 Jun 2024 15:12:02 +0400 Subject: [PATCH 11/11] add fixes to use spl-goverenance from crates, and remove token-haver --- Anchor.toml | 1 - Cargo.lock | 1130 +++++------------ programs/token-haver/Cargo.toml | 31 - programs/token-haver/Xargo.toml | 2 - programs/token-haver/readme.md | 6 - programs/token-haver/src/error.rs | 28 - .../src/instructions/configure_mints.rs | 73 -- .../src/instructions/create_registrar.rs | 83 -- .../create_voter_weight_record.rs | 46 - programs/token-haver/src/instructions/mod.rs | 11 - .../update_voter_weight_record.rs | 60 - programs/token-haver/src/lib.rs | 43 - .../src/state/max_voter_weight_record.rs | 96 -- programs/token-haver/src/state/mod.rs | 7 - programs/token-haver/src/state/registrar.rs | 76 -- .../src/state/voter_weight_record.rs | 110 -- programs/token-haver/src/tools/anchor.rs | 1 - programs/token-haver/src/tools/mod.rs | 1 - programs/token-haver/tests/configure_mints.rs | 297 ----- .../token-haver/tests/create_registrar.rs | 180 --- .../tests/create_voter_weight_record.rs | 66 - .../tests/fixtures/spl_governance.so | Bin 673864 -> 0 bytes .../tests/program_test/governance_test.rs | 406 ------ .../token-haver/tests/program_test/mod.rs | 4 - .../tests/program_test/program_test_bench.rs | 324 ----- .../tests/program_test/token_haver_test.rs | 297 ----- .../token-haver/tests/program_test/tools.rs | 80 -- .../tests/update_voter_weight_record.rs | 202 --- programs/token-voter/Cargo.toml | 6 +- .../src/instructions/close_voter.rs | 3 +- .../token-voter/src/instructions/withdraw.rs | 2 +- programs/token-voter/src/tools/spl_token.rs | 15 +- programs/token-voter/tests/cast_token_vote.rs | 21 +- programs/token-voter/tests/close_voter.rs | 4 +- .../tests/configure_voter_weights.rs | 3 +- .../tests/create_max_voter_weight_record.rs | 3 +- .../token-voter/tests/create_registrar.rs | 2 +- programs/token-voter/tests/deposit.rs | 6 +- .../tests/fixtures/spl_governance_2022.so | Bin 739288 -> 0 bytes .../tests/program_test/governance_test.rs | 100 +- programs/token-voter/tests/withdraw.rs | 4 +- 41 files changed, 363 insertions(+), 3467 deletions(-) delete mode 100644 programs/token-haver/Cargo.toml delete mode 100644 programs/token-haver/Xargo.toml delete mode 100644 programs/token-haver/readme.md delete mode 100644 programs/token-haver/src/error.rs delete mode 100644 programs/token-haver/src/instructions/configure_mints.rs delete mode 100644 programs/token-haver/src/instructions/create_registrar.rs delete mode 100644 programs/token-haver/src/instructions/create_voter_weight_record.rs delete mode 100644 programs/token-haver/src/instructions/mod.rs delete mode 100644 programs/token-haver/src/instructions/update_voter_weight_record.rs delete mode 100644 programs/token-haver/src/lib.rs delete mode 100644 programs/token-haver/src/state/max_voter_weight_record.rs delete mode 100644 programs/token-haver/src/state/mod.rs delete mode 100644 programs/token-haver/src/state/registrar.rs delete mode 100644 programs/token-haver/src/state/voter_weight_record.rs delete mode 100644 programs/token-haver/src/tools/anchor.rs delete mode 100644 programs/token-haver/src/tools/mod.rs delete mode 100644 programs/token-haver/tests/configure_mints.rs delete mode 100644 programs/token-haver/tests/create_registrar.rs delete mode 100644 programs/token-haver/tests/create_voter_weight_record.rs delete mode 100755 programs/token-haver/tests/fixtures/spl_governance.so delete mode 100644 programs/token-haver/tests/program_test/governance_test.rs delete mode 100644 programs/token-haver/tests/program_test/mod.rs delete mode 100644 programs/token-haver/tests/program_test/program_test_bench.rs delete mode 100644 programs/token-haver/tests/program_test/token_haver_test.rs delete mode 100644 programs/token-haver/tests/program_test/tools.rs delete mode 100644 programs/token-haver/tests/update_voter_weight_record.rs delete mode 100755 programs/token-voter/tests/fixtures/spl_governance_2022.so diff --git a/Anchor.toml b/Anchor.toml index 45cf47b5..4e303a40 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -12,7 +12,6 @@ nft_voter = "GnftV5kLjd67tvHpNGyodwWveEKivz3ZWvvE3Z4xi2iw" gateway = "GgathUhdrCWRHowoRKACjgWhYHfxCEdBi5ViqYN6HVxk" solana-gateway-program = "gatem74V238djXdzWnJf94Wo1DcnuGkfijbf3AuBhfs" token_voter = "3JhBg9bSPcfWGFa3t8LH7ooVtrjm45yCkHpxYXMXstUM" -token-haver = "vo65JQC6U8HCDPfoJxRrr17n7RZ5fKdfyjHm3erHJ2V" [registry] url = "https://anchor.projectserum.com" diff --git a/Cargo.lock b/Cargo.lock index b12bce33..fc16f113 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -14,9 +14,9 @@ dependencies = [ [[package]] name = "addr2line" -version = "0.21.0" +version = "0.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" +checksum = "6e4503c46a5c0c7844e948c9a4d6acd9f50cccb4de1c48eb9e291ea17470c678" dependencies = [ "gimli", ] @@ -117,90 +117,38 @@ dependencies = [ "alloc-no-stdlib", ] -[[package]] -name = "anchor-attribute-access-control" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" -dependencies = [ - "anchor-syn 0.26.0", - "anyhow", - "proc-macro2", - "quote", - "regex", - "syn 1.0.109", -] - [[package]] name = "anchor-attribute-access-control" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd7368e171b3a317885dc08ec0f74eed9d0ad6c726cc819593aed81440dca926" dependencies = [ - "anchor-syn 0.30.0", + "anchor-syn", "proc-macro2", "quote", "syn 1.0.109", ] -[[package]] -name = "anchor-attribute-account" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bcd731f21048a032be27c7791701120e44f3f6371358fc4261a7f716283d29" -dependencies = [ - "anchor-syn 0.26.0", - "anyhow", - "bs58 0.4.0", - "proc-macro2", - "quote", - "rustversion", - "syn 1.0.109", -] - [[package]] name = "anchor-attribute-account" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f527df85a8cba3f2bea04e46ed71b66e525ea378c7fec538aa205f4520b73e31" dependencies = [ - "anchor-syn 0.30.0", + "anchor-syn", "bs58 0.5.1", "proc-macro2", "quote", "syn 1.0.109", ] -[[package]] -name = "anchor-attribute-constant" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" -dependencies = [ - "anchor-syn 0.26.0", - "proc-macro2", - "syn 1.0.109", -] - [[package]] name = "anchor-attribute-constant" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3eb1dc1845cf8636c2e046a274ca074dabd3884ac8ed11cc4ed64b7e8ef5a318" dependencies = [ - "anchor-syn 0.30.0", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-error" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" -dependencies = [ - "anchor-syn 0.26.0", - "proc-macro2", + "anchor-syn", "quote", "syn 1.0.109", ] @@ -211,20 +159,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f382e41514c59a77ffa7bb1a47df9a0359564a749b6934485c742c11962e540" dependencies = [ - "anchor-syn 0.30.0", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-event" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" -dependencies = [ - "anchor-syn 0.26.0", - "anyhow", - "proc-macro2", + "anchor-syn", "quote", "syn 1.0.109", ] @@ -235,34 +170,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "473a122aeed3f6b666438236338d2ef7833ee5fdc5688e1baa80185d61088a53" dependencies = [ - "anchor-syn 0.30.0", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-interface" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6700a6f5c888a9c33fe8afc0c64fd8575fa28d05446037306d0f96102ae4480" -dependencies = [ - "anchor-syn 0.26.0", - "anyhow", - "heck 0.3.3", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-attribute-program" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" -dependencies = [ - "anchor-syn 0.26.0", - "anyhow", + "anchor-syn", "proc-macro2", "quote", "syn 1.0.109", @@ -275,7 +183,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f88c7ffe2eb40aeac43ffd0d74a6671581158aedfaa0552330a2ef92fa5c889" dependencies = [ "anchor-lang-idl", - "anchor-syn 0.30.0", + "anchor-syn", "anyhow", "bs58 0.5.1", "heck 0.3.3", @@ -285,39 +193,13 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "anchor-attribute-state" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" -dependencies = [ - "anchor-syn 0.26.0", - "anyhow", - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "anchor-derive-accounts" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" -dependencies = [ - "anchor-syn 0.26.0", - "anyhow", - "proc-macro2", - "quote", - "syn 1.0.109", -] - [[package]] name = "anchor-derive-accounts" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed9b97c99dcec135aae0ff908c14bcfcd3e78cfc16a0c6f245135038f0e6d390" dependencies = [ - "anchor-syn 0.30.0", + "anchor-syn", "quote", "syn 1.0.109", ] @@ -328,7 +210,7 @@ version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbece98f6ad9c37070edc0841326c9623a249346cd74f433e7cef69b14f7f31d" dependencies = [ - "anchor-syn 0.30.0", + "anchor-syn", "borsh-derive-internal 0.10.3", "proc-macro2", "quote", @@ -346,43 +228,19 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "anchor-lang" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662ceafe667448ee4199a4be2ee83b6bb76da28566eee5cea05f96ab38255af8" -dependencies = [ - "anchor-attribute-access-control 0.26.0", - "anchor-attribute-account 0.26.0", - "anchor-attribute-constant 0.26.0", - "anchor-attribute-error 0.26.0", - "anchor-attribute-event 0.26.0", - "anchor-attribute-interface", - "anchor-attribute-program 0.26.0", - "anchor-attribute-state", - "anchor-derive-accounts 0.26.0", - "arrayref", - "base64 0.13.1", - "bincode", - "borsh 0.9.3", - "bytemuck", - "solana-program", - "thiserror", -] - [[package]] name = "anchor-lang" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e41feb9c1cd9f4b0fad1c004fc8f289183f3ce27e9db38fa6e434470c716fb1e" dependencies = [ - "anchor-attribute-access-control 0.30.0", - "anchor-attribute-account 0.30.0", - "anchor-attribute-constant 0.30.0", - "anchor-attribute-error 0.30.0", - "anchor-attribute-event 0.30.0", - "anchor-attribute-program 0.30.0", - "anchor-derive-accounts 0.30.0", + "anchor-attribute-access-control", + "anchor-attribute-account", + "anchor-attribute-constant", + "anchor-attribute-error", + "anchor-attribute-event", + "anchor-attribute-program", + "anchor-derive-accounts", "anchor-derive-serde", "anchor-derive-space", "anchor-lang-idl", @@ -402,57 +260,26 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b29da81eae478b1bb846749b06b8a2cb9c6f9ed26ca793b0c916793fdf36adab" dependencies = [ - "anchor-syn 0.30.0", + "anchor-syn", "anyhow", "regex", "serde", "serde_json", ] -[[package]] -name = "anchor-spl" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f32390ce8356f54c0f0245ea156f8190717e37285b8bf4f406a613dc4b954cde" -dependencies = [ - "anchor-lang 0.26.0", - "solana-program", - "spl-associated-token-account 1.1.3", - "spl-token 3.5.0", -] - [[package]] name = "anchor-spl" version = "0.30.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0dcee54a30b27ea8317ca647759b5d9701a8c7caaaa0c922c6d3c306a7278a7a" dependencies = [ - "anchor-lang 0.30.0", + "anchor-lang", "spl-associated-token-account 3.0.2", - "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-pod 0.2.2", "spl-token 4.0.0", - "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-group-interface 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-metadata-interface 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "anchor-syn" -version = "0.26.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0418bcb5daac3b8cb1b60d8fdb1d468ca36f5509f31fb51179326fae1028fdcc" -dependencies = [ - "anyhow", - "bs58 0.3.1", - "heck 0.3.3", - "proc-macro2", - "proc-macro2-diagnostics", - "quote", - "serde", - "serde_json", - "sha2 0.9.9", - "syn 1.0.109", - "thiserror", + "spl-token-2022 3.0.2", + "spl-token-group-interface 0.2.3", + "spl-token-metadata-interface 0.3.3", ] [[package]] @@ -500,9 +327,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.83" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25bdb32cbbdce2b519a9cd7df3a678443100e265d5e25ca763b7572a5104f5f3" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "aquamarine" @@ -711,9 +538,9 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c90a406b4495d129f00461241616194cb8a032c8d1c53c657f0961d5f8e0498" +checksum = "cd066d0b4ef8ecb03a55319dc13aa6910616d0f44008a045bb1835af830abff5" dependencies = [ "brotli", "flate2", @@ -740,7 +567,7 @@ checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -762,9 +589,9 @@ checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "backtrace" -version = "0.3.71" +version = "0.3.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b05800d2e817c8b3b4b54abd461726265fa9789ae34330622f2db9ee696f9d" +checksum = "17c6a35df3749d2e8bb1b7b21a976d82b15548788d2735b9d82f329268f71a11" dependencies = [ "addr2line", "cc", @@ -893,11 +720,11 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbe5b10e214954177fb1dc9fbd20a1a2608fe99e6c832033bdc7cea287a20d77" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" dependencies = [ - "borsh-derive 1.5.0", + "borsh-derive 1.5.1", "cfg_aliases", ] @@ -929,15 +756,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.0" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d7a8646f94ab393e43e8b35a2558b1624bed28b97ee09c5d15456e3c9463f46d" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" dependencies = [ "once_cell", "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", "syn_derive", ] @@ -998,20 +825,14 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.0" +version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6221fe77a248b9117d431ad93761222e1cf8ff282d9d1d5d9f53d6299a1cf76" +checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] -[[package]] -name = "bs58" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" - [[package]] name = "bs58" version = "0.4.0" @@ -1045,22 +866,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.15.0" +version = "1.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" +checksum = "78834c15cb5d5efe3452d58b1e8ba890dd62d21907f867f383358198e56ebca5" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1113,14 +934,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" dependencies = [ "serde", - "toml 0.8.12", + "toml 0.8.13", ] [[package]] name = "cc" -version = "1.0.97" +version = "1.0.98" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "099a5357d84c4c61eb35fc8eafa9a79a902c2f76911e5747ced4e032edd8d9b4" +checksum = "41c270e7540d725e65ac7f1b212ac8ce349719624d7bcff99f8e2e488e8cf03f" dependencies = [ "jobserver", "libc", @@ -1135,9 +956,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cfg_aliases" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" [[package]] name = "chrono" @@ -1306,18 +1127,18 @@ dependencies = [ [[package]] name = "crc32fast" -version = "1.4.0" +version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3855a8a784b474f333699ef2bbca9db2c4a1f6d9088a90a2d25b1eb53111eaa" +checksum = "a97769d94ddab943e4510d138150169a2758b5ef3eb191a9ee688de3e23ef7b3" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.12" +version = "0.5.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" +checksum = "33480d6946193aa8033910124896ca395333cae7e2d1113d1fef6c3272217df2" dependencies = [ "crossbeam-utils", ] @@ -1343,9 +1164,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -1398,9 +1219,9 @@ dependencies = [ [[package]] name = "darling" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391" +checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1" dependencies = [ "darling_core", "darling_macro", @@ -1408,27 +1229,27 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f" +checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.62", + "strsim 0.11.1", + "syn 2.0.66", ] [[package]] name = "darling_macro" -version = "0.20.8" +version = "0.20.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f" +checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178" dependencies = [ "darling_core", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1576,7 +1397,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1599,7 +1420,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1663,9 +1484,9 @@ dependencies = [ [[package]] name = "either" -version = "1.11.0" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2" +checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b" [[package]] name = "encode_unicode" @@ -1699,7 +1520,7 @@ checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1712,7 +1533,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1724,7 +1545,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1882,7 +1703,7 @@ checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -1964,9 +1785,9 @@ dependencies = [ [[package]] name = "gimli" -version = "0.28.1" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "40ecd4077b5ae9fd2e9e169b102c6c330d0605168eb0e8bf79952b256dbefffd" [[package]] name = "goblin" @@ -1983,8 +1804,8 @@ dependencies = [ name = "gpl-civic-gateway" version = "0.2.0" dependencies = [ - "anchor-lang 0.30.0", - "anchor-spl 0.30.0", + "anchor-lang", + "anchor-spl", "arrayref", "borsh 0.10.3", "enum_dispatch", @@ -1996,10 +1817,10 @@ dependencies = [ "solana-program", "solana-program-test", "solana-sdk", - "spl-governance 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance", + "spl-governance-addin-api", "spl-governance-addin-mock", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-tools", "spl-token 4.0.0", ] @@ -2007,8 +1828,8 @@ dependencies = [ name = "gpl-nft-voter" version = "0.3.0" dependencies = [ - "anchor-lang 0.30.0", - "anchor-spl 0.30.0", + "anchor-lang", + "anchor-spl", "arrayref", "borsh 0.10.3", "itertools", @@ -2016,8 +1837,8 @@ dependencies = [ "solana-program", "solana-program-test", "solana-sdk", - "spl-governance 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance", + "spl-governance-tools", "spl-token 4.0.0", ] @@ -2025,34 +1846,18 @@ dependencies = [ name = "gpl-realm-voter" version = "0.0.1" dependencies = [ - "anchor-lang 0.30.0", - "anchor-spl 0.30.0", + "anchor-lang", + "anchor-spl", "arrayref", "borsh 0.10.3", "solana-program", "solana-program-test", "solana-sdk", - "spl-governance 4.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance", + "spl-governance-tools", "spl-token 4.0.0", ] -[[package]] -name = "gpl-token-haver" -version = "0.0.1" -dependencies = [ - "anchor-lang 0.26.0", - "anchor-spl 0.26.0", - "arrayref", - "borsh 0.9.3", - "solana-program", - "solana-program-test", - "solana-sdk", - "spl-governance 3.1.1", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token 3.5.0", -] - [[package]] name = "h2" version = "0.3.26" @@ -2373,9 +2178,9 @@ dependencies = [ [[package]] name = "instant" -version = "0.1.12" +version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" +checksum = "e0242819d153cba4b4b05a5a8f2a7e9bbf97b6055b2a002b395c96b5ff3c0222" dependencies = [ "cfg-if", ] @@ -2451,9 +2256,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.154" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae743338b92ff9146ce83992f766a31066a91a8c84a45e0e9f21e7cf6de6d346" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libredox" @@ -2527,9 +2332,9 @@ dependencies = [ [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" [[package]] name = "lock_api" @@ -2635,9 +2440,9 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.2" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d811f3e15f28568be3407c8e7fdb6514c1cda3cb30683f15b6a1a1dc4ea14a7" +checksum = "87dfd01fe195c66b572b37921ad8803d010623c0aca821bea2302239d155cdae" dependencies = [ "adler", ] @@ -2836,7 +2641,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -2949,7 +2754,7 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -2961,7 +2766,7 @@ dependencies = [ "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -2972,9 +2777,9 @@ checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" [[package]] name = "object" -version = "0.32.2" +version = "0.35.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "b8ec7ab813848ba4522158d5517a6093db1ded27575b070f4177b8d12b41db5e" dependencies = [ "memchr", ] @@ -3056,9 +2861,9 @@ dependencies = [ [[package]] name = "parking_lot" -version = "0.12.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e4af0ca4f6caed20e900d564c242b8e5d4903fdacf31d3daf527b66fe6f42fb" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -3142,7 +2947,7 @@ checksum = "2f38a4412a78282e09a2cf38d195ea5420d15ba0602cb375210efbc877243965" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -3300,26 +3105,13 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.82" +version = "1.0.84" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ad3d49ab951a01fbaafe34f2ec74122942fe18a3f9814c3268f1bb72042131b" +checksum = "ec96c6a92621310b51366f1e28d05ef11489516e93be030060e5fc12024a49d6" dependencies = [ "unicode-ident", ] -[[package]] -name = "proc-macro2-diagnostics" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "version_check", - "yansi", -] - [[package]] name = "qstring" version = "0.7.2" @@ -3337,7 +3129,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -3749,9 +3541,9 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.16" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "092474d1a01ea8278f69e6a358998405fae5b8b963ddaeb2b0b04a128bf1dfb0" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" @@ -3800,7 +3592,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -3853,9 +3645,9 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "780f1cebed1629e4753a1a38a3c72d30b97ec044f0aef68cb26650a3c5cf363c" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] @@ -3871,13 +3663,13 @@ dependencies = [ [[package]] name = "serde_derive" -version = "1.0.201" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5e405930b9796f1c00bee880d03fc7e0bb4b9a11afc776885ffe84320da2865" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -3893,9 +3685,9 @@ dependencies = [ [[package]] name = "serde_spanned" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" dependencies = [ "serde", ] @@ -3931,7 +3723,7 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -4077,9 +3869,9 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "142161f13c328e7807fe98fb8f6eaaa5045a8eaf4492414aa81254870c4fc8a0" +checksum = "52346da8fbbac45fdfbb9c09f7a4e263fabd13f401352e1feedc55e1178a8ba2" dependencies = [ "Inflector", "base64 0.21.7", @@ -4102,9 +3894,9 @@ dependencies = [ [[package]] name = "solana-accounts-db" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e8b4b15e353d5f0e0ddd77966c6f01b296bd83569af455da5fd9329356ff642" +checksum = "9185bf67cd460369b37e9cbd8bcb6e6600a10186820c38276c0bb34ff976dbd9" dependencies = [ "arrayref", "bincode", @@ -4163,9 +3955,9 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c4eef9fc8aa3ff804dbf17766ab2d2fe38561adc8b521705faa782c18a108d8" +checksum = "5b9d6b9faa090d38028778dbefe6e9b8cf98e2152edd03a66ad97c94c6f89c69" dependencies = [ "bincode", "bytemuck", @@ -4184,11 +3976,11 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13a4cbe27e78987b706caf90cbd16da9da3955c09a660b8107a96c2cb32f1124" +checksum = "973def28e8085a6a005eeb92bfd002da737052e170f1cc0bb58be402b9731d7a" dependencies = [ - "borsh 1.5.0", + "borsh 1.5.1", "futures", "solana-banks-interface", "solana-program", @@ -4201,9 +3993,9 @@ dependencies = [ [[package]] name = "solana-banks-interface" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "741279a09bf5ea1a3d17e591db7b189e163722e5c46423308c6a6165bea5e74d" +checksum = "47daecbd489590c74db838da88040f7e2416bca43e599efb43dad79dc2e673ad" dependencies = [ "serde", "solana-sdk", @@ -4212,9 +4004,9 @@ dependencies = [ [[package]] name = "solana-banks-server" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f66768544951feb91c3470e255d4613295b5cc5a58a9cc6a4207ab9a0178cfe9" +checksum = "01158f256f774cdf9055ebc6e9e3fa6f3fc4ef5045d84058c12b95f15fbc6a5a" dependencies = [ "bincode", "crossbeam-channel", @@ -4232,9 +4024,9 @@ dependencies = [ [[package]] name = "solana-bpf-loader-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60e9dd5e42193260cca0794bf4ab9e248f44b3d9710041f241b130d26ed682bc" +checksum = "641c08bd15950e54b4998db512bc4af1c16cb2c3f93d99b6497794146589b8cb" dependencies = [ "bincode", "byteorder", @@ -4251,9 +4043,9 @@ dependencies = [ [[package]] name = "solana-bucket-map" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a7b34296d69867253671a71a2231b8d5b4a810bd7a5c1c603e7b542832d5980" +checksum = "abde5d342d1132da622cf6bbcce3319594645b80ffb65f557fe8ae421df2f72a" dependencies = [ "bv", "bytemuck", @@ -4269,9 +4061,9 @@ dependencies = [ [[package]] name = "solana-clap-utils" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8e9f61034a61db538a41700b6df0b4b9f0392038adaf780150481923ff94356" +checksum = "bafd11f1614edd414adb414b96a481152b01ac45c14c3ff56fc757412698b228" dependencies = [ "chrono", "clap 2.34.0", @@ -4286,9 +4078,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c11246ea0930c3e95dc489d42f1020ea423a3daced137904d42ecc10a838436" +checksum = "2228beb53090556c65a82251b904ae197f4979b34e08ab03303448c1ac9f609f" dependencies = [ "dirs-next", "lazy_static", @@ -4302,9 +4094,9 @@ dependencies = [ [[package]] name = "solana-cli-output" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea94deca7268b61a245429a7798f3e673baccb5cee5909e7de403b322d4c130a" +checksum = "70f87dd426a280c531c48769e889ecc1af77bbe72407dd91b03095cb833bbe94" dependencies = [ "Inflector", "base64 0.21.7", @@ -4324,14 +4116,14 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "solana-vote-program", - "spl-memo 4.0.0", + "spl-memo", ] [[package]] name = "solana-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13f2bd5a986d7cac1b4ffb4344413b70b6f21fd7ffa92a985911756b4ac7682a" +checksum = "522922d51cc1fd3f0a6dd9ed0a8939f7ff46f5ebaa3a6d7eee3cd2516e6ac9e6" dependencies = [ "async-trait", "bincode", @@ -4362,9 +4154,9 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca100b2bdd7e455f5f0b9791bc204dacd684a0373ad1032697dbad43f34e527f" +checksum = "dfefe6da1767534c45c61ee11bb796c485ecaa3b224ea146e47a7695368480eb" dependencies = [ "solana-program-runtime", "solana-sdk", @@ -4372,9 +4164,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "970d28779e92a11e32a89ee453edc7d89394d3a68d8c4b75ef0ffb833944c588" +checksum = "2010ba6fe2a1c4270ca3d3ef23ebfd893e3d2c980b9c0fc04451c4ce2f6b3deb" dependencies = [ "bincode", "chrono", @@ -4386,9 +4178,9 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7d0022ded19dca32ced5528c6a050596877fc8b9a89322d876960a89466e1b" +checksum = "0acaf8e98f3f30596d73173183a80d7f83e23df1429a889a68cfe7be69abe39b" dependencies = [ "async-trait", "bincode", @@ -4408,9 +4200,9 @@ dependencies = [ [[package]] name = "solana-cost-model" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd3c63699df1680535daee8e486bd496e2ec849c427de4b6a42d4f1b27430949" +checksum = "13c584432678c3e83550d419d0fa5fcdd3f5909b64e61ea7d2101f08d7a991e6" dependencies = [ "lazy_static", "log", @@ -4432,9 +4224,9 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35a0b24cc4d0ebd5fd45d6bd47bed3790f8a75ade67af8ff24a3d719a8bc93bc" +checksum = "2c00a6aca244dfa904e2c4a26406ba7b0987344ceaec932f3cda0b35eff0babc" dependencies = [ "block-buffer 0.10.4", "bs58 0.4.0", @@ -4457,14 +4249,14 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51600f4066d3663ab2981fd24e77a8c2e65f5d20ea71b550b853ca9ae40eee7f" +checksum = "bed58b27b9b8877893f69bc5cfd1c62e984315e0229d83cf8a32ad0933c0d6c9" dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -4473,7 +4265,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a11e5afc65ef1845214987e9724aa6406916d4a2d67ed66e4583cb75368bb645" dependencies = [ - "borsh 1.5.0", + "borsh 1.5.1", "num-derive 0.4.2", "num-traits", "solana-program", @@ -4482,9 +4274,9 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c566ebf0da216efc70054bf2d6d06c16fe44b63402c6f3bb04f6a88d8571d9b" +checksum = "e999b9a1a8f323981670f191a423db06e247d4aea4e19309191c42f88b8c98a2" dependencies = [ "log", "solana-measure", @@ -4495,9 +4287,9 @@ dependencies = [ [[package]] name = "solana-logger" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd79ef26804612173c95be8da84df3128d648173cf1f746de8f183ec8dbedd92" +checksum = "bee2daf61ae582edf9634adf8e5021faf002df0d3f69078ecbcd6c7b41bdf833" dependencies = [ "env_logger", "lazy_static", @@ -4506,9 +4298,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "300f716a5f1c2f4b562fb008a0cc7d7c0d889cff802a7f8177fdf28772ae1ed9" +checksum = "148512f384b82cf9e8bfe80503b688340d42a4cc17cfd572b88a6d803a488527" dependencies = [ "log", "solana-sdk", @@ -4516,9 +4308,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abf1705d52e4f123856725e1b3842cd4928b954ff62391a95af142a5adc58ac6" +checksum = "55d734099c26f81621bd1aaddb8788908e20fd7fac28fb00402d564964eae4ea" dependencies = [ "crossbeam-channel", "gethostname", @@ -4531,9 +4323,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f2634fd50743e2ca075e663e07b0bd5c2f94db0ac320ce5bc2022e0002d82d" +checksum = "563911bb92bc6ae3ba4e7d9930dc560c61333ee57f7ba0421abe0cab14982e72" dependencies = [ "bincode", "clap 3.2.25", @@ -4559,9 +4351,9 @@ checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" [[package]] name = "solana-perf" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0264d7093d44c239d9eb41beb6877b7b1eea5ad8809c93c1d9ab0c840ba390" +checksum = "b21bd999096d156dd122aed05eb4601fbc9dba016e229be72ba838aa5ff2a7df" dependencies = [ "ahash 0.8.7", "bincode", @@ -4588,9 +4380,9 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a5513a02d622ba89e76baf4b49d25ae20c2c2c623fced12b0d6dd7b8f23e006" +checksum = "4f4908f360900d0a1aa81c7bad7937c78f0825c3f08ff0b22f1de0e43e5946f2" dependencies = [ "ark-bn254", "ark-ec", @@ -4602,7 +4394,7 @@ dependencies = [ "blake3", "borsh 0.10.3", "borsh 0.9.3", - "borsh 1.5.0", + "borsh 1.5.1", "bs58 0.4.0", "bv", "bytemuck", @@ -4643,9 +4435,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64dc9f666a8e4f93166ce58eea9dfbf275e5cad461b2f1bbfa06538718dc3212" +checksum = "47c8ace7f999a8278351ea86ed93f57e7833cb65fb04167a9ba9ea593e995288" dependencies = [ "base64 0.21.7", "bincode", @@ -4671,9 +4463,9 @@ dependencies = [ [[package]] name = "solana-program-test" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2760112327ffce892f6a21030f7c9e4b6da3ded8c8eadf1dbfffcb5a754c61db" +checksum = "eeaef9ab295769e3ed53234ea9e3fa4537817fddb03fca5f64e9406c25fcdcb8" dependencies = [ "assert_matches", "async-trait", @@ -4701,9 +4493,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ffdcbdad685b87475a91909fdb442d2edfabc2870110580c7f0cf7eb7883f97" +checksum = "dfaebabf56720238919d8d1699211240cca485bda3b12f6189c737679a935912" dependencies = [ "crossbeam-channel", "futures-util", @@ -4726,9 +4518,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "056e909037b05097d2ff0181cb7e3d26876d8dff6d50701463a61e990cf84afd" +checksum = "85f868c2bf7591835705298dd4350c38a8e9de07e53109fa243ebc55bbd33f03" dependencies = [ "async-mutex", "async-trait", @@ -4753,9 +4545,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93a5e1ef891dca2cca907f7196b6a5d3b80af4183f2be0f981906b16711ff5d" +checksum = "01c9c928e5b6b1e37296e139c757695f9540e2d4f04794a1ae1915eba7076e68" dependencies = [ "lazy_static", "num_cpus", @@ -4763,9 +4555,9 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52c06eaf47d9a98ba22e890e68868f5d48c91e01268c541a53b5960288b617d6" +checksum = "32d9f47fb9de096edd536bb39c1a8383372acf719f3fd49242bfe332ea216c3b" dependencies = [ "console", "dialoguer", @@ -4782,9 +4574,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed1d4b6f1f4e3dab7509401e85edc1c1ac208c61819de90178e01cf162c9c051" +checksum = "9f2259b63faca1132e3a0c8b98438fb60e5d25897260dd3655bcf4ec8c6f2bf8" dependencies = [ "async-trait", "base64 0.21.7", @@ -4808,9 +4600,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31feddef24d3e0aab189571adea7f109639ef6179fcd3cd34ffc8c73d3409f1" +checksum = "b0aea25d581de77ba256b81f4ebd8d963b85ec01d70a74829365e85f6403d497" dependencies = [ "base64 0.21.7", "bs58 0.4.0", @@ -4830,9 +4622,9 @@ dependencies = [ [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1837728262063723c659e4b8c0acf0baa99cd38cb333511456465d2c9e654474" +checksum = "3ef5cbfb47707599ccb5734aa70b5161a2d437df54044021870be3f575eb0f1a" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4843,9 +4635,9 @@ dependencies = [ [[package]] name = "solana-runtime" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3480088ad0ffb701ada496f19754b4ff737e516c6b5f1231508e50ae2e0ea3" +checksum = "27c071752762034dc6292ce35aacd6fe96cac6e8be4994234dbf18eb7e6cdb53" dependencies = [ "aquamarine", "arrayref", @@ -4920,15 +4712,15 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f50cac89269a01235f6b421bc580132191f4df388f4265513e78fd00cf864dd" +checksum = "c50ec330850953d4971b052ff98c74a8e67e7618b4aed9f4971b8d3b68fcd1cd" dependencies = [ "assert_matches", "base64 0.21.7", "bincode", "bitflags 2.5.0", - "borsh 1.5.0", + "borsh 1.5.1", "bs58 0.4.0", "bytemuck", "byteorder", @@ -4975,15 +4767,15 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5cb099b2f9c0a65a6f23ced791325141cd68c27b04d11c04fef838a00f613861" +checksum = "95ef2ea49002d1bf52a4a8509570b2c3b88e7b6d0a131b11bbd637ca1e1df0ff" dependencies = [ "bs58 0.4.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -4994,9 +4786,9 @@ checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" [[package]] name = "solana-send-transaction-service" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0deed4fe8bb31ff178d8b7e8295bc81e6e1d704fc0e2c5565f58d9eb8feec89d" +checksum = "dbbe96c86deccb6383b9c4913137b194f8b6f3b4c9f0de60e2591d77ad848f31" dependencies = [ "crossbeam-channel", "log", @@ -5010,9 +4802,9 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea02d44b82ed0eb271871cf8a1b8179a0ab50f4f995e7d8ae691c1971bd0a0e" +checksum = "a518323d52d8c8bb8b1e30c02940e65528951f8dbcfe65decb9dd2ab0b90bfff" dependencies = [ "bincode", "log", @@ -5025,9 +4817,9 @@ dependencies = [ [[package]] name = "solana-streamer" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8a20843e8370adb3c04f47caa79ffdc92ae1bf078ad26530be1bca5d7bdd5d2" +checksum = "29de0561c0aa6249292a2602be31e812977ae223be031b3a9e0715d98fb19b06" dependencies = [ "async-channel", "bytes", @@ -5058,9 +4850,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01294e45b407b7d4c8ff546af6f60344efd6591cf162c88e231ee3ba2c544672" +checksum = "cd7bd272efd8a596aab47dbe000267859f701743d02615e71ead8ed22ff18564" dependencies = [ "bincode", "log", @@ -5072,9 +4864,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c74da8f36b89b28c47e5ba3bad5279ff3dfea5829154882845d4821fc76ff497" +checksum = "d20b7c9b7214fe50e2e72090f833f11e07f3b00ba69b57872b6adcf5479cdf32" dependencies = [ "bincode", "log", @@ -5087,9 +4879,9 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0f2fd4b4aeffa14b9c5be9913072ea8e72ca261254a65a999f3d2fd70e7a660" +checksum = "fcbfd83d8d7da758b10d6e1075322843dce591a75d15d611e9eec5508e9c7233" dependencies = [ "async-trait", "bincode", @@ -5111,9 +4903,9 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3efa0d30f78dbc74e795638b053dd6ec7230739301e7f0e06b586f7731fd25c8" +checksum = "0439563ffb7471a0b51446f0fff5c8b2108e31248bf7dbab8b9efaa2af3a4c27" dependencies = [ "Inflector", "base64 0.21.7", @@ -5128,7 +4920,7 @@ dependencies = [ "solana-account-decoder", "solana-sdk", "spl-associated-token-account 2.3.0", - "spl-memo 4.0.0", + "spl-memo", "spl-token 4.0.0", "spl-token-2022 1.0.0", "thiserror", @@ -5136,9 +4928,9 @@ dependencies = [ [[package]] name = "solana-udp-client" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32af58cadd37be19d04e0f3877104b8640bccc4be8ca1dbf431549b399b784c2" +checksum = "1160ce03865189e4c3327cc492aeacc8567863f195a269533d98f15485402b74" dependencies = [ "async-trait", "solana-connection-cache", @@ -5151,9 +4943,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42c7cef8aa9f1c633bf09dd91b8e635b6b30c40236652031b1800b245dc1bd02" +checksum = "fb25449b519a334103778e2fc1c5c0e3ea7862ae2c1ffe90fc82ce3c96058171" dependencies = [ "log", "rustc_version", @@ -5167,9 +4959,9 @@ dependencies = [ [[package]] name = "solana-vote" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12945ee508c751ffdce58f976be6e58a05529ce0032c1f7db76eed6a8d76b33c" +checksum = "26648e8f72dab5488a1b31ed59c9f71ffb1a58d8b323cdaaa25bfde5a5c82c0c" dependencies = [ "crossbeam-channel", "itertools", @@ -5186,9 +4978,9 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "725a39044d455c08fe83fca758e94e5ddfaa25f6e2e2cfd5c31d7afdcad8de38" +checksum = "78899849d1131b2fbbe9f826080cc18cec5598da63a77357642c9cd8b1a86a86" dependencies = [ "bincode", "log", @@ -5208,9 +5000,9 @@ dependencies = [ [[package]] name = "solana-zk-token-proof-program" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39263f3e47a160b9b67896f2225d56e6872905c066152cbe61f5fd201c52a6d2" +checksum = "f904d8cd4cdaf9c708237e59f9a54eabed6eb32c5082e459fe7b15b3d0895fe8" dependencies = [ "bytemuck", "num-derive 0.4.2", @@ -5222,9 +5014,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.18.12" +version = "1.18.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "630dc0b5f6250cf6a4c8b2bd3895283738915e83eba5453db20bb02b2527f302" +checksum = "5cafb3df56516086f65e2a08a8cd03f504236f3b5348299abd45415d1d18ba32" dependencies = [ "aes-gcm-siv", "base64 0.21.7", @@ -5290,22 +5082,6 @@ dependencies = [ "der", ] -[[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 0.3.3", - "num-traits", - "solana-program", - "spl-token 3.5.0", - "spl-token-2022 0.6.1", - "thiserror", -] - [[package]] name = "spl-associated-token-account" version = "2.3.0" @@ -5329,12 +5105,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2e688554bac5838217ffd1fab7845c573ff106b6336bf7d290db7c98d5a8efd" dependencies = [ "assert_matches", - "borsh 1.5.0", + "borsh 1.5.1", "num-derive 0.4.2", "num-traits", "solana-program", "spl-token 4.0.0", - "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-2022 3.0.2", "thiserror", ] @@ -5357,17 +5133,7 @@ checksum = "34d1814406e98b08c5cd02c1126f83fd407ad084adce0b05fda5730677822eac" dependencies = [ "bytemuck", "solana-program", - "spl-discriminator-derive 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spl-discriminator" -version = "0.2.2" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator-derive 0.2.0 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-discriminator-derive 0.2.0", ] [[package]] @@ -5378,7 +5144,7 @@ checksum = "07fd7858fc4ff8fb0e34090e41d7eb06a823e1057945c26d480bfc21d2338a93" dependencies = [ "quote", "spl-discriminator-syn 0.1.2", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -5388,18 +5154,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" dependencies = [ "quote", - "spl-discriminator-syn 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 2.0.62", -] - -[[package]] -name = "spl-discriminator-derive" -version = "0.2.0" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "quote", - "spl-discriminator-syn 0.2.0 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "syn 2.0.62", + "spl-discriminator-syn 0.2.0", + "syn 2.0.66", ] [[package]] @@ -5411,7 +5167,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.62", + "syn 2.0.66", "thiserror", ] @@ -5424,39 +5180,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.62", - "thiserror", -] - -[[package]] -name = "spl-discriminator-syn" -version = "0.2.0" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "proc-macro2", - "quote", - "sha2 0.10.8", - "syn 2.0.62", - "thiserror", -] - -[[package]] -name = "spl-governance" -version = "3.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7a42340af2f3334ee1ee718e6d68b939c98cab4ceb381429f952c72d68e1ebf" -dependencies = [ - "arrayref", - "bincode", - "borsh 0.9.3", - "num-derive 0.3.3", - "num-traits", - "serde", - "serde_derive", - "solana-program", - "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token 3.5.0", + "syn 2.0.66", "thiserror", ] @@ -5474,34 +5198,12 @@ dependencies = [ "serde", "serde_derive", "solana-program", - "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-addin-api", + "spl-governance-tools", "spl-token 4.0.0", "thiserror", ] -[[package]] -name = "spl-governance" -version = "4.0.0" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "arrayref", - "bincode", - "borsh 1.5.0", - "num-derive 0.4.2", - "num-traits", - "serde", - "serde_derive", - "solana-program", - "spl-governance-addin-api 0.1.4 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-governance-tools 0.1.4 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-token 4.0.1", - "spl-token-2022 3.0.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-transfer-hook-example", - "spl-transfer-hook-interface 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "thiserror", -] - [[package]] name = "spl-governance-addin-api" version = "0.1.4" @@ -5510,17 +5212,7 @@ checksum = "9dc1be90f8b71e336933fedbe17f645cd33d36e8451dfb6ce1210ef585dc73b6" dependencies = [ "borsh 0.10.3", "solana-program", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spl-governance-addin-api" -version = "0.1.4" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "borsh 1.5.0", - "solana-program", - "spl-governance-tools 0.1.4 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-governance-tools", ] [[package]] @@ -5537,8 +5229,8 @@ dependencies = [ "serde", "serde_derive", "solana-program", - "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance-addin-api", + "spl-governance-tools", "spl-token 4.0.0", "thiserror", ] @@ -5561,32 +5253,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "spl-governance-tools" -version = "0.1.4" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "arrayref", - "bincode", - "borsh 1.5.0", - "num-derive 0.4.2", - "num-traits", - "serde", - "serde_derive", - "solana-program", - "spl-token 4.0.1", - "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-memo" version = "4.0.0" @@ -5596,14 +5262,6 @@ dependencies = [ "solana-program", ] -[[package]] -name = "spl-memo" -version = "4.0.1" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "solana-program", -] - [[package]] name = "spl-pod" version = "0.1.1" @@ -5623,25 +5281,13 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "046ce669f48cf2eca1ec518916d8725596bfb655beb1c74374cf71dc6cb773c9" dependencies = [ - "borsh 1.5.0", + "borsh 1.5.1", "bytemuck", "solana-program", "solana-zk-token-sdk", "spl-program-error 0.4.1", ] -[[package]] -name = "spl-pod" -version = "0.2.2" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "borsh 1.5.0", - "bytemuck", - "solana-program", - "solana-zk-token-sdk", - "spl-program-error 0.4.0", -] - [[package]] name = "spl-program-error" version = "0.3.1" @@ -5655,18 +5301,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "spl-program-error" -version = "0.4.0" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "num-derive 0.4.2", - "num-traits", - "solana-program", - "spl-program-error-derive 0.4.0", - "thiserror", -] - [[package]] name = "spl-program-error" version = "0.4.1" @@ -5689,18 +5323,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.62", -] - -[[package]] -name = "spl-program-error-derive" -version = "0.4.0" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "proc-macro2", - "quote", - "sha2 0.10.8", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -5712,7 +5335,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -5737,23 +5360,10 @@ checksum = "cace91ba08984a41556efe49cbf2edca4db2f577b649da7827d3621161784bf8" dependencies = [ "bytemuck", "solana-program", - "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", "spl-program-error 0.4.1", - "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spl-tlv-account-resolution" -version = "0.6.3" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-program-error 0.4.0", - "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-type-length-value 0.4.3", ] [[package]] @@ -5786,38 +5396,6 @@ dependencies = [ "thiserror", ] -[[package]] -name = "spl-token" -version = "4.0.1" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive 0.4.2", - "num-traits", - "num_enum 0.7.2", - "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 0.3.3", - "num-traits", - "num_enum 0.5.11", - "solana-program", - "solana-zk-token-sdk", - "spl-memo 3.0.1", - "spl-token 3.5.0", - "thiserror", -] - [[package]] name = "spl-token-2022" version = "1.0.0" @@ -5832,7 +5410,7 @@ dependencies = [ "solana-program", "solana-security-txt", "solana-zk-token-sdk", - "spl-memo 4.0.0", + "spl-memo", "spl-pod 0.1.1", "spl-token 4.0.0", "spl-token-group-interface 0.1.0", @@ -5856,36 +5434,13 @@ dependencies = [ "solana-program", "solana-security-txt", "solana-zk-token-sdk", - "spl-memo 4.0.0", - "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-memo", + "spl-pod 0.2.2", "spl-token 4.0.0", - "spl-token-group-interface 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-metadata-interface 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-transfer-hook-interface 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror", -] - -[[package]] -name = "spl-token-2022" -version = "3.0.2" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "arrayref", - "bytemuck", - "num-derive 0.4.2", - "num-traits", - "num_enum 0.7.2", - "solana-program", - "solana-security-txt", - "solana-zk-token-sdk", - "spl-memo 4.0.1", - "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-token 4.0.1", - "spl-token-group-interface 0.2.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-token-metadata-interface 0.3.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-transfer-hook-interface 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-token-group-interface 0.2.3", + "spl-token-metadata-interface 0.3.3", + "spl-transfer-hook-interface 0.6.3", + "spl-type-length-value 0.4.3", "thiserror", ] @@ -5906,12 +5461,12 @@ dependencies = [ "solana-rpc-client-api", "solana-sdk", "spl-associated-token-account 3.0.2", - "spl-memo 4.0.0", + "spl-memo", "spl-token 4.0.0", - "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-group-interface 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-metadata-interface 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-transfer-hook-interface 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-2022 3.0.2", + "spl-token-group-interface 0.2.3", + "spl-token-metadata-interface 0.3.3", + "spl-transfer-hook-interface 0.6.3", "thiserror", ] @@ -5936,23 +5491,11 @@ checksum = "d419b5cfa3ee8e0f2386fd7e02a33b3ec8a7db4a9c7064a2ea24849dc4a273b6" dependencies = [ "bytemuck", "solana-program", - "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", "spl-program-error 0.4.1", ] -[[package]] -name = "spl-token-group-interface" -version = "0.2.3" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-program-error 0.4.0", -] - [[package]] name = "spl-token-metadata-interface" version = "0.2.0" @@ -5973,38 +5516,26 @@ version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "30179c47e93625680dabb620c6e7931bd12d62af390f447bc7beb4a3a9b5feee" dependencies = [ - "borsh 1.5.0", + "borsh 1.5.1", "solana-program", - "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", "spl-program-error 0.4.1", - "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spl-token-metadata-interface" -version = "0.3.3" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "borsh 1.5.0", - "solana-program", - "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-program-error 0.4.0", - "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-type-length-value 0.4.3", ] [[package]] name = "spl-transfer-hook-example" version = "0.6.0" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77ca876e51260503efeb9d00f38950369ed660b31394500083b20cb8005ef498" dependencies = [ "arrayref", "solana-program", - "spl-tlv-account-resolution 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-token-2022 3.0.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-transfer-hook-interface 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-tlv-account-resolution 0.6.3", + "spl-token-2022 3.0.2", + "spl-transfer-hook-interface 0.6.3", + "spl-type-length-value 0.4.3", ] [[package]] @@ -6032,26 +5563,11 @@ dependencies = [ "arrayref", "bytemuck", "solana-program", - "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", "spl-program-error 0.4.1", - "spl-tlv-account-resolution 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-type-length-value 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "spl-transfer-hook-interface" -version = "0.6.3" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "arrayref", - "bytemuck", - "solana-program", - "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-program-error 0.4.0", - "spl-tlv-account-resolution 0.6.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-type-length-value 0.4.3 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", + "spl-tlv-account-resolution 0.6.3", + "spl-type-length-value 0.4.3", ] [[package]] @@ -6075,23 +5591,11 @@ checksum = "422ce13429dbd41d2cee8a73931c05fda0b0c8ca156a8b0c19445642550bb61a" dependencies = [ "bytemuck", "solana-program", - "spl-discriminator 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-pod 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", "spl-program-error 0.4.1", ] -[[package]] -name = "spl-type-length-value" -version = "0.4.3" -source = "git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5#bc41bebfdb9b3d28f21d7eb32e1667afeea3fa60" -dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-pod 0.2.2 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-program-error 0.4.0", -] - [[package]] name = "static_assertions" version = "1.1.0" @@ -6110,6 +5614,12 @@ version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "strum" version = "0.24.1" @@ -6157,9 +5667,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.62" +version = "2.0.66" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f660c3bfcefb88c538776b6685a0c472e3128b51e74d48793dc2a488196e8eb" +checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5" dependencies = [ "proc-macro2", "quote", @@ -6175,7 +5685,7 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -6308,7 +5818,7 @@ dependencies = [ "cfg-if", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -6319,7 +5829,7 @@ checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", "test-case-core", ] @@ -6340,22 +5850,22 @@ checksum = "23d434d3f8967a09480fb04132ebe0a3e088c173e6d0ee7897abbdf4eab0f8b9" [[package]] name = "thiserror" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "579e9083ca58dd9dcf91a9923bb9054071b9ebbd800b342194c9feb0ee89fc18" +checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.60" +version = "1.0.61" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2470041c06ec3ac1ab38d0356a6119054dedaea53e12fbefc0de730a1c08524" +checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -6438,8 +5948,8 @@ name = "token-voter" version = "0.1.0" dependencies = [ "ahash 0.8.7", - "anchor-lang 0.30.0", - "anchor-spl 0.30.0", + "anchor-lang", + "anchor-spl", "arrayref", "borsh 0.10.3", "env_logger", @@ -6448,23 +5958,23 @@ dependencies = [ "solana-program-test", "solana-sdk", "spl-associated-token-account 3.0.2", - "spl-governance 4.0.0 (git+https://github.com/crypt0miester/solana-program-library.git?branch=gib-bounty-jlFb5)", - "spl-governance-addin-api 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-governance-tools 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-tlv-account-resolution 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-governance", + "spl-governance-addin-api", + "spl-governance-tools", + "spl-tlv-account-resolution 0.6.3", "spl-token 3.5.0", - "spl-token-2022 3.0.2 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-2022 3.0.2", "spl-token-client", "spl-transfer-hook-example", - "spl-transfer-hook-interface 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-transfer-hook-interface 0.6.3", "static_assertions", ] [[package]] name = "tokio" -version = "1.37.0" +version = "1.38.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1adbebffeca75fcfd058afa480fb6c0b81e165a0323f9c9d39c9697e37c46787" +checksum = "ba4f4a02a7a80d6f274636f0aa95c7e383b912d41fe721a31f29e29698585a4a" dependencies = [ "backtrace", "bytes", @@ -6481,13 +5991,13 @@ dependencies = [ [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "5f5ae998a069d4b5aba8ee9dad856af7d520c3699e6159b185c2acd48155d39a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -6581,21 +6091,21 @@ dependencies = [ [[package]] name = "toml" -version = "0.8.12" +version = "0.8.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3" +checksum = "a4e43f8cc456c9704c851ae29c67e17ef65d2c30017c17a9765b89c382dc8bba" dependencies = [ "serde", "serde_spanned", "toml_datetime", - "toml_edit 0.22.12", + "toml_edit 0.22.13", ] [[package]] name = "toml_datetime" -version = "0.6.5" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] @@ -6624,15 +6134,15 @@ dependencies = [ [[package]] name = "toml_edit" -version = "0.22.12" +version = "0.22.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3328d4f68a705b2a4498da1d580585d39a6510f98318a2cec3018a7ec61ddef" +checksum = "c127785850e8c20836d49732ae6abfa47616e60bf9d9f57c43c250361a9db96c" dependencies = [ "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", - "winnow 0.6.8", + "winnow 0.6.9", ] [[package]] @@ -6661,7 +6171,7 @@ checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -6910,7 +6420,7 @@ dependencies = [ "once_cell", "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", "wasm-bindgen-shared", ] @@ -6944,7 +6454,7 @@ checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", "wasm-bindgen-backend", "wasm-bindgen-shared", ] @@ -7170,9 +6680,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.6.8" +version = "0.6.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3c52e9c97a68071b23e836c9380edae937f17b9c4667bd021973efc689f618d" +checksum = "86c949fede1d13936a99f14fafd3e76fd642b556dd2ce96287fbe2e0151bfac6" dependencies = [ "memchr", ] @@ -7216,12 +6726,6 @@ dependencies = [ "rustix", ] -[[package]] -name = "yansi" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec" - [[package]] name = "yasna" version = "0.5.2" @@ -7248,7 +6752,7 @@ checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] @@ -7268,7 +6772,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.62", + "syn 2.0.66", ] [[package]] diff --git a/programs/token-haver/Cargo.toml b/programs/token-haver/Cargo.toml deleted file mode 100644 index 4aea0243..00000000 --- a/programs/token-haver/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -name = "gpl-token-haver" -version = "0.0.1" -description = "SPL Governance plugin granting governance power based on the nonzero presence of locked tokens" -license = "Apache-2.0" -edition = "2018" - -[lib] -crate-type = ["cdylib", "lib"] -name = "gpl_token_haver" - -[features] -no-entrypoint = [] -no-idl = [] -no-log-ix-name = [] -cpi = ["no-entrypoint"] -default = [] - -[dependencies] -arrayref = "0.3.6" -anchor-lang = { version = "0.26.0" } -anchor-spl = "0.26.0" -solana-program = "1.14.16" -spl-governance = { version = "3.1.1", features = ["no-entrypoint"] } -spl-governance-tools= "0.1.3" -spl-token = { version = "3.3", features = [ "no-entrypoint" ] } - -[dev-dependencies] -borsh = "0.9.1" -solana-sdk = "1.14.16" -solana-program-test = "1.14.16" \ No newline at end of file diff --git a/programs/token-haver/Xargo.toml b/programs/token-haver/Xargo.toml deleted file mode 100644 index 475fb71e..00000000 --- a/programs/token-haver/Xargo.toml +++ /dev/null @@ -1,2 +0,0 @@ -[target.bpfel-unknown-unknown.dependencies.std] -features = [] diff --git a/programs/token-haver/readme.md b/programs/token-haver/readme.md deleted file mode 100644 index c140c504..00000000 --- a/programs/token-haver/readme.md +++ /dev/null @@ -1,6 +0,0 @@ -This plugin checks for the presence of nonzero tokens from certain mints in the user's wallet. - -### You would use this if: - -- You want voting power to be based on having an _indefinitely locked_ token, but not proportional to the amount of the token -- You don't want to use a Membership (for UX reasons) diff --git a/programs/token-haver/src/error.rs b/programs/token-haver/src/error.rs deleted file mode 100644 index de1e4678..00000000 --- a/programs/token-haver/src/error.rs +++ /dev/null @@ -1,28 +0,0 @@ -use anchor_lang::prelude::*; - -#[error_code] -pub enum TokenHaverError { - #[msg("Invalid Realm Authority")] - InvalidRealmAuthority, - - #[msg("Invalid Realm for Registrar")] - InvalidRealmForRegistrar, - - #[msg("Invalid VoterWeightRecord Realm")] - InvalidVoterWeightRecordRealm, - - #[msg("Invalid VoterWeightRecord Mint")] - InvalidVoterWeightRecordMint, - - #[msg("Governing TokenOwner must match")] - GoverningTokenOwnerMustMatch, - - #[msg("All token accounts must be owned by the governing token owner")] - TokenAccountWrongOwner, - - #[msg("All token accounts' mints must be included in the registrar")] - TokenAccountWrongMint, - - #[msg("All token accounts' mints must be included in the registrar")] - TokenAccountNotLocked, -} diff --git a/programs/token-haver/src/instructions/configure_mints.rs b/programs/token-haver/src/instructions/configure_mints.rs deleted file mode 100644 index bd360848..00000000 --- a/programs/token-haver/src/instructions/configure_mints.rs +++ /dev/null @@ -1,73 +0,0 @@ -use crate::error::TokenHaverError; -use crate::state::*; -use anchor_lang::system_program::Transfer; -use anchor_lang::{prelude::*, system_program}; -use spl_governance::state::realm; - -/// Configures mints for Registrar -#[derive(Accounts)] -#[instruction(mints: Vec)] -pub struct ConfigureMints<'info> { - /// The Registrar for the given realm and governing_token_mint - #[account(mut)] - pub registrar: Account<'info, Registrar>, - - #[account( - address = registrar.realm @ TokenHaverError::InvalidRealmForRegistrar, - owner = registrar.governance_program_id - )] - /// CHECK: Owned by spl-governance instance specified in registrar.governance_program_id - pub realm: UncheckedAccount<'info>, - - // will pay in the event of a resize - pub payer: Signer<'info>, - - /// Authority of the Realm must sign and match realm.authority - pub realm_authority: Signer<'info>, - - pub system_program: Program<'info, System>, -} - -pub fn configure_mints(ctx: Context, mints: Vec) -> Result<()> { - let new_size = Registrar::get_space(mints.len() as u8); - - let rent = Rent::get()?; - let new_minimum_balance = rent.minimum_balance(new_size); - - let lamports_diff = - new_minimum_balance.saturating_sub(ctx.accounts.registrar.to_account_info().lamports()); - - // if lamports_diff is positive, we need to fund the account - if lamports_diff > 0 { - // Create a CPI context for the transfer - let cpi_accounts = Transfer { - from: ctx.accounts.payer.to_account_info().clone(), - to: ctx.accounts.registrar.to_account_info().clone(), - }; - - let cpi_program = ctx.accounts.system_program.to_account_info(); - let cpi_ctx = CpiContext::new(cpi_program, cpi_accounts); - - // Perform the transfer - system_program::transfer(cpi_ctx, lamports_diff)?; - } - - let registrar = &mut ctx.accounts.registrar; - registrar.to_account_info().realloc(new_size, false)?; - - registrar.mints = mints; - - let realm = realm::get_realm_data_for_governing_token_mint( - ®istrar.governance_program_id, - &ctx.accounts.realm, - ®istrar.governing_token_mint, - )?; - - require_eq!( - realm.authority.unwrap(), - ctx.accounts.realm_authority.key(), - TokenHaverError::InvalidRealmAuthority - ); - - Ok(()) -} diff --git a/programs/token-haver/src/instructions/create_registrar.rs b/programs/token-haver/src/instructions/create_registrar.rs deleted file mode 100644 index ed05dc15..00000000 --- a/programs/token-haver/src/instructions/create_registrar.rs +++ /dev/null @@ -1,83 +0,0 @@ -use crate::error::TokenHaverError; -use crate::state::*; -use anchor_lang::prelude::*; -use anchor_spl::token::Mint; -use spl_governance::state::realm; - -/// Creates Registrar storing Realm Voter configuration for spl-governance Realm -/// This instruction should only be executed once per realm/governing_token_mint to create the account -#[derive(Accounts)] -#[instruction(mints: Vec)] -pub struct CreateRegistrar<'info> { - /// The Realm Voter Registrar - /// There can only be a single registrar per governance Realm and governing mint of the Realm - #[account( - init, - seeds = [b"registrar".as_ref(),realm.key().as_ref(), governing_token_mint.key().as_ref()], - bump, - payer = payer, - space = Registrar::get_space(mints.len() as u8), - )] - pub registrar: Account<'info, Registrar>, - - /// The program id of the spl-governance program the realm belongs to - /// CHECK: Can be any instance of spl-governance and it's not known at the compilation time - #[account(executable)] - pub governance_program_id: UncheckedAccount<'info>, - - /// An spl-governance Realm - /// - /// Realm is validated in the instruction: - /// - Realm is owned by the governance_program_id - /// - governing_token_mint must be the community or council mint - /// - realm_authority is realm.authority - /// CHECK: Owned by spl-governance instance specified in governance_program_id - #[account(owner = governance_program_id.key())] - pub realm: UncheckedAccount<'info>, - - /// Either the realm community mint or the council mint. - /// It must match Realm.community_mint or Realm.config.council_mint - /// - /// Note: Once the Realm voter plugin is enabled the governing_token_mint is used only as identity - /// for the voting population and the tokens of that are no longer used - pub governing_token_mint: Account<'info, Mint>, - - /// realm_authority must sign and match Realm.authority - pub realm_authority: Signer<'info>, - - #[account(mut)] - pub payer: Signer<'info>, - - pub system_program: Program<'info, System>, -} - -/// Creates a new Registrar which stores Realms voter configuration for the given Realm -/// -/// To use the registrar, call ConfigureGovernanceProgram to register spl-governance instance which will be -/// used for governance -/// -pub fn create_registrar(ctx: Context, mints: Vec) -> Result<()> { - let registrar = &mut ctx.accounts.registrar; - **registrar = Registrar { - governance_program_id: ctx.accounts.governance_program_id.key(), - realm: ctx.accounts.realm.key(), - governing_token_mint: ctx.accounts.governing_token_mint.key(), - mints, - }; - - // Verify that realm_authority is the expected authority of the Realm - // and that the mint matches one of the realm mints too - let realm = realm::get_realm_data_for_governing_token_mint( - ®istrar.governance_program_id, - &ctx.accounts.realm, - ®istrar.governing_token_mint, - )?; - - require_eq!( - realm.authority.unwrap(), - ctx.accounts.realm_authority.key(), - TokenHaverError::InvalidRealmAuthority - ); - - Ok(()) -} diff --git a/programs/token-haver/src/instructions/create_voter_weight_record.rs b/programs/token-haver/src/instructions/create_voter_weight_record.rs deleted file mode 100644 index 2a8b67ab..00000000 --- a/programs/token-haver/src/instructions/create_voter_weight_record.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::state::*; -use anchor_lang::prelude::*; - -/// Creates VoterWeightRecord used by spl-gov -/// This instruction should only be executed once per realm/governing_token_mint/governing_token_owner -/// to create the account -#[derive(Accounts)] -#[instruction(governing_token_owner: Pubkey)] -pub struct CreateVoterWeightRecord<'info> { - // The Registrar the VoterWeightRecord account belongs to - pub registrar: Account<'info, Registrar>, - - #[account( - init, - seeds = [ b"voter-weight-record".as_ref(), - registrar.realm.key().as_ref(), - registrar.governing_token_mint.key().as_ref(), - governing_token_owner.as_ref()], - bump, - payer = payer, - space = VoterWeightRecord::get_space() - )] - pub voter_weight_record: Account<'info, VoterWeightRecord>, - - #[account(mut)] - pub payer: Signer<'info>, - - pub system_program: Program<'info, System>, -} - -pub fn create_voter_weight_record( - ctx: Context, - governing_token_owner: Pubkey, -) -> Result<()> { - let voter_weight_record = &mut ctx.accounts.voter_weight_record; - let registrar = &ctx.accounts.registrar; - - voter_weight_record.realm = registrar.realm.key(); - voter_weight_record.governing_token_mint = registrar.governing_token_mint.key(); - voter_weight_record.governing_token_owner = governing_token_owner; - - // Set expiry to expired - voter_weight_record.voter_weight_expiry = Some(0); - - Ok(()) -} diff --git a/programs/token-haver/src/instructions/mod.rs b/programs/token-haver/src/instructions/mod.rs deleted file mode 100644 index 90e0290b..00000000 --- a/programs/token-haver/src/instructions/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub use create_registrar::*; -mod create_registrar; - -pub use create_voter_weight_record::*; -mod create_voter_weight_record; - -pub use update_voter_weight_record::*; -mod update_voter_weight_record; - -pub use configure_mints::*; -mod configure_mints; diff --git a/programs/token-haver/src/instructions/update_voter_weight_record.rs b/programs/token-haver/src/instructions/update_voter_weight_record.rs deleted file mode 100644 index c97723bf..00000000 --- a/programs/token-haver/src/instructions/update_voter_weight_record.rs +++ /dev/null @@ -1,60 +0,0 @@ -use crate::error::TokenHaverError; -use crate::state::*; -use anchor_lang::prelude::*; -use anchor_spl::token::TokenAccount; - -/// Updates VoterWeightRecord based on Realm DAO membership -/// The membership is evaluated via a valid TokenOwnerRecord which must belong to one of the configured spl-governance instances -/// -/// This instruction sets VoterWeightRecord.voter_weight which is valid for the current slot only -/// and must be executed inside the same transaction as the corresponding spl-gov instruction -#[derive(Accounts)] -pub struct UpdateVoterWeightRecord<'info> { - /// The RealmVoter voting Registrar - pub registrar: Account<'info, Registrar>, - - #[account( - mut, - constraint = voter_weight_record.realm == registrar.realm - @ TokenHaverError::InvalidVoterWeightRecordRealm, - - constraint = voter_weight_record.governing_token_mint == registrar.governing_token_mint - @ TokenHaverError::InvalidVoterWeightRecordMint, - )] - pub voter_weight_record: Account<'info, VoterWeightRecord>, -} - -pub fn update_voter_weight_record(ctx: Context) -> Result<()> { - let registrar = &ctx.accounts.registrar; - let voter_weight_record = &mut ctx.accounts.voter_weight_record; - - let nonzero_token_accounts: Vec> = ctx - .remaining_accounts - .iter() - .map(|account| Account::::try_from(account).unwrap()) - .filter(|account| account.amount > 0) // filter out zero balance accounts - .collect(); - - for account in nonzero_token_accounts.iter() { - // Throw an error if a token account's owner doesnt match token_owner_record.governing_token_owner - require_eq!( - account.owner, - voter_weight_record.governing_token_owner, - TokenHaverError::TokenAccountWrongOwner - ); - // Throw an error if a token account's mint isn't in registrar.mints - require!( - registrar.mints.contains(&account.mint), - TokenHaverError::TokenAccountWrongMint - ); - // Throw an error if a token account is not frozen - require!(account.is_frozen(), TokenHaverError::TokenAccountNotLocked); - } - - // Setup voter_weight - voter_weight_record.voter_weight = nonzero_token_accounts.len() as u64; - - // Record is only valid as of the current slot - voter_weight_record.voter_weight_expiry = Some(Clock::get()?.slot); - Ok(()) -} diff --git a/programs/token-haver/src/lib.rs b/programs/token-haver/src/lib.rs deleted file mode 100644 index 1a11f382..00000000 --- a/programs/token-haver/src/lib.rs +++ /dev/null @@ -1,43 +0,0 @@ -use anchor_lang::prelude::*; - -pub mod error; - -mod instructions; -use instructions::*; - -pub mod state; - -pub mod tools; - -declare_id!("vo65JQC6U8HCDPfoJxRrr17n7RZ5fKdfyjHm3erHJ2V"); - -#[program] -pub mod token_haver { - - use super::*; - - pub fn create_registrar(ctx: Context, mints: Vec) -> Result<()> { - log_version(); - instructions::create_registrar(ctx, mints) - } - pub fn create_voter_weight_record( - ctx: Context, - governing_token_owner: Pubkey, - ) -> Result<()> { - log_version(); - instructions::create_voter_weight_record(ctx, governing_token_owner) - } - pub fn update_voter_weight_record(ctx: Context) -> Result<()> { - log_version(); - instructions::update_voter_weight_record(ctx) - } - pub fn configure_mints(ctx: Context, mints: Vec) -> Result<()> { - log_version(); - instructions::configure_mints(ctx, mints) - } -} - -fn log_version() { - // TODO: Check if Anchor allows to log it before instruction is deserialized - msg!("VERSION:{:?}", env!("CARGO_PKG_VERSION")); -} diff --git a/programs/token-haver/src/state/max_voter_weight_record.rs b/programs/token-haver/src/state/max_voter_weight_record.rs deleted file mode 100644 index 66ac8da7..00000000 --- a/programs/token-haver/src/state/max_voter_weight_record.rs +++ /dev/null @@ -1,96 +0,0 @@ -use crate::id; -use crate::tools::anchor::DISCRIMINATOR_SIZE; -use anchor_lang::prelude::Pubkey; -use anchor_lang::prelude::*; -use solana_program::pubkey::PUBKEY_BYTES; - -/// MaxVoterWeightRecord account as defined in spl-governance-addin-api -/// It's redefined here without account_discriminator for Anchor to treat it as native account -/// -/// The account is used as an api interface to provide max voting power to the governance program from external addin contracts -#[account] -#[derive(Debug, PartialEq)] -pub struct MaxVoterWeightRecord { - /// The Realm the MaxVoterWeightRecord belongs to - pub realm: Pubkey, - - /// Governing Token Mint the MaxVoterWeightRecord is associated with - /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only - // The mint here is to link the record to either community or council mint of the realm - pub governing_token_mint: Pubkey, - - /// Max voter weight - /// The max voter weight provided by the addin for the given realm and governing_token_mint - pub max_voter_weight: u64, - - /// The slot when the max voting weight expires - /// It should be set to None if the weight never expires - /// If the max vote weight decays with time, for example for time locked based weights, then the expiry must be set - /// As a pattern Revise instruction to update the max weight should be invoked before governance instruction within the same transaction - /// and the expiry set to the current slot to provide up to date weight - pub max_voter_weight_expiry: Option, - - /// Reserved space for future versions - pub reserved: [u8; 8], -} - -impl Default for MaxVoterWeightRecord { - fn default() -> Self { - Self { - realm: Default::default(), - governing_token_mint: Default::default(), - max_voter_weight: Default::default(), - max_voter_weight_expiry: Some(0), - reserved: Default::default(), - } - } -} - -impl MaxVoterWeightRecord { - pub fn get_space() -> usize { - DISCRIMINATOR_SIZE + PUBKEY_BYTES * 2 + 8 + 1 + 8 + 8 - } -} - -/// Returns MaxVoterWeightRecord PDA seeds -pub fn get_max_voter_weight_record_seeds<'a>( - realm: &'a Pubkey, - governing_token_mint: &'a Pubkey, -) -> [&'a [u8]; 3] { - [ - b"max-voter-weight-record", - realm.as_ref(), - governing_token_mint.as_ref(), - ] -} - -/// Returns MaxVoterWeightRecord PDA address -pub fn get_max_voter_weight_record_address( - realm: &Pubkey, - governing_token_mint: &Pubkey, -) -> Pubkey { - Pubkey::find_program_address( - &get_max_voter_weight_record_seeds(realm, governing_token_mint), - &id(), - ) - .0 -} - -#[cfg(test)] -mod test { - - use super::*; - - #[test] - fn test_get_space() { - // Arrange - let expected_space = MaxVoterWeightRecord::get_space(); - - // Act - let actual_space = - DISCRIMINATOR_SIZE + MaxVoterWeightRecord::default().try_to_vec().unwrap().len(); - - // Assert - assert_eq!(expected_space, actual_space); - } -} diff --git a/programs/token-haver/src/state/mod.rs b/programs/token-haver/src/state/mod.rs deleted file mode 100644 index 2aafb4f9..00000000 --- a/programs/token-haver/src/state/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub use registrar::*; -pub mod registrar; - -pub mod max_voter_weight_record; - -pub use voter_weight_record::*; -pub mod voter_weight_record; diff --git a/programs/token-haver/src/state/registrar.rs b/programs/token-haver/src/state/registrar.rs deleted file mode 100644 index b36a121d..00000000 --- a/programs/token-haver/src/state/registrar.rs +++ /dev/null @@ -1,76 +0,0 @@ -use crate::{id, tools::anchor::DISCRIMINATOR_SIZE}; -use anchor_lang::prelude::*; -use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; -use solana_program::pubkey::PUBKEY_BYTES; - -/// Enum defining collection item change type -#[derive(Clone, Debug, PartialEq, BorshDeserialize, BorshSerialize, BorshSchema)] -pub enum CollectionItemChangeType { - /// Update item in the collection if it already exists and Insert the item if it doesn't - Upsert, - /// Remove item from the collection - Remove, -} - -/// Registrar which stores spl-governance configurations for the given Realm -#[account] -#[derive(Debug, PartialEq)] -pub struct Registrar { - /// spl-governance program the Realm belongs to - pub governance_program_id: Pubkey, - - /// Realm of the Registrar - pub realm: Pubkey, - - /// Governing token mint the Registrar is for - /// It can either be the Community or the Council mint of the Realm - /// When the plugin is enabled the mint is only used as the identity of the governing power (voting population) - /// and the actual token of the mint is not used - pub governing_token_mint: Pubkey, - - pub mints: Vec, -} - -impl Registrar { - pub fn get_space(max_mints: u8) -> usize { - DISCRIMINATOR_SIZE + PUBKEY_BYTES * 3 + max_mints as usize * (PUBKEY_BYTES + 8) - } -} - -/// Returns Registrar PDA seeds -pub fn get_registrar_seeds<'a>( - realm: &'a Pubkey, - governing_token_mint: &'a Pubkey, -) -> [&'a [u8]; 3] { - [b"registrar", realm.as_ref(), governing_token_mint.as_ref()] -} - -/// Returns Registrar PDA address -pub fn get_registrar_address(realm: &Pubkey, governing_token_mint: &Pubkey) -> Pubkey { - Pubkey::find_program_address(&get_registrar_seeds(realm, governing_token_mint), &id()).0 -} - -#[cfg(test)] -mod test { - - use super::*; - - #[test] - fn test_get_space() { - // Arrange - let expected_space = Registrar::get_space(3); - - let registrar = Registrar { - governance_program_id: Pubkey::default(), - realm: Pubkey::default(), - governing_token_mint: Pubkey::default(), - mints: vec![Pubkey::default(), Pubkey::default(), Pubkey::default()], - }; - - // Act - let actual_space = DISCRIMINATOR_SIZE + registrar.try_to_vec().unwrap().len(); - - // Assert - assert_eq!(expected_space, actual_space); - } -} diff --git a/programs/token-haver/src/state/voter_weight_record.rs b/programs/token-haver/src/state/voter_weight_record.rs deleted file mode 100644 index 0d0e24c7..00000000 --- a/programs/token-haver/src/state/voter_weight_record.rs +++ /dev/null @@ -1,110 +0,0 @@ -use anchor_lang::prelude::*; -use solana_program::pubkey::PUBKEY_BYTES; - -use crate::tools::anchor::DISCRIMINATOR_SIZE; - -/// VoterWeightAction enum as defined in spl-governance-addin-api -/// It's redefined here for Anchor to export it to IDL -#[derive(AnchorSerialize, AnchorDeserialize, Debug, Clone, Copy, PartialEq)] -pub enum VoterWeightAction { - /// Cast vote for a proposal. Target: Proposal - CastVote, - - /// Comment a proposal. Target: Proposal - CommentProposal, - - /// Create Governance within a realm. Target: Realm - CreateGovernance, - - /// Create a proposal for a governance. Target: Governance - CreateProposal, - - /// Signs off a proposal for a governance. Target: Proposal - /// Note: SignOffProposal is not supported in the current version - SignOffProposal, -} - -/// VoterWeightRecord account as defined in spl-governance-addin-api -/// It's redefined here without account_discriminator for Anchor to treat it as native account -/// -/// The account is used as an api interface to provide voting power to the governance program from external addin contracts -#[account] -#[derive(Debug, PartialEq)] -pub struct VoterWeightRecord { - /// The Realm the VoterWeightRecord belongs to - pub realm: Pubkey, - - /// Governing Token Mint the VoterWeightRecord is associated with - /// Note: The addin can take deposits of any tokens and is not restricted to the community or council tokens only - // The mint here is to link the record to either community or council mint of the realm - pub governing_token_mint: Pubkey, - - /// The owner of the governing token and voter - /// This is the actual owner (voter) and corresponds to TokenOwnerRecord.governing_token_owner - pub governing_token_owner: Pubkey, - - /// Voter's weight - /// The weight of the voter provided by the addin for the given realm, governing_token_mint and governing_token_owner (voter) - pub voter_weight: u64, - - /// The slot when the voting weight expires - /// It should be set to None if the weight never expires - /// If the voter weight decays with time, for example for time locked based weights, then the expiry must be set - /// As a common pattern Revise instruction to update the weight should be invoked before governance instruction within the same transaction - /// and the expiry set to the current slot to provide up to date weight - pub voter_weight_expiry: Option, - - /// The governance action the voter's weight pertains to - /// It allows to provided voter's weight specific to the particular action the weight is evaluated for - /// When the action is provided then the governance program asserts the executing action is the same as specified by the addin - pub weight_action: Option, - - /// The target the voter's weight action pertains to - /// It allows to provided voter's weight specific to the target the weight is evaluated for - /// For example when addin supplies weight to vote on a particular proposal then it must specify the proposal as the action target - /// When the target is provided then the governance program asserts the target is the same as specified by the addin - pub weight_action_target: Option, - - /// Reserved space for future versions - pub reserved: [u8; 8], -} - -impl VoterWeightRecord { - pub fn get_space() -> usize { - DISCRIMINATOR_SIZE + PUBKEY_BYTES * 4 + 8 + 1 + 8 + 1 + 1 + 1 + 8 - } -} - -impl Default for VoterWeightRecord { - fn default() -> Self { - Self { - realm: Default::default(), - governing_token_mint: Default::default(), - governing_token_owner: Default::default(), - voter_weight: Default::default(), - voter_weight_expiry: Some(0), - weight_action: Some(VoterWeightAction::CastVote), - weight_action_target: Some(Default::default()), - reserved: Default::default(), - } - } -} - -#[cfg(test)] -mod test { - - use super::*; - - #[test] - fn test_get_space() { - // Arrange - let expected_space = VoterWeightRecord::get_space(); - - // Act - let actual_space = - DISCRIMINATOR_SIZE + VoterWeightRecord::default().try_to_vec().unwrap().len(); - - // Assert - assert_eq!(expected_space, actual_space); - } -} diff --git a/programs/token-haver/src/tools/anchor.rs b/programs/token-haver/src/tools/anchor.rs deleted file mode 100644 index abc1dd52..00000000 --- a/programs/token-haver/src/tools/anchor.rs +++ /dev/null @@ -1 +0,0 @@ -pub const DISCRIMINATOR_SIZE: usize = 8; diff --git a/programs/token-haver/src/tools/mod.rs b/programs/token-haver/src/tools/mod.rs deleted file mode 100644 index 37794aee..00000000 --- a/programs/token-haver/src/tools/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod anchor; diff --git a/programs/token-haver/tests/configure_mints.rs b/programs/token-haver/tests/configure_mints.rs deleted file mode 100644 index 9693627e..00000000 --- a/programs/token-haver/tests/configure_mints.rs +++ /dev/null @@ -1,297 +0,0 @@ -use gpl_realm_voter::{error::TokenHaverError, state::CollectionItemChangeType}; -use program_test::token_haver_test::RealmVoterTest; -use solana_program_test::*; -use solana_sdk::{signature::Keypair, signer::Signer, transport::TransportError}; -mod program_test; -use program_test::tools::{assert_anchor_err, assert_realm_voter_err}; - -#[tokio::test] -async fn test_configure_governance_program() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - // Act - let governance_program_config_cookie = realm_voter_test - .configure_mints( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - ) - .await?; - - // // Assert - let registrar = realm_voter_test - .get_registrar_account(®istrar_cookie.address) - .await; - - assert_eq!(registrar.governance_program_configs.len(), 1); - - assert_eq!( - registrar.governance_program_configs[0], - governance_program_config_cookie.program_config - ); - - Ok(()) -} - -#[tokio::test] -async fn test_configure_governance_program_with_multiple_programs() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie1 = realm_voter_test.with_governance_program(None).await; - - // Create config with gpl_realm_voter::id() to have some other executable program, the actual program is irrelevant here - let governance_program_cookie2 = realm_voter_test - .with_governance_program(Some(gpl_realm_voter::id())) - .await; - - // Act - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie1, - CollectionItemChangeType::Upsert, - ) - .await?; - - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie2, - CollectionItemChangeType::Upsert, - ) - .await?; - - // Assert - let registrar = realm_voter_test - .get_registrar_account(®istrar_cookie.address) - .await; - - assert_eq!(registrar.governance_program_configs.len(), 2); - - Ok(()) -} - -#[tokio::test] -async fn test_configure_governance_program_for_existing_program() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - ) - .await?; - - // Act - - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - ) - .await?; - - // Assert - let registrar = realm_voter_test - .get_registrar_account(®istrar_cookie.address) - .await; - - assert_eq!(registrar.governance_program_configs.len(), 1); - assert_eq!( - registrar.governance_program_configs[0].program_id, - governance_program_cookie.program_id - ); - - Ok(()) -} - -#[tokio::test] -async fn test_configure_governance_program_with_invalid_realm_error() -> Result<(), TransportError> -{ - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - // Try to use a different Realm - let realm_cookie2 = realm_voter_test.governance.with_realm().await?; - - // Act - let err = realm_voter_test - .configure_governance_program_using_ix( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - |i| i.accounts[1].pubkey = realm_cookie2.address, // realm - None, - ) - .await - .err() - .unwrap(); - - // Assert - - assert_realm_voter_err(err, TokenHaverError::InvalidRealmForRegistrar); - - Ok(()) -} - -#[tokio::test] -async fn test_configure_governance_program_with_realm_authority_must_sign_error( -) -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - // Act - let err = realm_voter_test - .configure_governance_program_using_ix( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - |i| i.accounts[2].is_signer = false, // realm_authority - Some(&[]), - ) - .await - .err() - .unwrap(); - - // Assert - - assert_anchor_err(err, anchor_lang::error::ErrorCode::AccountNotSigner); - - Ok(()) -} - -#[tokio::test] -async fn test_configure_governance_program_with_invalid_realm_authority_error( -) -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - let realm_authority = Keypair::new(); - - // Act - let err = realm_voter_test - .configure_governance_program_using_ix( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - |i| i.accounts[2].pubkey = realm_authority.pubkey(), // realm_authority - Some(&[&realm_authority]), - ) - .await - .err() - .unwrap(); - - // Assert - - assert_realm_voter_err(err, TokenHaverError::InvalidRealmAuthority); - - Ok(()) -} - -#[tokio::test] -async fn test_remove_governance_program_configuration() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - ) - .await?; - - // Act - - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Remove, - ) - .await?; - - // // Assert - let registrar = realm_voter_test - .get_registrar_account(®istrar_cookie.address) - .await; - - assert_eq!(registrar.governance_program_configs.len(), 0); - - Ok(()) -} - -#[tokio::test] -async fn test_remove_governance_program_configuration_with_program_not_configured_error( -) -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - // Act - let err = realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Remove, - ) - .await - .err() - .unwrap(); - - // // Assert - - assert_realm_voter_err(err, TokenHaverError::GovernanceProgramNotConfigured); - - Ok(()) -} diff --git a/programs/token-haver/tests/create_registrar.rs b/programs/token-haver/tests/create_registrar.rs deleted file mode 100644 index 4ee9c78e..00000000 --- a/programs/token-haver/tests/create_registrar.rs +++ /dev/null @@ -1,180 +0,0 @@ -mod program_test; - -use anchor_lang::prelude::{ErrorCode, Pubkey}; -use gpl_realm_voter::error::TokenHaverError; -use program_test::token_haver_test::RealmVoterTest; - -use solana_program::instruction::InstructionError; -use solana_program_test::*; -use solana_sdk::{signature::Keypair, transport::TransportError}; - -use program_test::tools::{assert_anchor_err, assert_ix_err, assert_realm_voter_err}; - -#[tokio::test] -async fn test_create_registrar() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - // Act - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - // Assert - let registrar = realm_voter_test - .get_registrar_account(®istrar_cookie.address) - .await; - - assert_eq!(registrar, registrar_cookie.account); - - Ok(()) -} - -#[tokio::test] -async fn test_create_registrar_with_invalid_realm_authority_error() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let mut realm_cookie = realm_voter_test.governance.with_realm().await?; - realm_cookie.realm_authority = Keypair::new(); - - // Act - let err = realm_voter_test - .with_registrar(&realm_cookie) - .await - .err() - .unwrap(); - - assert_realm_voter_err(err, TokenHaverError::InvalidRealmAuthority); - - Ok(()) -} - -#[tokio::test] -async fn test_create_registrar_with_realm_authority_must_sign_error() -> Result<(), TransportError> -{ - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - // Act - let err = realm_voter_test - .with_registrar_using_ix( - &realm_cookie, - |i| i.accounts[4].is_signer = false, // realm_authority - Some(&[]), - ) - .await - .err() - .unwrap(); - - assert_anchor_err(err, anchor_lang::error::ErrorCode::AccountNotSigner); - - Ok(()) -} - -#[tokio::test] -async fn test_create_registrar_with_invalid_spl_gov_program_id_error() -> Result<(), TransportError> -{ - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - // Try to use a different program id - let governance_program_id = realm_voter_test.program_id; - - // Act - let err = realm_voter_test - .with_registrar_using_ix( - &realm_cookie, - |i| i.accounts[1].pubkey = governance_program_id, //governance_program_id - None, - ) - .await - .err() - .unwrap(); - - assert_anchor_err(err, anchor_lang::error::ErrorCode::ConstraintOwner); - - Ok(()) -} - -#[tokio::test] -async fn test_create_registrar_with_invalid_realm_error() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - // Act - let err = realm_voter_test - .with_registrar_using_ix( - &realm_cookie, - |i| i.accounts[2].pubkey = Pubkey::new_unique(), // realm - None, - ) - .await - .err() - .unwrap(); - - // PDA doesn't match and hence the error is ConstraintSeeds - assert_anchor_err(err, ErrorCode::ConstraintSeeds); - - Ok(()) -} - -#[tokio::test] -async fn test_create_registrar_with_invalid_governing_token_mint_error( -) -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let mint_cookie = realm_voter_test.bench.with_mint().await?; - - // Act - let err = realm_voter_test - .with_registrar_using_ix( - &realm_cookie, - |i| i.accounts[3].pubkey = mint_cookie.address, // governing_token_mint - None, - ) - .await - .err() - .unwrap(); - - // PDA doesn't match and hence the error is ConstraintSeeds - assert_anchor_err(err, ErrorCode::ConstraintSeeds); - - Ok(()) -} - -#[tokio::test] -async fn test_create_registrar_with_registrar_already_exists_error() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - realm_voter_test.with_registrar(&realm_cookie).await?; - - realm_voter_test.bench.advance_clock().await; - - // Act - - let err = realm_voter_test - .with_registrar(&realm_cookie) - .await - .err() - .unwrap(); - - // Assert - - // Registrar already exists and it throws Custom(0) error - assert_ix_err(err, InstructionError::Custom(0)); - - Ok(()) -} diff --git a/programs/token-haver/tests/create_voter_weight_record.rs b/programs/token-haver/tests/create_voter_weight_record.rs deleted file mode 100644 index 102bcc9a..00000000 --- a/programs/token-haver/tests/create_voter_weight_record.rs +++ /dev/null @@ -1,66 +0,0 @@ -use crate::program_test::token_haver_test::RealmVoterTest; -use program_test::tools::assert_ix_err; -use solana_program::instruction::InstructionError; -use solana_program_test::*; -use solana_sdk::transport::TransportError; - -mod program_test; - -#[tokio::test] -async fn test_create_voter_weight_record() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let voter_cookie = realm_voter_test.bench.with_wallet().await; - - // Act - let voter_weight_record_cookie = realm_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - // Assert - - let voter_weight_record = realm_voter_test - .get_voter_weight_record(&voter_weight_record_cookie.address) - .await; - - assert_eq!(voter_weight_record_cookie.account, voter_weight_record); - - Ok(()) -} - -#[tokio::test] -async fn test_create_voter_weight_record_with_already_exists_error() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let voter_cookie = realm_voter_test.bench.with_wallet().await; - - realm_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await?; - - realm_voter_test.bench.advance_clock().await; - - // Act - let err = realm_voter_test - .with_voter_weight_record(®istrar_cookie, &voter_cookie) - .await - .err() - .unwrap(); - - // Assert - - // InstructionError::Custom(0) is returned for TransactionError::AccountInUse - assert_ix_err(err, InstructionError::Custom(0)); - - Ok(()) -} diff --git a/programs/token-haver/tests/fixtures/spl_governance.so b/programs/token-haver/tests/fixtures/spl_governance.so deleted file mode 100755 index 84786e9a1d8cdc4ca1b65a7d3e90c59aaa218fed..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 673864 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
=;tyYo+JA;`uJ4r`*Z2n&xIcqjZdGy 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, -} - -impl RealmCookie { - pub fn get_realm_authority(&self) -> Keypair { - clone_keypair(&self.realm_authority) - } -} - -pub struct ProposalCookie { - pub address: Pubkey, - pub account: ProposalV2, -} - -pub struct TokenOwnerRecordCookie { - pub address: Pubkey, - pub account: TokenOwnerRecordV2, -} - -pub struct GovernanceTest { - pub program_id: Pubkey, - pub bench: Arc, - pub next_id: u8, - pub community_voter_weight_addin: Option, - pub max_community_voter_weight_addin: Option, -} - -impl GovernanceTest { - pub fn program_id() -> Pubkey { - Pubkey::from_str("Governance111111111111111111111111111111111").unwrap() - } - - #[allow(dead_code)] - pub fn add_program(program_test: &mut ProgramTest) { - program_test.add_program("spl_governance", Self::program_id(), None); - } - - #[allow(dead_code)] - pub fn new( - bench: Arc, - community_voter_weight_addin: Option, - max_community_voter_weight_addin: Option, - ) -> Self { - GovernanceTest { - bench, - program_id: Self::program_id(), - next_id: 0, - community_voter_weight_addin, - max_community_voter_weight_addin, - } - } - - #[allow(dead_code)] - pub async fn with_realm(&mut self) -> Result { - let realm_authority = Keypair::new(); - - let community_mint_cookie = self.bench.with_mint().await?; - let council_mint_cookie = self.bench.with_mint().await?; - - self.next_id += 1; - let realm_name = format!("Realm #{}", self.next_id).to_string(); - - let min_community_weight_to_create_governance = 1; - let community_mint_max_voter_weight_source = MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION; - - let realm_key = get_realm_address(&self.program_id, &realm_name); - - let community_token_config_args = GoverningTokenConfigAccountArgs { - voter_weight_addin: self.community_voter_weight_addin, - max_voter_weight_addin: self.community_voter_weight_addin, - token_type: GoverningTokenType::default(), - }; - - let create_realm_ix = create_realm( - &self.program_id, - &realm_authority.pubkey(), - &community_mint_cookie.address, - &self.bench.payer.pubkey(), - Some(council_mint_cookie.address), - Some(community_token_config_args), - None, - realm_name.clone(), - min_community_weight_to_create_governance, - community_mint_max_voter_weight_source.clone(), - ); - - self.bench - .process_transaction(&[create_realm_ix], None) - .await?; - - let account = RealmV2 { - account_type: GovernanceAccountType::RealmV2, - community_mint: community_mint_cookie.address, - - name: realm_name, - reserved: [0; 6], - authority: Some(realm_authority.pubkey()), - config: RealmConfig { - council_mint: Some(council_mint_cookie.address), - reserved: [0; 6], - min_community_weight_to_create_governance, - legacy1: 0, - legacy2: 0, - community_mint_max_voter_weight_source, - }, - reserved_v2: [0; 128], - legacy1: 0, - }; - - Ok(RealmCookie { - address: realm_key, - account, - realm_authority, - community_mint_cookie, - council_mint_cookie: Some(council_mint_cookie), - }) - } - - #[allow(dead_code)] - pub async fn with_proposal( - &mut self, - realm_cookie: &RealmCookie, - ) -> Result { - let token_account_cookie = self - .bench - .with_token_account(&realm_cookie.account.community_mint) - .await?; - - let token_owner = self.bench.payer.pubkey(); - let council_mint_cookie = realm_cookie.council_mint_cookie.as_ref().unwrap(); - let governing_token_mint = council_mint_cookie.address; - - let governing_token_account_cookie = self - .bench - .with_tokens(council_mint_cookie, &token_owner, 1) - .await?; - - let proposal_owner_record_key = get_token_owner_record_address( - &self.program_id, - &realm_cookie.address, - &governing_token_mint, - &token_owner, - ); - - let create_tor_ix = create_token_owner_record( - &self.program_id, - &realm_cookie.address, - &self.bench.payer.pubkey(), - &governing_token_mint, - &self.bench.payer.pubkey(), - ); - - self.bench - .process_transaction(&[create_tor_ix], None) - .await?; - - let deposit_ix = deposit_governing_tokens( - &self.program_id, - &realm_cookie.address, - &governing_token_account_cookie.address, - &token_owner, - &token_owner, - &self.bench.payer.pubkey(), - 1, - &governing_token_mint, - ); - - self.bench.process_transaction(&[deposit_ix], None).await?; - - let governance_key = get_governance_address( - &self.program_id, - &realm_cookie.address, - &token_account_cookie.address, - ); - - let create_governance_ix = create_governance( - &self.program_id, - &realm_cookie.address, - Some(&token_account_cookie.address), - &proposal_owner_record_key, - &self.bench.payer.pubkey(), - &realm_cookie.realm_authority.pubkey(), - None, - spl_governance::state::governance::GovernanceConfig { - min_community_weight_to_create_proposal: 1, - min_transaction_hold_up_time: 0, - min_council_weight_to_create_proposal: 1, - community_vote_threshold: VoteThreshold::YesVotePercentage(60), - voting_base_time: 600, - community_vote_tipping: VoteTipping::Strict, - council_vote_threshold: VoteThreshold::YesVotePercentage(60), - council_veto_vote_threshold: VoteThreshold::Disabled, - council_vote_tipping: VoteTipping::Disabled, - community_veto_vote_threshold: VoteThreshold::Disabled, - voting_cool_off_time: 0, - deposit_exempt_proposal_count: 10, - }, - ); - - self.bench - .process_transaction( - &[create_governance_ix], - Some(&[&realm_cookie.realm_authority]), - ) - .await?; - - let proposal_governing_token_mint = realm_cookie.account.community_mint; - let proposal_seed = Pubkey::new_unique(); - - let proposal_key = get_proposal_address( - &self.program_id, - &governance_key, - &proposal_governing_token_mint, - &proposal_seed, - ); - - let create_proposal_ix = create_proposal( - &self.program_id, - &governance_key, - &proposal_owner_record_key, - &token_owner, - &self.bench.payer.pubkey(), - None, - &realm_cookie.address, - String::from("Proposal #1"), - String::from("Proposal #1 link"), - &proposal_governing_token_mint, - spl_governance::state::proposal::VoteType::SingleChoice, - vec!["Yes".to_string()], - true, - &proposal_seed, - ); - - let sign_off_proposal_ix = sign_off_proposal( - &self.program_id, - &realm_cookie.address, - &governance_key, - &proposal_key, - &token_owner, - Some(&proposal_owner_record_key), - ); - - self.bench - .process_transaction(&[create_proposal_ix, sign_off_proposal_ix], None) - .await?; - - let account = ProposalV2 { - account_type: GovernanceAccountType::GovernanceV2, - governing_token_mint: proposal_governing_token_mint, - state: ProposalState::Voting, - governance: governance_key, - token_owner_record: proposal_owner_record_key, - signatories_count: 1, - signatories_signed_off_count: 1, - vote_type: spl_governance::state::proposal::VoteType::SingleChoice, - options: vec![], - deny_vote_weight: Some(1), - veto_vote_weight: 0, - abstain_vote_weight: None, - start_voting_at: None, - draft_at: 1, - signing_off_at: None, - voting_at: None, - voting_at_slot: None, - voting_completed_at: None, - executing_at: None, - closed_at: None, - execution_flags: spl_governance::state::enums::InstructionExecutionFlags::None, - max_vote_weight: None, - max_voting_time: None, - reserved: [0; 64], - name: String::from("Proposal #1"), - description_link: String::from("Proposal #1 link"), - reserved1: 0, - vote_threshold: None, - }; - - Ok(ProposalCookie { - address: proposal_key, - account, - }) - } - - #[allow(dead_code)] - pub async fn with_token_owner_record( - &mut self, - realm_cookie: &RealmCookie, - token_owner_cookie: &WalletCookie, - ) -> Result { - let token_owner_record_key = get_token_owner_record_address( - &self.program_id, - &realm_cookie.address, - &realm_cookie.account.community_mint, - &token_owner_cookie.address, - ); - - let create_tor_ix = create_token_owner_record( - &self.program_id, - &realm_cookie.address, - &token_owner_cookie.address, - &realm_cookie.account.community_mint, - &self.bench.payer.pubkey(), - ); - - self.bench - .process_transaction(&[create_tor_ix], None) - .await?; - - let account = TokenOwnerRecordV2 { - account_type: GovernanceAccountType::TokenOwnerRecordV2, - realm: realm_cookie.address, - governing_token_mint: realm_cookie.account.community_mint, - governing_token_owner: token_owner_cookie.address, - governing_token_deposit_amount: 0, - unrelinquished_votes_count: 0, - - outstanding_proposal_count: 0, - reserved: [0; 6], - governance_delegate: None, - reserved_v2: [0; 128], - version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, - }; - - Ok(TokenOwnerRecordCookie { - address: token_owner_record_key, - account, - }) - } - - #[allow(dead_code)] - pub async fn relinquish_vote( - &mut self, - proposal_cookie: &ProposalCookie, - token_owner_cookie: &WalletCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - ) -> Result<(), TransportError> { - let relinquish_vote_ix = relinquish_vote( - &self.program_id, - &token_owner_record_cookie.account.realm, - &proposal_cookie.account.governance, - &proposal_cookie.address, - &token_owner_record_cookie.address, - &proposal_cookie.account.governing_token_mint, - Some(token_owner_record_cookie.account.governing_token_owner), - Some(self.bench.payer.pubkey()), - ); - - self.bench - .process_transaction(&[relinquish_vote_ix], Some(&[&token_owner_cookie.signer])) - .await?; - - Ok(()) - } - - #[allow(dead_code)] - pub async fn get_proposal(&mut self, proposal_key: &Pubkey) -> ProposalV2 { - self.bench - .get_borsh_account::(proposal_key) - .await - } - - #[allow(dead_code)] - pub async fn get_token_owner_record( - &mut self, - token_owner_record_key: &Pubkey, - ) -> TokenOwnerRecordV2 { - self.bench - .get_borsh_account::(token_owner_record_key) - .await - } -} diff --git a/programs/token-haver/tests/program_test/mod.rs b/programs/token-haver/tests/program_test/mod.rs deleted file mode 100644 index 4ec44783..00000000 --- a/programs/token-haver/tests/program_test/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod governance_test; -pub mod program_test_bench; -pub mod token_haver_test; -pub mod tools; diff --git a/programs/token-haver/tests/program_test/program_test_bench.rs b/programs/token-haver/tests/program_test/program_test_bench.rs deleted file mode 100644 index cd65942a..00000000 --- a/programs/token-haver/tests/program_test/program_test_bench.rs +++ /dev/null @@ -1,324 +0,0 @@ -use std::cell::RefCell; - -use anchor_lang::{ - prelude::{Pubkey, Rent}, - AccountDeserialize, -}; - -use solana_program::{borsh::try_from_slice_unchecked, system_program}; -use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; -use solana_sdk::{ - account::{Account, ReadableAccount}, - instruction::Instruction, - program_pack::Pack, - signature::Keypair, - signer::Signer, - system_instruction, - transaction::Transaction, - transport::TransportError, -}; - -use borsh::BorshDeserialize; - -use crate::program_test::tools::clone_keypair; - -pub struct MintCookie { - pub address: Pubkey, - pub mint_authority: Keypair, - pub freeze_authority: Option, -} -pub struct TokenAccountCookie { - pub address: Pubkey, -} - -#[derive(Debug)] -pub struct WalletCookie { - pub address: Pubkey, - pub account: Account, - - pub signer: Keypair, -} - -pub struct ProgramTestBench { - pub context: RefCell, - pub payer: Keypair, - pub rent: Rent, -} - -impl ProgramTestBench { - /// Create new bench given a ProgramTest instance populated with all of the - /// desired programs. - pub async fn start_new(program_test: ProgramTest) -> Self { - let mut context = program_test.start_with_context().await; - - let payer = clone_keypair(&context.payer); - - let rent = context.banks_client.get_rent().await.unwrap(); - - Self { - payer, - context: RefCell::new(context), - rent, - } - } - - #[allow(dead_code)] - pub async fn process_transaction( - &self, - instructions: &[Instruction], - signers: Option<&[&Keypair]>, - ) -> Result<(), BanksClientError> { - let mut context = self.context.borrow_mut(); - - let mut transaction = - Transaction::new_with_payer(&instructions, Some(&context.payer.pubkey())); - - let mut all_signers = vec![&context.payer]; - - if let Some(signers) = signers { - all_signers.extend_from_slice(signers); - } - - transaction.sign(&all_signers, context.last_blockhash); - - context - .banks_client - .process_transaction_with_commitment( - transaction, - solana_sdk::commitment_config::CommitmentLevel::Processed, - ) - .await - } - - pub async fn get_clock(&self) -> solana_program::clock::Clock { - self.context - .borrow_mut() - .banks_client - .get_sysvar::() - .await - .unwrap() - } - - #[allow(dead_code)] - pub async fn advance_clock(&self) { - let clock = self.get_clock().await; - self.context - .borrow_mut() - .warp_to_slot(clock.slot + 2) - .unwrap(); - } - - pub async fn with_mint(&self) -> Result { - let mint_keypair = Keypair::new(); - let mint_authority = Keypair::new(); - let freeze_authority = Keypair::new(); - - self.create_mint(&mint_keypair, &mint_authority.pubkey(), None) - .await?; - - Ok(MintCookie { - address: mint_keypair.pubkey(), - mint_authority, - freeze_authority: Some(freeze_authority), - }) - } - - #[allow(dead_code)] - pub async fn create_mint( - &self, - mint_keypair: &Keypair, - mint_authority: &Pubkey, - freeze_authority: Option<&Pubkey>, - ) -> Result<(), BanksClientError> { - let mint_rent = self.rent.minimum_balance(spl_token::state::Mint::LEN); - - let instructions = [ - system_instruction::create_account( - &self.context.borrow().payer.pubkey(), - &mint_keypair.pubkey(), - mint_rent, - spl_token::state::Mint::LEN as u64, - &spl_token::id(), - ), - spl_token::instruction::initialize_mint( - &spl_token::id(), - &mint_keypair.pubkey(), - mint_authority, - freeze_authority, - 0, - ) - .unwrap(), - ]; - - self.process_transaction(&instructions, Some(&[mint_keypair])) - .await - } - - #[allow(dead_code)] - pub async fn with_token_account( - &self, - token_mint: &Pubkey, - ) -> Result { - let token_account_keypair = Keypair::new(); - self.create_token_account(&token_account_keypair, token_mint, &self.payer.pubkey()) - .await?; - - Ok(TokenAccountCookie { - address: token_account_keypair.pubkey(), - }) - } - - #[allow(dead_code)] - pub async fn with_tokens( - &self, - mint_cookie: &MintCookie, - owner: &Pubkey, - amount: u64, - ) -> Result { - let token_account_keypair = Keypair::new(); - - self.create_token_account(&token_account_keypair, &mint_cookie.address, owner) - .await?; - - self.mint_tokens( - &mint_cookie.address, - &mint_cookie.mint_authority, - &token_account_keypair.pubkey(), - amount, - ) - .await?; - - Ok(TokenAccountCookie { - address: token_account_keypair.pubkey(), - }) - } - - pub async fn mint_tokens( - &self, - token_mint: &Pubkey, - token_mint_authority: &Keypair, - token_account: &Pubkey, - amount: u64, - ) -> Result<(), BanksClientError> { - let mint_instruction = spl_token::instruction::mint_to( - &spl_token::id(), - token_mint, - token_account, - &token_mint_authority.pubkey(), - &[], - amount, - ) - .unwrap(); - - self.process_transaction(&[mint_instruction], Some(&[token_mint_authority])) - .await - } - - #[allow(dead_code)] - pub async fn create_token_account( - &self, - token_account_keypair: &Keypair, - token_mint: &Pubkey, - owner: &Pubkey, - ) -> Result<(), BanksClientError> { - let rent = self - .context - .borrow_mut() - .banks_client - .get_rent() - .await - .unwrap(); - - let create_account_instruction = system_instruction::create_account( - &self.context.borrow().payer.pubkey(), - &token_account_keypair.pubkey(), - rent.minimum_balance(spl_token::state::Account::get_packed_len()), - spl_token::state::Account::get_packed_len() as u64, - &spl_token::id(), - ); - - let initialize_account_instruction = spl_token::instruction::initialize_account( - &spl_token::id(), - &token_account_keypair.pubkey(), - token_mint, - owner, - ) - .unwrap(); - - self.process_transaction( - &[create_account_instruction, initialize_account_instruction], - Some(&[token_account_keypair]), - ) - .await - } - - #[allow(dead_code)] - pub async fn with_wallet(&self) -> WalletCookie { - let account_rent = self.rent.minimum_balance(0); - let account_keypair = Keypair::new(); - - let create_account_ix = system_instruction::create_account( - &self.context.borrow().payer.pubkey(), - &account_keypair.pubkey(), - account_rent, - 0, - &system_program::id(), - ); - - self.process_transaction(&[create_account_ix], Some(&[&account_keypair])) - .await - .unwrap(); - - let account = Account { - lamports: account_rent, - data: vec![], - owner: system_program::id(), - executable: false, - rent_epoch: 0, - }; - - WalletCookie { - address: account_keypair.pubkey(), - account, - signer: account_keypair, - } - } - - #[allow(dead_code)] - pub async fn get_account(&self, address: &Pubkey) -> Option { - self.context - .borrow_mut() - .banks_client - .get_account(*address) - .await - .unwrap() - } - - #[allow(dead_code)] - pub async fn get_borsh_account(&self, address: &Pubkey) -> T { - self.get_account(address) - .await - .map(|a| try_from_slice_unchecked(&a.data).unwrap()) - .unwrap_or_else(|| panic!("GET-TEST-ACCOUNT-ERROR: Account {} not found", address)) - } - - #[allow(dead_code)] - pub async fn get_account_data(&self, address: Pubkey) -> Vec { - self.context - .borrow_mut() - .banks_client - .get_account(address) - .await - .unwrap() - .unwrap() - .data() - .to_vec() - } - - #[allow(dead_code)] - pub async fn get_anchor_account(&self, address: Pubkey) -> T { - let data = self.get_account_data(address).await; - let mut data_slice: &[u8] = &data; - AccountDeserialize::try_deserialize(&mut data_slice).unwrap() - } -} diff --git a/programs/token-haver/tests/program_test/token_haver_test.rs b/programs/token-haver/tests/program_test/token_haver_test.rs deleted file mode 100644 index 8b560eb0..00000000 --- a/programs/token-haver/tests/program_test/token_haver_test.rs +++ /dev/null @@ -1,297 +0,0 @@ -use std::sync::Arc; - -use anchor_lang::prelude::Pubkey; - -use gpl_realm_voter::state::max_voter_weight_record::MaxVoterWeightRecord; -use gpl_realm_voter::state::*; - -use solana_program_test::{BanksClientError, ProgramTest}; -use solana_sdk::instruction::Instruction; -use solana_sdk::signature::Keypair; -use solana_sdk::signer::Signer; - -use crate::program_test::governance_test::GovernanceTest; -use crate::program_test::program_test_bench::ProgramTestBench; - -use crate::program_test::governance_test::RealmCookie; -use crate::program_test::program_test_bench::WalletCookie; - -use crate::program_test::tools::NopOverride; - -use crate::program_test::governance_test::TokenOwnerRecordCookie; - -#[derive(Debug, PartialEq)] -pub struct RegistrarCookie { - pub address: Pubkey, - pub account: Registrar, - - pub realm_authority: Keypair, - pub mints: Vec, -} - -pub struct VoterWeightRecordCookie { - pub address: Pubkey, - pub account: VoterWeightRecord, -} - -pub struct MaxVoterWeightRecordCookie { - pub address: Pubkey, - pub account: MaxVoterWeightRecord, -} - -pub struct GovernanceProgramCookie { - pub program_id: Pubkey, -} - -pub struct RealmVoterTest { - pub program_id: Pubkey, - pub bench: Arc, - pub governance: GovernanceTest, -} - -impl RealmVoterTest { - #[allow(dead_code)] - pub fn add_program(program_test: &mut ProgramTest) { - program_test.add_program("gpl_realm_voter", gpl_realm_voter::id(), None); - } - - #[allow(dead_code)] - pub async fn start_new() -> Self { - let mut program_test = ProgramTest::default(); - - RealmVoterTest::add_program(&mut program_test); - GovernanceTest::add_program(&mut program_test); - - let program_id = gpl_realm_voter::id(); - - let bench = ProgramTestBench::start_new(program_test).await; - let bench_rc = Arc::new(bench); - - let governance_bench = - GovernanceTest::new(bench_rc.clone(), Some(program_id), Some(program_id)); - - Self { - program_id, - bench: bench_rc, - governance: governance_bench, - } - } - - #[allow(dead_code)] - pub async fn with_governance_program( - &mut self, - program_id: Option, - ) -> GovernanceProgramCookie { - let program_id = program_id.unwrap_or(GovernanceTest::program_id()); - - // Use the spl-governance instance used for testing - GovernanceProgramCookie { program_id } - } - - #[allow(dead_code)] - pub async fn with_registrar( - &mut self, - realm_cookie: &RealmCookie, - ) -> Result { - self.with_registrar_using_ix(realm_cookie, NopOverride, None) - .await - } - - #[allow(dead_code)] - pub async fn with_registrar_using_ix( - &mut self, - realm_cookie: &RealmCookie, - instruction_override: F, - signers_override: Option<&[&Keypair]>, - ) -> Result { - let registrar_key = - get_registrar_address(&realm_cookie.address, &realm_cookie.account.community_mint); - - let mints = &[realm_cookie.account.community_mint].to_vec(); - - let data = - anchor_lang::InstructionData::data(&gpl_realm_voter::instruction::CreateRegistrar { - mints: mints.clone(), - }); - - let accounts = anchor_lang::ToAccountMetas::to_account_metas( - &gpl_realm_voter::accounts::CreateRegistrar { - registrar: registrar_key, - realm: realm_cookie.address, - governance_program_id: self.governance.program_id, - governing_token_mint: realm_cookie.account.community_mint, - realm_authority: realm_cookie.get_realm_authority().pubkey(), - payer: self.bench.payer.pubkey(), - system_program: solana_sdk::system_program::id(), - }, - None, - ); - - let mut create_registrar_ix = Instruction { - program_id: gpl_realm_voter::id(), - accounts, - data, - }; - - instruction_override(&mut create_registrar_ix); - - let default_signers = &[&realm_cookie.realm_authority]; - let signers = signers_override.unwrap_or(default_signers); - - self.bench - .process_transaction(&[create_registrar_ix], Some(signers)) - .await?; - - let account = Registrar { - governance_program_id: self.governance.program_id, - realm: realm_cookie.address, - governing_token_mint: realm_cookie.account.community_mint, - mints: mints.clone(), - }; - - Ok(RegistrarCookie { - address: registrar_key, - account, - realm_authority: realm_cookie.get_realm_authority(), - mints: mints.clone(), - }) - } - - #[allow(dead_code)] - pub async fn with_voter_weight_record( - &self, - registrar_cookie: &RegistrarCookie, - voter_cookie: &WalletCookie, - ) -> Result { - self.with_voter_weight_record_using_ix(registrar_cookie, voter_cookie, NopOverride) - .await - } - - #[allow(dead_code)] - pub async fn with_voter_weight_record_using_ix( - &self, - registrar_cookie: &RegistrarCookie, - voter_cookie: &WalletCookie, - instruction_override: F, - ) -> Result { - let governing_token_owner = voter_cookie.address; - - let (voter_weight_record_key, _) = Pubkey::find_program_address( - &[ - b"voter-weight-record".as_ref(), - registrar_cookie.account.realm.as_ref(), - registrar_cookie.account.governing_token_mint.as_ref(), - governing_token_owner.as_ref(), - ], - &gpl_realm_voter::id(), - ); - - let data = anchor_lang::InstructionData::data( - &gpl_realm_voter::instruction::CreateVoterWeightRecord { - governing_token_owner, - }, - ); - - let accounts = gpl_realm_voter::accounts::CreateVoterWeightRecord { - registrar: registrar_cookie.address, - voter_weight_record: voter_weight_record_key, - payer: self.bench.payer.pubkey(), - system_program: solana_sdk::system_program::id(), - }; - - let mut create_voter_weight_record_ix = Instruction { - program_id: gpl_realm_voter::id(), - accounts: anchor_lang::ToAccountMetas::to_account_metas(&accounts, None), - data, - }; - - instruction_override(&mut create_voter_weight_record_ix); - - self.bench - .process_transaction(&[create_voter_weight_record_ix], None) - .await?; - - let account = VoterWeightRecord { - realm: registrar_cookie.account.realm, - governing_token_mint: registrar_cookie.account.governing_token_mint, - governing_token_owner, - voter_weight: 0, - voter_weight_expiry: Some(0), - weight_action: None, - weight_action_target: None, - reserved: [0; 8], - }; - - Ok(VoterWeightRecordCookie { - address: voter_weight_record_key, - account, - }) - } - - #[allow(dead_code)] - pub async fn update_voter_weight_record( - &self, - registrar_cookie: &RegistrarCookie, - voter_weight_record_cookie: &mut VoterWeightRecordCookie, - token_owner_record_cookie: &TokenOwnerRecordCookie, - ) -> Result<(), BanksClientError> { - let data = anchor_lang::InstructionData::data( - &gpl_realm_voter::instruction::UpdateVoterWeightRecord {}, - ); - - let accounts = gpl_realm_voter::accounts::UpdateVoterWeightRecord { - registrar: registrar_cookie.address, - voter_weight_record: voter_weight_record_cookie.address, - token_owner_record: token_owner_record_cookie.address, - }; - - let account_metas = anchor_lang::ToAccountMetas::to_account_metas(&accounts, None); - - let instructions = vec![Instruction { - program_id: gpl_realm_voter::id(), - accounts: account_metas, - data, - }]; - - self.bench.process_transaction(&instructions, None).await - } - - #[allow(dead_code)] - pub async fn configure_voter_weights( - &self, - registrar_cookie: &RegistrarCookie, - max_voter_weight_record_cookie: &mut MaxVoterWeightRecordCookie, - realm_member_voter_weight: u64, - max_voter_weight: u64, - ) -> Result<(), BanksClientError> { - self.configure_voter_weights_using_ix( - registrar_cookie, - max_voter_weight_record_cookie, - realm_member_voter_weight, - max_voter_weight, - NopOverride, - None, - ) - .await - } - - #[allow(dead_code)] - pub async fn get_registrar_account(&mut self, registrar: &Pubkey) -> Registrar { - self.bench.get_anchor_account::(*registrar).await - } - - #[allow(dead_code)] - pub async fn get_max_voter_weight_record( - &self, - max_voter_weight_record: &Pubkey, - ) -> MaxVoterWeightRecord { - self.bench - .get_anchor_account(*max_voter_weight_record) - .await - } - - #[allow(dead_code)] - pub async fn get_voter_weight_record(&self, voter_weight_record: &Pubkey) -> VoterWeightRecord { - self.bench.get_anchor_account(*voter_weight_record).await - } -} diff --git a/programs/token-haver/tests/program_test/tools.rs b/programs/token-haver/tests/program_test/tools.rs deleted file mode 100644 index 8229f783..00000000 --- a/programs/token-haver/tests/program_test/tools.rs +++ /dev/null @@ -1,80 +0,0 @@ -use anchor_lang::prelude::ERROR_CODE_OFFSET; -use gpl_realm_voter::error::TokenHaverError; -use solana_program::instruction::InstructionError; -use solana_program_test::BanksClientError; -use solana_sdk::{signature::Keypair, transaction::TransactionError, transport::TransportError}; -use spl_governance_tools::error::GovernanceToolsError; - -pub fn clone_keypair(source: &Keypair) -> Keypair { - Keypair::from_bytes(&source.to_bytes()).unwrap() -} - -/// NOP (No Operation) Override function -#[allow(non_snake_case)] -pub fn NopOverride(_: &mut T) {} - -#[allow(dead_code)] -pub fn assert_realm_voter_err( - banks_client_error: BanksClientError, - realm_voter_error: TokenHaverError, -) { - let tx_error = banks_client_error.unwrap(); - - match tx_error { - TransactionError::InstructionError(_, instruction_error) => match instruction_error { - InstructionError::Custom(e) => { - assert_eq!(e, realm_voter_error as u32 + ERROR_CODE_OFFSET) - } - _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), - }, - _ => panic!("{:?} Is not InstructionError", tx_error), - }; -} - -#[allow(dead_code)] -pub fn assert_gov_tools_err( - banks_client_error: TransportError, - gov_tools_error: GovernanceToolsError, -) { - let tx_error = banks_client_error.unwrap(); - - match tx_error { - TransactionError::InstructionError(_, instruction_error) => match instruction_error { - InstructionError::Custom(e) => { - assert_eq!(e, gov_tools_error as u32) - } - _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), - }, - _ => panic!("{:?} Is not InstructionError", tx_error), - }; -} - -#[allow(dead_code)] -pub fn assert_anchor_err( - banks_client_error: BanksClientError, - anchor_error: anchor_lang::error::ErrorCode, -) { - let tx_error = banks_client_error.unwrap(); - - match tx_error { - TransactionError::InstructionError(_, instruction_error) => match instruction_error { - InstructionError::Custom(e) => { - assert_eq!(e, anchor_error as u32) - } - _ => panic!("{:?} Is not InstructionError::Custom()", instruction_error), - }, - _ => panic!("{:?} Is not InstructionError", tx_error), - }; -} - -#[allow(dead_code)] -pub fn assert_ix_err(banks_client_error: BanksClientError, ix_error: InstructionError) { - let tx_error = banks_client_error.unwrap(); - - match tx_error { - TransactionError::InstructionError(_, instruction_error) => { - assert_eq!(instruction_error, ix_error); - } - _ => panic!("{:?} Is not InstructionError", tx_error), - }; -} diff --git a/programs/token-haver/tests/update_voter_weight_record.rs b/programs/token-haver/tests/update_voter_weight_record.rs deleted file mode 100644 index 74e142a0..00000000 --- a/programs/token-haver/tests/update_voter_weight_record.rs +++ /dev/null @@ -1,202 +0,0 @@ -use crate::program_test::token_haver_test::RealmVoterTest; -use gpl_realm_voter::{error::TokenHaverError, state::CollectionItemChangeType}; -use program_test::tools::*; -use solana_program_test::*; -use solana_sdk::transport::TransportError; -mod program_test; - -#[tokio::test] -async fn test_update_voter_weight_record() -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - // Create TokenOwnerRecord for other Realm - let realm_cookie2 = realm_voter_test.governance.with_realm().await?; - let token_owner_cookie = realm_voter_test.bench.with_wallet().await; - let token_owner_record_cookie = realm_voter_test - .governance - .with_token_owner_record(&realm_cookie2, &token_owner_cookie) - .await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - let mut voter_weight_record_cookie = realm_voter_test - .with_voter_weight_record(®istrar_cookie, &token_owner_cookie) - .await?; - - realm_voter_test - .configure_voter_weights( - ®istrar_cookie, - &mut max_voter_weight_record_cookie, - 10, // realm_member_voter_weight - 110, - ) - .await?; - - let clock = realm_voter_test.bench.get_clock().await; - - // Act - realm_voter_test - .update_voter_weight_record( - ®istrar_cookie, - &mut voter_weight_record_cookie, - &token_owner_record_cookie, - ) - .await?; - - // Assert - - let voter_weight_record = realm_voter_test - .get_voter_weight_record(&voter_weight_record_cookie.address) - .await; - - assert_eq!(voter_weight_record.voter_weight, 10); - assert_eq!(voter_weight_record.voter_weight_expiry, Some(clock.slot)); - assert_eq!(voter_weight_record.weight_action, None); - assert_eq!(voter_weight_record.weight_action_target, None); - - Ok(()) -} - -#[tokio::test] -async fn test_update_voter_weight_record_with_token_owner_record_from_own_realm_not_allowed_error( -) -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let token_owner_cookie = realm_voter_test.bench.with_wallet().await; - let token_owner_record_cookie = realm_voter_test - .governance - .with_token_owner_record(&realm_cookie, &token_owner_cookie) - .await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - ) - .await?; - - let mut voter_weight_record_cookie = realm_voter_test - .with_voter_weight_record(®istrar_cookie, &token_owner_cookie) - .await?; - - // Act - let err = realm_voter_test - .update_voter_weight_record( - ®istrar_cookie, - &mut voter_weight_record_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - assert_realm_voter_err(err, TokenHaverError::TokenOwnerRecordFromOwnRealmNotAllowed); - - Ok(()) -} - -#[tokio::test] -async fn test_update_voter_weight_record_for_member_from_not_configured_governance_program_error( -) -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - // Create TokenOwnerRecord for other Realm - let realm_cookie2 = realm_voter_test.governance.with_realm().await?; - let token_owner_cookie = realm_voter_test.bench.with_wallet().await; - let token_owner_record_cookie = realm_voter_test - .governance - .with_token_owner_record(&realm_cookie2, &token_owner_cookie) - .await?; - - let mut voter_weight_record_cookie = realm_voter_test - .with_voter_weight_record(®istrar_cookie, &token_owner_cookie) - .await?; - - // Act - let err = realm_voter_test - .update_voter_weight_record( - ®istrar_cookie, - &mut voter_weight_record_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - - assert_realm_voter_err(err, TokenHaverError::GovernanceProgramNotConfigured); - - Ok(()) -} - -#[tokio::test] -async fn test_update_voter_weight_record_with_token_owner_record_must_match_error( -) -> Result<(), TransportError> { - // Arrange - let mut realm_voter_test = RealmVoterTest::start_new().await; - - let realm_cookie = realm_voter_test.governance.with_realm().await?; - - let registrar_cookie = realm_voter_test.with_registrar(&realm_cookie).await?; - - let governance_program_cookie = realm_voter_test.with_governance_program(None).await; - - realm_voter_test - .configure_governance_program( - ®istrar_cookie, - &governance_program_cookie, - CollectionItemChangeType::Upsert, - ) - .await?; - - // Create TokenOwnerRecord for other Realm - let realm_cookie2 = realm_voter_test.governance.with_realm().await?; - let token_owner_cookie = realm_voter_test.bench.with_wallet().await; - let token_owner_record_cookie = realm_voter_test - .governance - .with_token_owner_record(&realm_cookie2, &token_owner_cookie) - .await?; - - let token_owner_cookie2 = realm_voter_test.bench.with_wallet().await; - - let mut voter_weight_record_cookie = realm_voter_test - .with_voter_weight_record(®istrar_cookie, &token_owner_cookie2) - .await?; - - // Act - let err = realm_voter_test - .update_voter_weight_record( - ®istrar_cookie, - &mut voter_weight_record_cookie, - &token_owner_record_cookie, - ) - .await - .err() - .unwrap(); - - // Assert - - assert_realm_voter_err(err, TokenHaverError::GoverningTokenOwnerMustMatch); - - Ok(()) -} diff --git a/programs/token-voter/Cargo.toml b/programs/token-voter/Cargo.toml index 07915345..6c905b1e 100644 --- a/programs/token-voter/Cargo.toml +++ b/programs/token-voter/Cargo.toml @@ -21,10 +21,7 @@ anchor-lang = { version = "0.30.0", features = ["init-if-needed"] } anchor-spl = "0.30.0" arrayref = "0.3.7" solana-program = "1.18.12" -# spl-governance = { version = "4.0.0", features = ["no-entrypoint"] } -# spl-transfer-hook-interface = { version = "0.6.3" } -spl-governance = { git = "https://github.com/crypt0miester/solana-program-library.git", branch = "gib-bounty-jlFb5", default-features = false, features = ["no-entrypoint"] } -spl-transfer-hook-example = { git = "https://github.com/crypt0miester/solana-program-library.git", branch = "gib-bounty-jlFb5", default-features = false, features = ["no-entrypoint"] } +spl-governance = { version = "4.0.0", features = ["no-entrypoint"] } spl-tlv-account-resolution = { version = "0.6.3" } spl-transfer-hook-interface = { version = "0.6.3" } spl-governance-tools = "0.1.4" @@ -38,6 +35,7 @@ spl-governance-addin-api = "0.1.4" [dev-dependencies] borsh = "0.10.3" spl-associated-token-account = { version = "^3.0.2", features = ["no-entrypoint"] } +spl-transfer-hook-example = { version = "0.6.0", features = ["no-entrypoint"] } solana-sdk = "1.18.12" solana-program-test = "1.18.12" log = "0.4.14" diff --git a/programs/token-voter/src/instructions/close_voter.rs b/programs/token-voter/src/instructions/close_voter.rs index cad3af3a..b453b5e7 100644 --- a/programs/token-voter/src/instructions/close_voter.rs +++ b/programs/token-voter/src/instructions/close_voter.rs @@ -1,11 +1,10 @@ use { - crate::{error::*, state::*, tools::spl_token::get_spl_token_amount}, + crate::{error::*, state::*, tools::spl_token::{get_spl_token_amount, get_spl_token_owner}}, anchor_lang::prelude::*, anchor_spl::{ token_2022::{self, CloseAccount}, token_interface::TokenInterface, }, - spl_governance::tools::spl_token::get_spl_token_owner, }; // Remaining accounts must be all the token accounts owned by voter account they want to close, diff --git a/programs/token-voter/src/instructions/withdraw.rs b/programs/token-voter/src/instructions/withdraw.rs index a00ae6f2..0b624108 100644 --- a/programs/token-voter/src/instructions/withdraw.rs +++ b/programs/token-voter/src/instructions/withdraw.rs @@ -108,7 +108,7 @@ pub fn withdraw<'key, 'accounts, 'remaining, 'info>( registrar, voter_authority_key, )?; - token_owner_record.assert_can_withdraw_governing_tokens(Clock::get()?.unix_timestamp)?; + token_owner_record.assert_can_withdraw_governing_tokens()?; let deposit_entry = voter.active_deposit_mut(deposit_entry_index)?; diff --git a/programs/token-voter/src/tools/spl_token.rs b/programs/token-voter/src/tools/spl_token.rs index 93abc7a8..8dccaa90 100644 --- a/programs/token-voter/src/tools/spl_token.rs +++ b/programs/token-voter/src/tools/spl_token.rs @@ -55,7 +55,7 @@ pub fn transfer_checked_spl_tokens<'a>( mint_info: &AccountInfo<'a>, additional_accounts: &[AccountInfo<'a>], ) -> ProgramResult { - let spl_token_program_id = spl_token_info.owner; + let spl_token_program_id = spl_token_info.key; let mut transfer_instruction = spl_token_2022::instruction::transfer_checked( spl_token_program_id, @@ -135,7 +135,7 @@ pub fn transfer_spl_tokens_signed_checked<'a>( return Err(ProgramError::InvalidSeeds); } - let spl_token_program_id = spl_token_info.owner; + let spl_token_program_id = spl_token_info.key; let mut transfer_instruction = spl_token_2022::instruction::transfer_checked( spl_token_program_id, @@ -282,6 +282,17 @@ fn valid_mint_length(mint_data: &[u8]) -> bool { && ACCOUNTTYPE_MINT == mint_data[Mint::LEN]) } +/// Computationally cheap method to get owner from a token account +/// It reads owner without deserializing full account data +pub fn get_spl_token_owner(token_account_info: &AccountInfo) -> Result { + assert_is_valid_spl_token_account(token_account_info)?; + + // TokeAccount layout: mint(32), owner(32), amount(8) + let data = token_account_info.try_borrow_data()?; + let owner_data = array_ref![data, 32, 32]; + Ok(Pubkey::new_from_array(*owner_data)) +} + /// Get current TransferFee, returns 0 if no TransferFeeConfig exist. pub fn get_current_mint_fee(mint_info: &AccountInfo, amount: u64) -> Result { let mint_data = mint_info.try_borrow_data()?; diff --git a/programs/token-voter/tests/cast_token_vote.rs b/programs/token-voter/tests/cast_token_vote.rs index f4f5ba4e..21b396de 100644 --- a/programs/token-voter/tests/cast_token_vote.rs +++ b/programs/token-voter/tests/cast_token_vote.rs @@ -1,5 +1,4 @@ use crate::program_test::program_test_bench::MintType; -use anchor_spl::token_interface::spl_token_metadata_interface::borsh::BorshDeserialize; use program_test::token_voter_test::TokenVoterTest; use program_test::tools::*; use solana_program_test::*; @@ -9,6 +8,7 @@ use solana_sdk::signer::Signer; use solana_sdk::transport::TransportError; mod program_test; use crate::program_test::program_test_bench::TokenAccountCookie; +use anchor_lang::AnchorDeserialize; #[tokio::test] async fn test_cast_token_vote() -> Result<(), TransportError> { @@ -113,7 +113,7 @@ async fn test_cast_token_vote() -> Result<(), TransportError> { ) .await?; - let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie, &MintType::SplToken).await?; + let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie).await?; token_voter_test .governance @@ -166,7 +166,8 @@ async fn test_cast_token_vote_token_extension() -> Result<(), TransportError> { // Arrange let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; + let realm_cookie = token_voter_test.governance.with_realm().await?; + let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; @@ -191,7 +192,7 @@ async fn test_cast_token_vote_token_extension() -> Result<(), TransportError> { &token_account_keypair, &council_mint_cookie.address, &first_user_cookie.key.pubkey(), - &MintType::SplTokenExtensions, + &MintType::SplToken, true ) .await?; @@ -200,7 +201,7 @@ async fn test_cast_token_vote_token_extension() -> Result<(), TransportError> { &council_mint_cookie.mint_authority, &token_account_keypair.pubkey(), 100, - &MintType::SplTokenExtensions, + &MintType::SplToken, &first_user_cookie.key.pubkey(), true, ) @@ -278,7 +279,7 @@ async fn test_cast_token_vote_token_extension() -> Result<(), TransportError> { ) .await?; - let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie, &MintType::SplTokenExtensions).await?; + let proposal_cookie = token_voter_test.governance.with_proposal(&realm_cookie).await?; token_voter_test .governance @@ -336,7 +337,7 @@ async fn test_cast_token_vote_token_extension_transfer_fees() -> Result<(), Tran let realm_cookie = token_voter_test .governance - .with_realm_token_extension(&MintType::SplTokenExtensionsWithTransferFees) + .with_realm() .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -365,7 +366,7 @@ async fn test_cast_token_vote_token_extension_transfer_fees() -> Result<(), Tran &token_account_keypair, &council_mint_cookie.address, &first_user_cookie.key.pubkey(), - &MintType::SplTokenExtensionsWithTransferFees, + &MintType::SplToken, true, ) .await?; @@ -377,7 +378,7 @@ async fn test_cast_token_vote_token_extension_transfer_fees() -> Result<(), Tran &council_mint_cookie.mint_authority, &token_account_keypair.pubkey(), 100, - &MintType::SplTokenExtensionsWithTransferFees, + &MintType::SplToken, &first_user_cookie.key.pubkey(), true, ) @@ -457,7 +458,7 @@ async fn test_cast_token_vote_token_extension_transfer_fees() -> Result<(), Tran let proposal_cookie = token_voter_test .governance - .with_proposal(&realm_cookie, &MintType::SplTokenExtensionsWithTransferFees) + .with_proposal(&realm_cookie) .await?; token_voter_test diff --git a/programs/token-voter/tests/close_voter.rs b/programs/token-voter/tests/close_voter.rs index 20bdfbb7..4b8f8548 100644 --- a/programs/token-voter/tests/close_voter.rs +++ b/programs/token-voter/tests/close_voter.rs @@ -5,7 +5,6 @@ use program_test::tools::*; use solana_program_test::*; use solana_sdk::transport::TransportError; use token_voter::error::TokenVoterError; -use crate::program_test::program_test_bench::MintType; mod program_test; #[tokio::test] @@ -15,7 +14,7 @@ async fn test_close_with_token_extensions() -> Result<(), TransportError> { let realm_cookie = token_voter_test .governance - .with_realm_token_extension(&MintType::SplTokenExtensions) + .with_realm() .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -105,6 +104,7 @@ async fn test_close_with_token_extensions() -> Result<(), TransportError> { .await .err() .unwrap(); + assert_token_voter_err(err, TokenVoterError::VotingTokenNonZero); token_voter_test diff --git a/programs/token-voter/tests/configure_voter_weights.rs b/programs/token-voter/tests/configure_voter_weights.rs index 64c28dcb..42683924 100644 --- a/programs/token-voter/tests/configure_voter_weights.rs +++ b/programs/token-voter/tests/configure_voter_weights.rs @@ -3,7 +3,6 @@ use program_test::tools::*; use solana_program_test::*; use solana_sdk::pubkey::Pubkey; use solana_sdk::transport::TransportError; -use crate::program_test::program_test_bench::MintType; mod program_test; @@ -12,7 +11,7 @@ async fn test_configure_voter_weights_with_token_extensions() -> Result<(), Tran // Arrange let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; + let realm_cookie = token_voter_test.governance.with_realm().await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; let governance_program_cookie = token_voter_test.with_governance_program(None).await; diff --git a/programs/token-voter/tests/create_max_voter_weight_record.rs b/programs/token-voter/tests/create_max_voter_weight_record.rs index 2a3d0ee5..d78f4579 100644 --- a/programs/token-voter/tests/create_max_voter_weight_record.rs +++ b/programs/token-voter/tests/create_max_voter_weight_record.rs @@ -3,7 +3,6 @@ use program_test::tools::assert_ix_err; use solana_program::instruction::InstructionError; use solana_program_test::*; use solana_sdk::transport::TransportError; -use crate::program_test::program_test_bench::MintType; mod program_test; @@ -11,7 +10,7 @@ mod program_test; async fn test_create_max_voter_weight_record_with_token_extensions() -> Result<(), TransportError> { // Arrange let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; + let realm_cookie = token_voter_test.governance.with_realm().await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/create_registrar.rs b/programs/token-voter/tests/create_registrar.rs index b83d3fe7..32daad49 100644 --- a/programs/token-voter/tests/create_registrar.rs +++ b/programs/token-voter/tests/create_registrar.rs @@ -15,7 +15,7 @@ async fn test_create_registrar_with_token_extensions() -> Result<(), TransportEr // Arrange let mut token_voter_test = TokenVoterTest::start_new_token_extensions(None).await; - let realm_cookie = token_voter_test.governance.with_realm_token_extension(&MintType::SplTokenExtensions).await?; + let realm_cookie = token_voter_test.governance.with_realm().await?; // Act let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/deposit.rs b/programs/token-voter/tests/deposit.rs index 3baa2e43..54d7aa87 100644 --- a/programs/token-voter/tests/deposit.rs +++ b/programs/token-voter/tests/deposit.rs @@ -18,7 +18,7 @@ async fn test_deposit_entry_with_token_extension() -> Result<(), TransportError> let realm_cookie = token_voter_test .governance - .with_realm_token_extension(&MintType::SplTokenExtensions) + .with_realm() .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -111,7 +111,7 @@ async fn test_deposit_entry_with_token_extension_transfer_hooks() -> Result<(), let realm_cookie = token_voter_test .governance - .with_realm_token_extension(&MintType::SplTokenExtensions) + .with_realm() .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -245,7 +245,7 @@ async fn test_deposit_entry_with_token_extension_transfer_fees() -> Result<(), T let realm_cookie = token_voter_test .governance - .with_realm_token_extension(&MintType::SplTokenExtensions) + .with_realm() .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; diff --git a/programs/token-voter/tests/fixtures/spl_governance_2022.so b/programs/token-voter/tests/fixtures/spl_governance_2022.so deleted file mode 100755 index 114dac496667f1f7236ed64f3377e3beb9228022..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 739288 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%0D^hZ)OcQdizVsxyuG3;E`u!_*=(thutXFE% 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 diff --git a/programs/token-voter/tests/program_test/governance_test.rs b/programs/token-voter/tests/program_test/governance_test.rs index 6bb47e41..96863d61 100644 --- a/programs/token-voter/tests/program_test/governance_test.rs +++ b/programs/token-voter/tests/program_test/governance_test.rs @@ -75,8 +75,7 @@ impl GovernanceTest { #[allow(dead_code)] pub fn add_program(program_test: &mut ProgramTest) { - // program_test.add_program("spl_governance", Self::program_id(), None); - program_test.add_program("spl_governance_2022", Self::program_id(), None); + program_test.add_program("spl_governance", Self::program_id(), None); } #[allow(dead_code)] @@ -125,81 +124,7 @@ impl GovernanceTest { None, realm_name.clone(), min_community_weight_to_create_governance, - community_mint_max_voter_weight_source.clone(), - false, - ); - - self.bench - .process_transaction(&[create_realm_ix], None) - .await?; - - let account = RealmV2 { - account_type: GovernanceAccountType::RealmV2, - community_mint: community_mint_cookie.address, - - name: realm_name, - reserved: [0; 6], - authority: Some(realm_authority.pubkey()), - config: RealmConfig { - council_mint: Some(council_mint_cookie.address), - reserved: [0; 6], - min_community_weight_to_create_governance, - legacy1: 0, - legacy2: 0, - community_mint_max_voter_weight_source, - }, - reserved_v2: [0; 128], - legacy1: 0, - }; - - Ok(RealmCookie { - address: realm_key, - account, - realm_authority, - community_mint_cookie, - council_mint_cookie: Some(council_mint_cookie), - }) - } - - #[allow(dead_code)] - pub async fn with_realm_token_extension(&mut self, mint_type: &MintType) -> Result { - let realm_authority = Keypair::new(); - - let community_mint_cookie = self - .bench - .with_mint(mint_type, None) - .await?; - let council_mint_cookie = self - .bench - .with_mint(mint_type, None) - .await?; - - self.next_id += 1; - let realm_name = format!("Realm #{}", self.next_id).to_string(); - - let min_community_weight_to_create_governance = 1; - let community_mint_max_voter_weight_source = MintMaxVoterWeightSource::FULL_SUPPLY_FRACTION; - - let realm_key = get_realm_address(&self.program_id, &realm_name); - - let community_token_config_args = GoverningTokenConfigAccountArgs { - voter_weight_addin: self.community_voter_weight_addin, - max_voter_weight_addin: self.community_voter_weight_addin, - token_type: GoverningTokenType::default(), - }; - - let create_realm_ix = create_realm( - &self.program_id, - &realm_authority.pubkey(), - &community_mint_cookie.address, - &self.bench.payer.pubkey(), - Some(council_mint_cookie.address), - Some(community_token_config_args), - None, - realm_name.clone(), - min_community_weight_to_create_governance, - community_mint_max_voter_weight_source.clone(), - true, + community_mint_max_voter_weight_source.clone() ); self.bench @@ -238,11 +163,10 @@ impl GovernanceTest { pub async fn with_proposal( &mut self, realm_cookie: &RealmCookie, - mint_type: &MintType, ) -> Result { let token_account_cookie = self .bench - .with_token_account(&realm_cookie.account.community_mint, mint_type, true) + .with_token_account(&realm_cookie.account.community_mint, &MintType::SplToken, true) .await?; let token_owner = self.bench.payer.pubkey(); @@ -251,7 +175,7 @@ impl GovernanceTest { let governing_token_account_cookie = self .bench - .with_tokens(council_mint_cookie, &token_owner, 2, mint_type, true) + .with_tokens(council_mint_cookie, &token_owner, 2, &MintType::SplToken, true) .await?; let proposal_owner_record_key = get_token_owner_record_address( @@ -273,11 +197,6 @@ impl GovernanceTest { .process_transaction(&[create_tor_ix], None) .await?; - let is_token_2022 = match mint_type { - MintType::SplToken => false, - _ => true, - }; - let deposit_ix = deposit_governing_tokens( &self.program_id, &realm_cookie.address, @@ -287,7 +206,6 @@ impl GovernanceTest { &self.bench.payer.pubkey(), 2, &governing_token_mint, - is_token_2022 ); self.bench.process_transaction(&[deposit_ix], None).await?; @@ -301,15 +219,15 @@ impl GovernanceTest { let create_governance_ix = create_governance( &self.program_id, &realm_cookie.address, - &token_account_cookie.address, + Some(&token_account_cookie.address), &proposal_owner_record_key, &self.bench.payer.pubkey(), &realm_cookie.realm_authority.pubkey(), None, spl_governance::state::governance::GovernanceConfig { min_community_weight_to_create_proposal: 1, - transactions_hold_up_time: 10, min_council_weight_to_create_proposal: 1, + min_transaction_hold_up_time: 0, community_vote_threshold: VoteThreshold::YesVotePercentage(60), voting_base_time: 600, community_vote_tipping: VoteTipping::Strict, @@ -442,9 +360,8 @@ impl GovernanceTest { outstanding_proposal_count: 0, reserved: [0; 6], governance_delegate: None, - reserved_v2: [0; 124], + reserved_v2: [0; 128], version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, - locks: vec![], }; Ok(TokenOwnerRecordCookie { @@ -489,9 +406,8 @@ impl GovernanceTest { outstanding_proposal_count: 0, reserved: [0; 6], governance_delegate: None, - reserved_v2: [0; 124], + reserved_v2: [0; 128], version: TOKEN_OWNER_RECORD_LAYOUT_VERSION, - locks: vec![], }; Ok(TokenOwnerRecordCookie { diff --git a/programs/token-voter/tests/withdraw.rs b/programs/token-voter/tests/withdraw.rs index f5526ccc..cca302d0 100644 --- a/programs/token-voter/tests/withdraw.rs +++ b/programs/token-voter/tests/withdraw.rs @@ -20,7 +20,7 @@ async fn test_withdraw_with_token_extensions_transfer_hooks() -> Result<(), Tran let realm_cookie = token_voter_test .governance - .with_realm_token_extension(&MintType::SplTokenExtensions) + .with_realm() .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?; @@ -200,7 +200,7 @@ async fn test_withdraw_with_token_extensions() -> Result<(), TransportError> { let realm_cookie = token_voter_test .governance - .with_realm_token_extension(&MintType::SplTokenExtensions) + .with_realm() .await?; let registrar_cookie = token_voter_test.with_registrar(&realm_cookie).await?;