From 07c198e09d719e9fba8997593020471b44f476e2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Mon, 25 Aug 2025 21:02:11 +0100 Subject: [PATCH 01/15] feat: cSDK (#6) * feat: cSDK with git tag csdk-0.3.3 --- Anchor.toml | 7 + Cargo.lock | 591 +++++++++++------ README.md | 16 +- client/Cargo.toml | 20 +- client/src/instructions/amm_instructions.rs | 186 +++++- .../instructions/compression_instructions.rs | 235 +++++++ client/src/instructions/mod.rs | 1 + client/src/instructions/rpc.rs | 64 +- client/src/instructions/token_instructions.rs | 138 ++-- client/src/instructions/utils.rs | 1 + client/src/main.rs | 425 ++++++++---- client_config.ini | 10 +- package.json | 10 +- programs/cp-swap/Cargo.toml | 27 +- programs/cp-swap/src/error.rs | 7 + .../instructions/admin/collect_fund_fee.rs | 42 +- .../admin/collect_protocol_fee.rs | 43 +- .../instructions/admin/update_pool_status.rs | 4 +- programs/cp-swap/src/instructions/deposit.rs | 80 ++- .../cp-swap/src/instructions/initialize.rs | 337 ++++++---- .../src/instructions/swap_base_input.rs | 53 +- .../src/instructions/swap_base_output.rs | 28 +- programs/cp-swap/src/instructions/withdraw.rs | 75 ++- programs/cp-swap/src/lib.rs | 30 +- programs/cp-swap/src/states/oracle.rs | 82 ++- programs/cp-swap/src/states/pool.rs | 40 +- programs/cp-swap/src/utils/account_load.rs | 169 ----- programs/cp-swap/src/utils/compression.rs | 110 ++++ programs/cp-swap/src/utils/ctoken.rs | 264 ++++++++ programs/cp-swap/src/utils/mod.rs | 6 +- programs/cp-swap/src/utils/token.rs | 128 ++-- scripts/lut.json | 1 + scripts/test-with-light.sh | 19 + tests/deposit.test.ts | 73 ++- tests/initialize.test.ts | 29 +- tests/utils/instruction.ts | 607 ++++++++++++++++-- tests/utils/pda.ts | 63 +- tests/utils/util.ts | 102 ++- tests/utils/web3.ts | 37 ++ tests/withdraw.test.ts | 9 +- yarn.lock | 103 ++- 41 files changed, 3153 insertions(+), 1119 deletions(-) create mode 100644 client/src/instructions/compression_instructions.rs delete mode 100644 programs/cp-swap/src/utils/account_load.rs create mode 100644 programs/cp-swap/src/utils/compression.rs create mode 100644 programs/cp-swap/src/utils/ctoken.rs create mode 100644 scripts/lut.json create mode 100755 scripts/test-with-light.sh diff --git a/Anchor.toml b/Anchor.toml index f06fe87..bd33d8c 100644 --- a/Anchor.toml +++ b/Anchor.toml @@ -25,6 +25,7 @@ test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.test.ts" [test] startup_wait = 10000 +upgradeable = true [test.validator] url = "https://api.mainnet-beta.solana.com" @@ -34,3 +35,9 @@ address = "DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8" # pool fee receiver [[test.validator.clone]] address = "D4FPEruKEHrG5TenZ2mpDGEfu1iUvTiqBxvpU8HLBvC2" # index 0 AMM Config account + + +[idl] +typescript = true +idl_dir = "target/idl" +types_dir = "target/types" diff --git a/Cargo.lock b/Cargo.lock index 9116c0e..bc75f05 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -15,7 +15,7 @@ dependencies = [ [[package]] name = "account-compression" version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "aligned-sized", "anchor-lang", @@ -112,7 +112,7 @@ dependencies = [ [[package]] name = "aligned-sized" version = "1.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "proc-macro2", "quote", @@ -235,6 +235,27 @@ dependencies = [ "url", ] +[[package]] +name = "anchor-compressed-token" +version = "2.0.0" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +dependencies = [ + "account-compression", + "anchor-lang", + "anchor-spl 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)", + "light-compressed-account", + "light-ctoken-types", + "light-hasher", + "light-heap", + "light-system-program-anchor", + "light-zero-copy", + "solana-sdk", + "solana-security-txt", + "spl-token", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "zerocopy", +] + [[package]] name = "anchor-derive-accounts" version = "0.31.1" @@ -324,6 +345,20 @@ name = "anchor-spl" version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c08cb5d762c0694f74bd02c9a5b04ea53cefc496e2c27b3234acffca5cd076b" +dependencies = [ + "anchor-lang", + "spl-associated-token-account", + "spl-pod", + "spl-token", + "spl-token-2022 6.0.0", + "spl-token-group-interface", + "spl-token-metadata-interface", +] + +[[package]] +name = "anchor-spl" +version = "0.31.1" +source = "git+https://github.com/lightprotocol/anchor?rev=d8a2b3d9#d8a2b3d99d61ef900d1f6cdaabcef14eb9af6279" dependencies = [ "anchor-lang", "mpl-token-metadata", @@ -770,28 +805,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "async-stream" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b5a71a6f37880a80d1d7f19efd781e4b5de42c88f0722cc13bcb6cc2cfe8476" -dependencies = [ - "async-stream-impl", - "futures-core", - "pin-project-lite", -] - -[[package]] -name = "async-stream-impl" -version = "0.3.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", -] - [[package]] name = "async-trait" version = "0.1.88" @@ -865,18 +878,6 @@ version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" -[[package]] -name = "bb8" -version = "0.8.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d89aabfae550a5c44b43ab941844ffcd2e993cb6900b342debf59e9ea74acdb8" -dependencies = [ - "async-trait", - "futures-util", - "parking_lot", - "tokio", -] - [[package]] name = "bincode" version = "1.3.3" @@ -1074,6 +1075,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bytecount" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" + [[package]] name = "bytemuck" version = "1.23.1" @@ -1237,17 +1244,25 @@ version = "0.1.0" dependencies = [ "anchor-client", "anchor-lang", - "anchor-spl", + "anchor-spl 0.31.1 (git+https://github.com/lightprotocol/anchor?rev=d8a2b3d9)", "anyhow", "arrayref", "base64 0.21.7", "bincode", + "borsh 1.5.7", "bs58", "bytemuck", "clap", "colorful", "configparser", + "futures", "hex", + "light-client", + "light-compressed-account", + "light-compressible-client", + "light-program-test", + "light-sdk", + "light-token-client", "rand 0.9.2", "raydium-cp-swap", "regex", @@ -1255,8 +1270,10 @@ dependencies = [ "serde_json", "solana-account-decoder", "solana-client", + "solana-message", "solana-sdk", "solana-transaction-status", + "tokio", ] [[package]] @@ -1392,20 +1409,6 @@ dependencies = [ "cfg-if", ] -[[package]] -name = "create-address-test-program" -version = "1.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" -dependencies = [ - "account-compression", - "anchor-lang", - "light-compressed-account", - "light-hasher", - "light-sdk", - "light-sdk-types", - "light-system-program-anchor", -] - [[package]] name = "crossbeam-channel" version = "0.5.15" @@ -1566,20 +1569,6 @@ dependencies = [ "parking_lot_core", ] -[[package]] -name = "dashmap" -version = "6.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5041cc499144891f3790297212f32a74fb938e5136a14943f338ef9e0ae276cf" -dependencies = [ - "cfg-if", - "crossbeam-utils", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - [[package]] name = "data-encoding" version = "2.9.0" @@ -1968,44 +1957,6 @@ version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" -[[package]] -name = "forester-utils" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" -dependencies = [ - "account-compression", - "anchor-lang", - "async-stream", - "async-trait", - "bb8", - "futures", - "governor 0.8.1", - "light-account-checks", - "light-batched-merkle-tree", - "light-client", - "light-compressed-account", - "light-concurrent-merkle-tree", - "light-hash-set", - "light-hasher", - "light-indexed-array", - "light-indexed-merkle-tree", - "light-merkle-tree-metadata", - "light-prover-client", - "light-registry", - "light-sdk", - "light-sparse-merkle-tree", - "num-bigint 0.4.6", - "num-traits", - "rand 0.8.5", - "reqwest 0.12.22", - "serde", - "serde_json", - "solana-sdk", - "thiserror 2.0.12", - "tokio", - "tracing", -] - [[package]] name = "form_urlencoded" version = "1.2.1" @@ -2189,7 +2140,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ "cfg-if", - "dashmap 5.5.3", + "dashmap", "futures", "futures-timer", "no-std-compat", @@ -2202,29 +2153,6 @@ dependencies = [ "spinning_top", ] -[[package]] -name = "governor" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be93b4ec2e4710b04d9264c0c7350cdd62a8c20e5e4ac732552ebb8f0debe8eb" -dependencies = [ - "cfg-if", - "dashmap 6.1.0", - "futures-sink", - "futures-timer", - "futures-util", - "getrandom 0.3.3", - "no-std-compat", - "nonzero_ext", - "parking_lot", - "portable-atomic", - "quanta", - "rand 0.9.2", - "smallvec", - "spinning_top", - "web-time", -] - [[package]] name = "groth16-solana" version = "0.2.0" @@ -2983,9 +2911,11 @@ dependencies = [ [[package]] name = "light-account-checks" version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ + "pinocchio", "solana-account-info", + "solana-msg", "solana-program-error", "solana-pubkey", "solana-sysvar", @@ -2995,7 +2925,7 @@ dependencies = [ [[package]] name = "light-batched-merkle-tree" version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -3019,7 +2949,7 @@ dependencies = [ [[package]] name = "light-bloom-filter" version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "bitvec", "num-bigint 0.4.6", @@ -3043,7 +2973,7 @@ dependencies = [ [[package]] name = "light-client" version = "0.13.1" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "async-trait", "base64 0.13.1", @@ -3073,6 +3003,7 @@ dependencies = [ "solana-hash", "solana-instruction", "solana-keypair", + "solana-message", "solana-program-error", "solana-pubkey", "solana-rpc-client", @@ -3089,7 +3020,7 @@ dependencies = [ [[package]] name = "light-compressed-account" version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -3097,6 +3028,7 @@ dependencies = [ "light-hasher", "light-macros", "light-zero-copy", + "solana-msg", "solana-program-error", "solana-pubkey", "thiserror 2.0.12", @@ -3106,32 +3038,83 @@ dependencies = [ [[package]] name = "light-compressed-token" version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "account-compression", + "anchor-compressed-token", "anchor-lang", - "anchor-spl", + "arrayvec", + "borsh 0.10.4", + "light-account-checks", "light-compressed-account", + "light-ctoken-types", "light-hasher", "light-heap", + "light-sdk", + "light-sdk-pinocchio", + "light-sdk-types", "light-system-program-anchor", "light-zero-copy", - "solana-sdk", + "pinocchio", + "solana-pubkey", "solana-security-txt", + "spl-pod", "spl-token", - "spl-token-2022 7.0.0", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-2022 7.0.0 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", "zerocopy", ] +[[package]] +name = "light-compressed-token-sdk" +version = "0.1.0" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +dependencies = [ + "anchor-lang", + "arrayvec", + "borsh 0.10.4", + "light-account-checks", + "light-compressed-account", + "light-compressed-token-types", + "light-ctoken-types", + "light-macros", + "light-sdk", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-pod", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.12", +] + +[[package]] +name = "light-compressed-token-types" +version = "0.1.0" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +dependencies = [ + "anchor-lang", + "borsh 0.10.4", + "light-account-checks", + "light-compressed-account", + "light-macros", + "light-sdk-types", + "solana-msg", + "thiserror 2.0.12", +] + [[package]] name = "light-compressible-client" version = "0.13.1" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "anchor-lang", "borsh 0.10.4", "light-client", "light-sdk", + "solana-account", "solana-instruction", "solana-pubkey", "thiserror 2.0.12", @@ -3140,7 +3123,7 @@ dependencies = [ [[package]] name = "light-concurrent-merkle-tree" version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "borsh 0.10.4", "light-bounded-vec", @@ -3150,10 +3133,31 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "light-ctoken-types" +version = "0.1.0" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +dependencies = [ + "anchor-lang", + "arrayvec", + "borsh 0.10.4", + "light-compressed-account", + "light-hasher", + "light-macros", + "light-zero-copy", + "pinocchio", + "solana-msg", + "solana-pubkey", + "spl-pod", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.12", + "zerocopy", +] + [[package]] name = "light-hash-set" version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "light-hasher", "num-bigint 0.4.6", @@ -3165,7 +3169,7 @@ dependencies = [ [[package]] name = "light-hasher" version = "3.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", @@ -3184,7 +3188,7 @@ dependencies = [ [[package]] name = "light-heap" version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "anchor-lang", ] @@ -3192,7 +3196,7 @@ dependencies = [ [[package]] name = "light-indexed-array" version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "light-hasher", "num-bigint 0.4.6", @@ -3203,7 +3207,7 @@ dependencies = [ [[package]] name = "light-indexed-merkle-tree" version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "light-bounded-vec", "light-concurrent-merkle-tree", @@ -3218,7 +3222,7 @@ dependencies = [ [[package]] name = "light-macros" version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "bs58", "proc-macro2", @@ -3229,7 +3233,7 @@ dependencies = [ [[package]] name = "light-merkle-tree-metadata" version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -3245,7 +3249,7 @@ dependencies = [ [[package]] name = "light-merkle-tree-reference" version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "light-hasher", "light-indexed-array", @@ -3281,13 +3285,15 @@ dependencies = [ [[package]] name = "light-program-test" version = "0.13.2" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "account-compression", "anchor-lang", "async-trait", "borsh 0.10.4", + "bs58", "bytemuck", + "chrono", "light-batched-merkle-tree", "light-client", "light-compressed-account", @@ -3302,6 +3308,7 @@ dependencies = [ "light-prover-client", "light-registry", "light-sdk", + "light-sdk-types", "litesvm", "log", "num-bigint 0.4.6", @@ -3309,6 +3316,8 @@ dependencies = [ "photon-api", "rand 0.8.5", "reqwest 0.12.22", + "serde", + "serde_json", "solana-account", "solana-banks-client", "solana-compute-budget", @@ -3317,14 +3326,16 @@ dependencies = [ "solana-rpc-client-api", "solana-sdk", "solana-transaction", + "solana-transaction-status", "solana-transaction-status-client-types", + "tabled", "tokio", ] [[package]] name = "light-prover-client" version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "ark-bn254 0.5.0", "ark-serialize 0.5.0", @@ -3346,7 +3357,7 @@ dependencies = [ [[package]] name = "light-registry" version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "account-compression", "aligned-sized", @@ -3361,10 +3372,11 @@ dependencies = [ [[package]] name = "light-sdk" version = "0.13.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "anchor-lang", "arrayvec", + "bincode", "borsh 0.10.4", "light-account-checks", "light-compressed-account", @@ -3379,6 +3391,7 @@ dependencies = [ "solana-cpi", "solana-instruction", "solana-msg", + "solana-program", "solana-program-error", "solana-pubkey", "solana-rent", @@ -3390,7 +3403,7 @@ dependencies = [ [[package]] name = "light-sdk-macros" version = "0.13.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "heck 0.4.1", "light-hasher", @@ -3401,10 +3414,28 @@ dependencies = [ "syn 2.0.104", ] +[[package]] +name = "light-sdk-pinocchio" +version = "0.13.0" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +dependencies = [ + "borsh 0.10.4", + "light-account-checks", + "light-compressed-account", + "light-hasher", + "light-macros", + "light-sdk-macros", + "light-sdk-types", + "light-zero-copy", + "pinocchio", + "solana-pubkey", + "thiserror 2.0.12", +] + [[package]] name = "light-sdk-types" version = "0.13.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -3420,7 +3451,7 @@ dependencies = [ [[package]] name = "light-sparse-merkle-tree" version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "light-hasher", "light-indexed-array", @@ -3432,7 +3463,7 @@ dependencies = [ [[package]] name = "light-system-program-anchor" version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "account-compression", "aligned-sized", @@ -3443,48 +3474,31 @@ dependencies = [ ] [[package]] -name = "light-test-utils" -version = "1.2.1" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +name = "light-token-client" +version = "0.1.0" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ - "account-compression", - "anchor-lang", - "anchor-spl", - "create-address-test-program", - "forester-utils", - "light-account-checks", - "light-batched-merkle-tree", + "borsh 0.10.4", "light-client", "light-compressed-account", - "light-compressed-token", - "light-concurrent-merkle-tree", - "light-hasher", - "light-indexed-array", - "light-indexed-merkle-tree", - "light-merkle-tree-metadata", - "light-merkle-tree-reference", - "light-program-test", - "light-prover-client", - "light-registry", + "light-compressed-token-sdk", + "light-compressed-token-types", + "light-ctoken-types", "light-sdk", - "light-sparse-merkle-tree", - "light-system-program-anchor", - "log", - "num-bigint 0.4.6", - "num-traits", - "rand 0.8.5", - "reqwest 0.12.22", - "solana-banks-client", - "solana-sdk", - "spl-token", - "spl-token-2022 7.0.0", - "thiserror 2.0.12", + "solana-instruction", + "solana-keypair", + "solana-msg", + "solana-pubkey", + "solana-signature", + "solana-signer", + "spl-pod", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "light-verifier" version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "groth16-solana", "light-compressed-account", @@ -3494,13 +3508,24 @@ dependencies = [ [[package]] name = "light-zero-copy" version = "0.2.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ + "light-zero-copy-derive", "solana-program-error", - "thiserror 2.0.12", "zerocopy", ] +[[package]] +name = "light-zero-copy-derive" +version = "0.1.0" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "linux-raw-sys" version = "0.9.4" @@ -3774,7 +3799,6 @@ checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ "num-integer", "num-traits", - "rand 0.8.5", "serde", ] @@ -3994,6 +4018,17 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "papergrid" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6978128c8b51d8f4080631ceb2302ab51e32cc6e8615f735ee2f83fd269ae3f1" +dependencies = [ + "bytecount", + "fnv", + "unicode-width", +] + [[package]] name = "parking" version = "2.2.1" @@ -4065,7 +4100,7 @@ dependencies = [ [[package]] name = "photon-api" version = "0.51.0" -source = "git+https://github.com/lightprotocol/light-protocol?branch=swen-0011-proc#7cf6a9a2b200f1e77f7d39344c8bde69f9597e3e" +source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" dependencies = [ "reqwest 0.12.22", "serde", @@ -4108,6 +4143,12 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[package]] +name = "pinocchio" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c33b58567c11b07749cefbb8320ac023f3387c57807aeb8e3b1262501b6e9f0" + [[package]] name = "pkg-config" version = "0.3.32" @@ -4174,6 +4215,28 @@ dependencies = [ "toml_edit", ] +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "proc-macro2" version = "1.0.95" @@ -4456,24 +4519,26 @@ name = "raydium-cp-swap" version = "0.2.0" dependencies = [ "anchor-lang", - "anchor-spl", + "anchor-spl 0.31.1 (git+https://github.com/lightprotocol/anchor?rev=d8a2b3d9)", "arrayref", "bytemuck", "light-client", + "light-compressed-account", + "light-compressed-token-sdk", "light-compressible-client", + "light-ctoken-types", "light-hasher", "light-macros", "light-program-test", "light-sdk", "light-sdk-macros", "light-sdk-types", - "light-test-utils", "proptest", "quickcheck", "rand 0.9.2", "solana-security-txt", "spl-math", - "spl-token-2022 7.0.0", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "uint", ] @@ -5236,7 +5301,7 @@ dependencies = [ "solana-slot-history", "solana-sysvar", "spl-token", - "spl-token-2022 7.0.0", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "spl-token-group-interface", "spl-token-metadata-interface", "thiserror 2.0.12", @@ -5513,7 +5578,7 @@ checksum = "5e827416867d988cbba327b6e448ad0bfb85ba44f080c6a02a00aa498c2249c4" dependencies = [ "async-trait", "bincode", - "dashmap 5.5.3", + "dashmap", "futures", "futures-util", "indexmap 2.10.0", @@ -7196,10 +7261,10 @@ dependencies = [ "async-channel", "bytes", "crossbeam-channel", - "dashmap 5.5.3", + "dashmap", "futures", "futures-util", - "governor 0.6.3", + "governor", "histogram", "indexmap 2.10.0", "itertools 0.12.1", @@ -7553,7 +7618,7 @@ dependencies = [ "spl-associated-token-account", "spl-memo", "spl-token", - "spl-token-2022 7.0.0", + "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "spl-token-group-interface", "spl-token-metadata-interface", "thiserror 2.0.12", @@ -7873,7 +7938,19 @@ dependencies = [ "solana-program", "solana-zk-sdk", "spl-pod", - "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-extraction 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.1" +source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +dependencies = [ + "bytemuck", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction 0.2.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", ] [[package]] @@ -7906,9 +7983,9 @@ dependencies = [ [[package]] name = "spl-pod" -version = "0.5.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "41a7d5950993e1ff2680bd989df298eeb169367fb2f9deeef1f132de6e4e8016" +checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" dependencies = [ "borsh 1.5.7", "bytemuck", @@ -7921,7 +7998,7 @@ dependencies = [ "solana-program-option", "solana-pubkey", "solana-zk-sdk", - "thiserror 1.0.69", + "thiserror 2.0.12", ] [[package]] @@ -8000,12 +8077,12 @@ dependencies = [ "solana-program", "solana-security-txt", "solana-zk-sdk", - "spl-elgamal-registry", + "spl-elgamal-registry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "spl-memo", "spl-pod", "spl-token", - "spl-token-confidential-transfer-ciphertext-arithmetic", - "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-confidential-transfer-proof-extraction 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "spl-token-confidential-transfer-proof-generation 0.2.0", "spl-token-group-interface", "spl-token-metadata-interface", @@ -8028,13 +8105,40 @@ dependencies = [ "solana-program", "solana-security-txt", "solana-zk-sdk", - "spl-elgamal-registry", + "spl-elgamal-registry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "spl-memo", "spl-pod", "spl-token", - "spl-token-confidential-transfer-ciphertext-arithmetic", - "spl-token-confidential-transfer-proof-extraction", - "spl-token-confidential-transfer-proof-generation 0.3.0", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-confidential-transfer-proof-extraction 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-confidential-transfer-proof-generation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror 2.0.12", +] + +[[package]] +name = "spl-token-2022" +version = "7.0.0" +source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-sdk", + "spl-elgamal-registry 0.1.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", + "spl-token-confidential-transfer-proof-extraction 0.2.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", + "spl-token-confidential-transfer-proof-generation 0.3.0 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", "spl-token-group-interface", "spl-token-metadata-interface", "spl-transfer-hook-interface", @@ -8054,6 +8158,17 @@ dependencies = [ "solana-zk-sdk", ] +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.1" +source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + [[package]] name = "spl-token-confidential-transfer-proof-extraction" version = "0.2.1" @@ -8068,6 +8183,19 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.1" +source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +dependencies = [ + "bytemuck", + "solana-curve25519", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.12", +] + [[package]] name = "spl-token-confidential-transfer-proof-generation" version = "0.2.0" @@ -8090,6 +8218,16 @@ dependencies = [ "thiserror 2.0.12", ] +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.3.0" +source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +dependencies = [ + "curve25519-dalek 4.1.3", + "solana-zk-sdk", + "thiserror 2.0.12", +] + [[package]] name = "spl-token-group-interface" version = "0.5.0" @@ -8299,6 +8437,30 @@ dependencies = [ "libc", ] +[[package]] +name = "tabled" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e39a2ee1fbcd360805a771e1b300f78cc88fec7b8d3e2f71cd37bbf23e725c7d" +dependencies = [ + "papergrid", + "tabled_derive", + "testing_table", +] + +[[package]] +name = "tabled_derive" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ea5d1b13ca6cff1f9231ffd62f15eefd72543dab5e468735f1a456728a02846" +dependencies = [ + "heck 0.5.0", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.104", +] + [[package]] name = "tap" version = "1.0.1" @@ -8371,6 +8533,15 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "testing_table" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f8daae29995a24f65619e19d8d31dea5b389f3d853d8bf297bbf607cd0014cc" +dependencies = [ + "unicode-width", +] + [[package]] name = "thiserror" version = "1.0.69" diff --git a/README.md b/README.md index 49f044c..af96c36 100644 --- a/README.md +++ b/README.md @@ -1,14 +1,16 @@ # raydium-cp-swap -A revamped constant product AMM program optimized for straightforward pool deployment along with additional features and integrations: +A constant product AMM program reference implementation based to Raydiun's CP AMM. + +We added: + +- rent-free + +Original readme: + - No Openbook market ID is required for pool creation - Token22 is supported - Built-in price oracle -- Optimized in Anchor - -The program has been audited by [MadShield](https://www.madshield.xyz/). The report can be found [here](https://github.com/raydium-io/raydium-docs/tree/master/audit/MadShield%20Q1%202024). - -The program assets are in-scope for Raydium’s [Immunefi bug bounty program](https://immunefi.com/bug-bounty/raydium/). ## Environment Setup @@ -30,7 +32,7 @@ The program assets are in-scope for Raydium’s [Immunefi bug bounty program](ht 3. install `Anchor` ```shell - # Installing using Anchor version manager (avm) + # Installing using Anchor version manager (avm) cargo install --git https://github.com/coral-xyz/anchor avm --locked --force # Install anchor avm install 0.31.0 diff --git a/client/Cargo.toml b/client/Cargo.toml index 074c134..3308da6 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -5,17 +5,21 @@ edition = "2021" [features] devnet = ["raydium-cp-swap/devnet"] +test-sbf = ["raydium-cp-swap/test-sbf"] [dependencies] -anchor-client = { version = "=0.31.1" } +anchor-client = { version = "=0.31.1", features = ["async"] } anchor-lang = { version = "=0.31.1" } -anchor-spl = { version = "=0.31.1", features = ["idl-build"] } +anchor-spl = { version = "=0.31.1", git = "https://github.com/lightprotocol/anchor", rev = "d8a2b3d9", features = ["memo", "metadata", "idl-build"] } + raydium-cp-swap = { path = "../programs/cp-swap", features = [ "no-entrypoint", "client", + "idl-build", ] } solana-sdk = "2.2" solana-client = "2.2" +solana-message = "2.2" solana-account-decoder = "2.2" solana-transaction-status = "2.2" clap = { version = "4.1.8", features = ["derive"] } @@ -28,7 +32,19 @@ serde = { version = "1.0", features = ["derive"] } arrayref = "0.3.7" bs58 = { version = "0.5.0" } bincode = { version = "1.3.3" } +borsh = { version = "1.5.7" } regex = "1" colorful = "0.3.2" base64 = "0.21.0" bytemuck = { version = "1.23.0", features = ["derive"] } +tokio = { version = "1.0", features = ["full"] } +futures = "0.3" + +light-program-test = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } +light-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } +light-compressible-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } +light-sdk = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor", "anchor-discriminator-compat", "v2"] } +light-compressed-account = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } +light-token-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3" } + + diff --git a/client/src/instructions/amm_instructions.rs b/client/src/instructions/amm_instructions.rs index 2f15ec9..62080a4 100644 --- a/client/src/instructions/amm_instructions.rs +++ b/client/src/instructions/amm_instructions.rs @@ -4,19 +4,33 @@ use anchor_spl::{ token_2022::spl_token_2022, }; use anyhow::Result; +use light_client::{ + indexer::{AddressWithTree, Indexer}, + rpc::{LightClient, Rpc}, +}; +use light_compressed_account::address::derive_address; +use light_sdk::{ + compressible::CompressibleConfig, + instruction::{PackedAccounts, SystemAccountMetaConfig}, +}; +use light_token_client::compressed_token::{self, derive_compressed_mint_address}; use solana_sdk::{instruction::Instruction, pubkey::Pubkey, system_program, sysvar}; +use std::rc::Rc; -use raydium_cp_swap::accounts as raydium_cp_accounts; -use raydium_cp_swap::instruction as raydium_cp_instructions; +use raydium_cp_swap::{accounts as raydium_cp_accounts, utils::POOL_STATE_CREATION_INDEX}; +use raydium_cp_swap::{ + instruction as raydium_cp_instructions, + utils::{LP_MINT_CREATION_INDEX, OBSERVATION_STATE_CREATION_INDEX}, +}; use raydium_cp_swap::{ states::{AMM_CONFIG_SEED, OBSERVATION_SEED, POOL_LP_MINT_SEED, POOL_SEED, POOL_VAULT_SEED}, AUTH_SEED, }; -use std::rc::Rc; use super::super::{read_keypair_file, ClientConfig}; -pub fn initialize_pool_instr( +pub async fn initialize_pool_instr( + light_client: &mut LightClient, config: &ClientConfig, token_0_mint: Pubkey, token_1_mint: Pubkey, @@ -32,7 +46,7 @@ pub fn initialize_pool_instr( ) -> Result> { let payer = read_keypair_file(&config.payer_path)?; let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. + let client = Client::new(url, Rc::new(payer)); let program = client.program(config.raydium_cp_program)?; @@ -58,6 +72,7 @@ pub fn initialize_pool_instr( }; let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); + let (token_0_vault, __bump) = Pubkey::find_program_address( &[ POOL_VAULT_SEED.as_bytes(), @@ -74,13 +89,21 @@ pub fn initialize_pool_instr( ], &program.id(), ); - let (lp_mint_key, __bump) = Pubkey::find_program_address( + + let (lp_mint_signer, _lp_mint_signer_bump) = Pubkey::find_program_address( &[ POOL_LP_MINT_SEED.as_bytes(), pool_account_key.to_bytes().as_ref(), ], &program.id(), ); + + let (lp_mint_key, lp_mint_bump) = compressed_token::find_mint_address(lp_mint_signer); + + let (lp_vault, __bump) = Pubkey::find_program_address( + &[POOL_VAULT_SEED.as_bytes(), lp_mint_key.to_bytes().as_ref()], + &program.id(), + ); let (observation_key, __bump) = Pubkey::find_program_address( &[ OBSERVATION_SEED.as_bytes(), @@ -89,6 +112,85 @@ pub fn initialize_pool_instr( &program.id(), ); + let compression_config_key = CompressibleConfig::derive_default_pda(&program.id()).0; + let mut remaining_accounts = PackedAccounts::default(); + let address_tree_info = light_client.get_address_tree_v2(); + let state_tree_info = light_client.get_state_tree_infos()[0]; + remaining_accounts.add_system_accounts_small(SystemAccountMetaConfig::new_with_cpi_context( + program.id(), + state_tree_info.cpi_context.unwrap(), + ))?; + + // Derive compressed addresses of all to-be-initialized compressible accounts. + let pool_compressed_address = derive_address( + &pool_account_key.to_bytes(), + &address_tree_info.tree.to_bytes(), + &program.id().to_bytes(), + ); + let observation_compressed_address = derive_address( + &observation_key.to_bytes(), + &address_tree_info.tree.to_bytes(), + &program.id().to_bytes(), + ); + let lp_mint_compressed_address = + derive_compressed_mint_address(lp_mint_key, &address_tree_info.tree); + + // Fetch validity proof for all new compressed addresses. Proves that the + // accounts don't exist yet. Must match the ordering used by the program + // when invoking the cpi. + let rpc_result = light_client + .get_validity_proof( + vec![], + vec![ + AddressWithTree { + address: pool_compressed_address, + tree: address_tree_info.tree, + }, + AddressWithTree { + address: observation_compressed_address, + tree: address_tree_info.tree, + }, + AddressWithTree { + address: lp_mint_compressed_address, + tree: address_tree_info.tree, + }, + ], + None, + ) + .await + .unwrap() + .value; + + let output_state_tree_index = remaining_accounts.insert_or_get(state_tree_info.queue); + let packed_tree_infos = rpc_result.pack_tree_infos(&mut remaining_accounts); + let pool_address_tree_info = + packed_tree_infos.address_trees[POOL_STATE_CREATION_INDEX as usize]; + let observation_address_tree_info = + packed_tree_infos.address_trees[OBSERVATION_STATE_CREATION_INDEX as usize]; + let lp_mint_address_tree_info = + packed_tree_infos.address_trees[LP_MINT_CREATION_INDEX as usize]; + + let (system_accounts, _, _) = remaining_accounts.to_account_metas(); + + let (creator_lp_token, creator_lp_token_bump) = + compressed_token::get_associated_ctoken_address_and_bump(&program.payer(), &lp_mint_key); + + let compression_params = + raydium_cp_swap::instructions::initialize::InitializeCompressionParams { + pool_address_tree_info, + observation_address_tree_info, + lp_mint_address_tree_info, + lp_mint_bump, + proof: rpc_result.proof.into(), + output_state_tree_index, + creator_lp_token_bump, + }; + + let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&token_0_mint); + let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&token_1_mint); + let mut instructions = program .request() .accounts(raydium_cp_accounts::Initialize { @@ -99,12 +201,10 @@ pub fn initialize_pool_instr( token_0_mint, token_1_mint, lp_mint: lp_mint_key, + lp_vault, creator_token_0: user_token_0_account, creator_token_1: user_token_1_account, - creator_lp_token: spl_associated_token_account::get_associated_token_address( - &program.payer(), - &lp_mint_key, - ), + creator_lp_token, token_0_vault, token_1_vault, create_pool_fee, @@ -115,13 +215,23 @@ pub fn initialize_pool_instr( associated_token_program: spl_associated_token_account::id(), system_program: system_program::id(), rent: sysvar::rent::id(), + compression_config: compression_config_key, + rent_recipient: program.payer(), + lp_mint_signer, + compressed_token_program_cpi_authority: compressed_token::cpi_authority(), + compressed_token_program: compressed_token::id(), + compressed_token_0_pool_pda, + compressed_token_1_pool_pda, }) + .accounts(system_accounts) .args(raydium_cp_instructions::Initialize { init_amount_0, init_amount_1, open_time, + compression_params, }) .instructions()?; + if random_pool_id.is_some() { // update account signer as true for random pool for account in instructions[0].accounts.iter_mut() { @@ -131,6 +241,7 @@ pub fn initialize_pool_instr( } } } + Ok(instructions) } @@ -157,6 +268,19 @@ pub fn deposit_instr( let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); + let (lp_vault, __bump) = Pubkey::find_program_address( + &[ + POOL_VAULT_SEED.as_bytes(), + token_lp_mint.to_bytes().as_ref(), + ], + &program.id(), + ); + + let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&token_0_mint); + let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&token_1_mint); + let instructions = program .request() .accounts(raydium_cp_accounts::Deposit { @@ -172,7 +296,11 @@ pub fn deposit_instr( token_program_2022: spl_token_2022::id(), vault_0_mint: token_0_mint, vault_1_mint: token_1_mint, - lp_mint: token_lp_mint, + lp_vault, + compressed_token_program: compressed_token::id(), + compressed_token_program_cpi_authority: compressed_token::cpi_authority(), + compressed_token_0_pool_pda, + compressed_token_1_pool_pda, }) .args(raydium_cp_instructions::Deposit { lp_token_amount, @@ -206,6 +334,18 @@ pub fn withdraw_instr( let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); + let (lp_vault, __bump) = Pubkey::find_program_address( + &[ + POOL_VAULT_SEED.as_bytes(), + token_lp_mint.to_bytes().as_ref(), + ], + &program.id(), + ); + let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&token_0_mint); + let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&token_1_mint); + let instructions = program .request() .accounts(raydium_cp_accounts::Withdraw { @@ -221,8 +361,12 @@ pub fn withdraw_instr( token_program_2022: spl_token_2022::id(), vault_0_mint: token_0_mint, vault_1_mint: token_1_mint, - lp_mint: token_lp_mint, + lp_vault, + compressed_token_program: compressed_token::id(), memo_program: spl_memo::id(), + compressed_token_program_cpi_authority: compressed_token::cpi_authority(), + compressed_token_0_pool_pda, + compressed_token_1_pool_pda, }) .args(raydium_cp_instructions::Withdraw { lp_token_amount, @@ -257,6 +401,11 @@ pub fn swap_base_input_instr( let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); + let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&input_token_mint); + let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&output_token_mint); + let instructions = program .request() .accounts(raydium_cp_accounts::Swap { @@ -273,6 +422,10 @@ pub fn swap_base_input_instr( input_token_mint, output_token_mint, observation_state: observation_account, + compressed_token_program_cpi_authority: compressed_token::cpi_authority(), + compressed_token_program: compressed_token::id(), + compressed_token_0_pool_pda, + compressed_token_1_pool_pda, }) .args(raydium_cp_instructions::SwapBaseInput { amount_in, @@ -306,6 +459,11 @@ pub fn swap_base_output_instr( let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); + let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&input_token_mint); + let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = + compressed_token::get_token_pool_address_and_bump(&output_token_mint); + let instructions = program .request() .accounts(raydium_cp_accounts::Swap { @@ -322,6 +480,10 @@ pub fn swap_base_output_instr( input_token_mint, output_token_mint, observation_state: observation_account, + compressed_token_program_cpi_authority: compressed_token::cpi_authority(), + compressed_token_program: compressed_token::id(), + compressed_token_0_pool_pda, + compressed_token_1_pool_pda, }) .args(raydium_cp_instructions::SwapBaseOutput { max_amount_in, diff --git a/client/src/instructions/compression_instructions.rs b/client/src/instructions/compression_instructions.rs new file mode 100644 index 0000000..ae4018c --- /dev/null +++ b/client/src/instructions/compression_instructions.rs @@ -0,0 +1,235 @@ +use anchor_lang::AnchorDeserialize; +use anyhow::Result; +use light_client::{ + indexer::Indexer, + rpc::{LightClient, Rpc}, +}; +use light_compressible_client::CompressibleInstruction; +use light_sdk::compressible::CompressibleConfig; +use solana_client::rpc_client::RpcClient; +use solana_sdk::{ + pubkey::Pubkey, + signature::{Keypair, Signer}, +}; +use std::str::FromStr; + +use super::super::{read_keypair_file, ClientConfig}; +use super::rpc::send_versioned_txn; +use light_client::rpc::load_lookup_table; + +pub const COMPRESSION_DELAY: u32 = 100; +pub const ADDRESS_SPACE: [Pubkey; 1] = [solana_sdk::pubkey!( + "EzKE84aVTkCUhDHLELqyJaq1Y7UVVmqxXqZjVHwHY3rK" +)]; + +pub async fn initialize_compression_config( + rpc_client: &RpcClient, + config: &ClientConfig, + authority: &Keypair, +) -> Result<()> { + let payer = read_keypair_file(&config.payer_path)?; + let program_id = config.raydium_cp_program; + + let (config_pda, _) = CompressibleConfig::derive_default_pda(&program_id); + if rpc_client.get_account(&config_pda).is_ok() { + return Ok(()); + } + + let instruction = CompressibleInstruction::initialize_compression_config( + &program_id, + &CompressibleInstruction::INITIALIZE_COMPRESSION_CONFIG_DISCRIMINATOR, + &payer.pubkey(), + &authority.pubkey(), + COMPRESSION_DELAY, + payer.pubkey(), // rent_recipient + ADDRESS_SPACE.to_vec(), + None, + ); + + let lookup_table_address = Pubkey::from_str("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ")?; + let lookup_table = load_lookup_table(&rpc_client, &lookup_table_address)?; + let lookup_tables = vec![lookup_table]; + + let signers = vec![&payer, authority]; + let _signature = send_versioned_txn( + &rpc_client, + &[instruction], + &signers, + &payer.pubkey(), + &lookup_tables, + true, + )?; + + Ok(()) +} + +pub async fn decompress_pool_and_observation_idempotent( + light_client: &mut LightClient, + rpc_client: &RpcClient, + config: &ClientConfig, + pool_address: Pubkey, + observation_address: Pubkey, + amm_config: Pubkey, + token_0_mint: Pubkey, + token_1_mint: Pubkey, +) -> Result<()> { + let payer = read_keypair_file(&config.payer_path)?; + let program_id = config.raydium_cp_program; + + let pool_exists = rpc_client.get_account(&pool_address).is_ok(); + let observation_exists = rpc_client.get_account(&observation_address).is_ok(); + + if pool_exists && observation_exists { + return Ok(()); + } + + let address_tree_info = light_client.get_address_tree_v2(); + + let pool_compressed_address = light_compressed_account::address::derive_address( + &pool_address.to_bytes(), + &address_tree_info.tree.to_bytes(), + &program_id.to_bytes(), + ); + + let observation_compressed_address = light_compressed_account::address::derive_address( + &observation_address.to_bytes(), + &address_tree_info.tree.to_bytes(), + &program_id.to_bytes(), + ); + + let pool_compressed_accounts = light_client + .get_compressed_accounts_by_owner(&program_id, None, None) + .await?; + + let pool_compressed = pool_compressed_accounts + .value + .items + .iter() + .find(|acc| acc.address == Some(pool_compressed_address)) + .cloned(); + + let observation_compressed = pool_compressed_accounts + .value + .items + .iter() + .find(|acc| acc.address == Some(observation_compressed_address)) + .cloned(); + + if pool_compressed.is_none() && observation_compressed.is_none() { + if rpc_client.get_account(&pool_address).is_err() { + return Err(anyhow::anyhow!("Onchain pool account does not exist")); + } + if rpc_client.get_account(&observation_address).is_err() { + return Err(anyhow::anyhow!( + "Onchain observation account does not exist" + )); + } + + return Ok(()); + } + + let pool_compressed = + pool_compressed.ok_or_else(|| anyhow::anyhow!("Pool compressed account not found"))?; + let observation_compressed = observation_compressed + .ok_or_else(|| anyhow::anyhow!("Observation compressed account not found"))?; + + let validity_proof_result = light_client + .get_validity_proof( + vec![ + pool_compressed.hash.clone(), + observation_compressed.hash.clone(), + ], + vec![], + None, + ) + .await? + .value; + + let (_, pool_bump) = Pubkey::find_program_address( + &[ + raydium_cp_swap::states::POOL_SEED.as_bytes(), + amm_config.as_ref(), + token_0_mint.as_ref(), + token_1_mint.as_ref(), + ], + &program_id, + ); + + let (_, observation_bump) = Pubkey::find_program_address( + &[ + raydium_cp_swap::states::OBSERVATION_SEED.as_bytes(), + pool_address.as_ref(), + ], + &program_id, + ); + + let state_tree_info = light_client.get_state_tree_infos()[0]; + + let pool_data = pool_compressed + .data + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Pool compressed account has no data"))?; + let pool_state = raydium_cp_swap::states::PoolState::deserialize(&mut &pool_data.data[..])?; + + let observation_data = observation_compressed + .data + .as_ref() + .ok_or_else(|| anyhow::anyhow!("Observation compressed account has no data"))?; + let observation_state = + raydium_cp_swap::states::ObservationState::deserialize(&mut &observation_data.data[..])?; + + let decompress_instr = + light_compressible_client::CompressibleInstruction::decompress_accounts_idempotent( + &program_id, + &CompressibleInstruction::DECOMPRESS_ACCOUNTS_IDEMPOTENT_DISCRIMINATOR, + &payer.pubkey(), + &payer.pubkey(), + &[pool_address, observation_address], + &[ + ( + pool_compressed.clone(), + raydium_cp_swap::raydium_cp_swap::CompressedAccountVariant::PoolState( + pool_state, + ), + vec![ + raydium_cp_swap::states::POOL_SEED.as_bytes().to_vec(), + amm_config.to_bytes().to_vec(), + token_0_mint.to_bytes().to_vec(), + token_1_mint.to_bytes().to_vec(), + ], + ), + ( + observation_compressed.clone(), + raydium_cp_swap::raydium_cp_swap::CompressedAccountVariant::ObservationState( + observation_state, + ), + vec![ + raydium_cp_swap::states::OBSERVATION_SEED + .as_bytes() + .to_vec(), + pool_address.to_bytes().to_vec(), + ], + ), + ], + &[pool_bump, observation_bump], + validity_proof_result, + state_tree_info, + ) + .map_err(|e| anyhow::anyhow!("Failed to build decompress instruction: {}", e))?; + + let lookup_table_address = Pubkey::from_str("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ")?; + let lookup_table = load_lookup_table(&rpc_client, &lookup_table_address)?; + let lookup_tables = vec![lookup_table]; + + let signers = vec![&payer]; + send_versioned_txn( + &rpc_client, + &[decompress_instr], + &signers, + &payer.pubkey(), + &lookup_tables, + true, + )?; + + Ok(()) +} diff --git a/client/src/instructions/mod.rs b/client/src/instructions/mod.rs index 77b482b..041e32b 100644 --- a/client/src/instructions/mod.rs +++ b/client/src/instructions/mod.rs @@ -1,4 +1,5 @@ pub mod amm_instructions; +pub mod compression_instructions; pub mod events_instructions_parse; pub mod rpc; pub mod token_instructions; diff --git a/client/src/instructions/rpc.rs b/client/src/instructions/rpc.rs index 7dc2ff6..7a9b04b 100644 --- a/client/src/instructions/rpc.rs +++ b/client/src/instructions/rpc.rs @@ -1,13 +1,18 @@ -use anyhow::{anyhow, Result}; +use anyhow::Result; use solana_client::{ rpc_client::RpcClient, rpc_config::RpcSendTransactionConfig, rpc_request::RpcRequest, rpc_response::{RpcResult, RpcSimulateTransactionResult}, }; +use solana_message::AddressLookupTableAccount; use solana_sdk::{ - account::Account, commitment_config::CommitmentConfig, program_pack::Pack as TokenPack, - pubkey::Pubkey, signature::Signature, transaction::Transaction, + commitment_config::CommitmentConfig, + instruction::Instruction, + message::{v0, VersionedMessage}, + pubkey::Pubkey, + signature::{Signature, Signer}, + transaction::{Transaction, VersionedTransaction}, }; use std::convert::Into; @@ -25,6 +30,44 @@ pub fn simulate_transaction( }]), ) } +pub fn send_versioned_txn( + client: &RpcClient, + instructions: &[Instruction], + signers: &[&T], + payer: &Pubkey, + lookup_tables: &[AddressLookupTableAccount], + wait_confirm: bool, +) -> Result { + let mut instructions_with_cu = vec![ + solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(1_000_000), + ]; + instructions_with_cu.extend_from_slice(instructions); + let instructions = &instructions_with_cu; + let blockhash = client.get_latest_blockhash()?; + let tx = VersionedTransaction::try_new( + VersionedMessage::V0(v0::Message::try_compile( + payer, + instructions, + lookup_tables, + blockhash, + )?), + signers, + )?; + + client.send_and_confirm_transaction_with_spinner_and_config( + &tx, + if wait_confirm { + CommitmentConfig::confirmed() + } else { + CommitmentConfig::processed() + }, + RpcSendTransactionConfig { + skip_preflight: true, + ..RpcSendTransactionConfig::default() + }, + )?; + Ok(tx.signatures[0]) +} pub fn send_txn(client: &RpcClient, txn: &Transaction, wait_confirm: bool) -> Result { Ok(client.send_and_confirm_transaction_with_spinner_and_config( @@ -40,18 +83,3 @@ pub fn send_txn(client: &RpcClient, txn: &Transaction, wait_confirm: bool) -> Re }, )?) } - -pub fn get_token_account(client: &RpcClient, addr: &Pubkey) -> Result { - let account = client - .get_account_with_commitment(addr, CommitmentConfig::processed())? - .value - .map_or(Err(anyhow!("Account not found")), Ok)?; - T::unpack_from_slice(&account.data).map_err(Into::into) -} - -pub fn get_multiple_accounts( - client: &RpcClient, - pubkeys: &[Pubkey], -) -> Result>> { - Ok(client.get_multiple_accounts(pubkeys)?) -} diff --git a/client/src/instructions/token_instructions.rs b/client/src/instructions/token_instructions.rs index 67bc07c..e2f1d41 100644 --- a/client/src/instructions/token_instructions.rs +++ b/client/src/instructions/token_instructions.rs @@ -10,7 +10,7 @@ use anchor_spl::{ }, }; use anyhow::Result; -use solana_client::rpc_client::RpcClient; +use solana_client::nonblocking::rpc_client::RpcClient; use solana_sdk::{ account::WritableAccount, instruction::Instruction, @@ -19,56 +19,66 @@ use solana_sdk::{ signature::{Keypair, Signer}, system_instruction, }; -// use spl_token_client::token::ExtensionInitializationParams; use std::{rc::Rc, str::FromStr}; -// pub fn create_and_init_mint_instr( -// config: &ClientConfig, -// token_program: Pubkey, -// mint_key: &Pubkey, -// mint_authority: &Pubkey, -// freeze_authority: Option<&Pubkey>, -// extension_init_params: Vec, -// decimals: u8, -// ) -> Result> { -// let payer = read_keypair_file(&config.payer_path)?; -// let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); -// // Client. -// let client = Client::new(url, Rc::new(payer)); -// let program = if token_program == spl_token::id() { -// client.program(spl_token::id())? -// } else { -// client.program(spl_token_2022::id())? -// }; -// let extension_types = extension_init_params -// .iter() -// .map(|e| e.extension()) -// .collect::>(); -// let space = ExtensionType::try_calculate_account_len::(&extension_types)?; +pub async fn create_and_init_mint_instr( + config: &ClientConfig, + token_program: Pubkey, + mint_key: &Pubkey, + mint_authority: &Pubkey, + freeze_authority: Option<&Pubkey>, + decimals: u8, +) -> Result> { + let payer = read_keypair_file(&config.payer_path)?; + let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); + + let client = Client::new(url, Rc::new(payer)); + let program = if token_program == spl_token::id() { + client.program(spl_token::id())? + } else { + client.program(spl_token_2022::id())? + }; + + let space = if token_program == spl_token::id() { + spl_token::state::Mint::LEN + } else { + spl_token_2022::extension::ExtensionType::try_calculate_account_len::< + spl_token_2022::state::Mint, + >(&[])? + }; + + let mut instructions = vec![system_instruction::create_account( + &program.payer(), + mint_key, + program + .rpc() + .get_minimum_balance_for_rent_exemption(space) + .await?, + space as u64, + &program.id(), + )]; -// let mut instructions = vec![system_instruction::create_account( -// &program.payer(), -// mint_key, -// program -// .rpc() -// .get_minimum_balance_for_rent_exemption(space)?, -// space as u64, -// &program.id(), -// )]; -// for params in extension_init_params { -// instructions.push(params.instruction(&token_program, &mint_key)?); -// } -// instructions.push(spl_token_2022::instruction::initialize_mint( -// &program.id(), -// mint_key, -// mint_authority, -// freeze_authority, -// decimals, -// )?); -// Ok(instructions) -// } + if token_program == spl_token::id() { + instructions.push(spl_token::instruction::initialize_mint( + &program.id(), + mint_key, + mint_authority, + freeze_authority, + decimals, + )?); + } else { + instructions.push(spl_token_2022::instruction::initialize_mint( + &program.id(), + mint_key, + mint_authority, + freeze_authority, + decimals, + )?); + } + Ok(instructions) +} -pub fn create_account_rent_exmpt_instr( +pub async fn create_account_rent_exmpt_instr( config: &ClientConfig, new_account_key: &Pubkey, owner: Pubkey, @@ -76,7 +86,7 @@ pub fn create_account_rent_exmpt_instr( ) -> Result> { let payer = read_keypair_file(&config.payer_path)?; let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. + let client = Client::new(url, Rc::new(payer)); let program = client.program(owner)?; let instructions = program @@ -86,7 +96,8 @@ pub fn create_account_rent_exmpt_instr( &new_account_key, program .rpc() - .get_minimum_balance_for_rent_exemption(data_size)?, + .get_minimum_balance_for_rent_exemption(data_size) + .await?, data_size as u64, &program.id(), )) @@ -102,7 +113,7 @@ pub fn create_ata_token_account_instr( ) -> Result> { let payer = read_keypair_file(&config.payer_path)?; let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. + let client = Client::new(url, Rc::new(payer)); let program = client.program(token_program)?; let instructions = program @@ -119,7 +130,7 @@ pub fn create_ata_token_account_instr( Ok(instructions) } -pub fn create_and_init_auxiliary_token( +pub async fn create_and_init_auxiliary_token( config: &ClientConfig, new_account_key: &Pubkey, mint: &Pubkey, @@ -127,8 +138,10 @@ pub fn create_and_init_auxiliary_token( ) -> Result> { let payer = read_keypair_file(&config.payer_path)?; let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - let mint_account = &mut RpcClient::new(config.http_url.to_string()).get_account(&mint)?; - // Client. + let mint_account = &mut RpcClient::new(config.http_url.to_string()) + .get_account(&mint) + .await?; + let client = Client::new(url, Rc::new(payer)); let (program, space) = if mint_account.owner == spl_token::id() { ( @@ -159,7 +172,8 @@ pub fn create_and_init_auxiliary_token( &mint, program .rpc() - .get_minimum_balance_for_rent_exemption(space)?, + .get_minimum_balance_for_rent_exemption(space) + .await?, space as u64, &program.id(), )) @@ -177,7 +191,7 @@ pub fn create_and_init_auxiliary_token( Ok(instructions) } -pub fn close_token_account( +pub async fn close_token_account( config: &ClientConfig, close_account: &Pubkey, destination: &Pubkey, @@ -185,7 +199,7 @@ pub fn close_token_account( ) -> Result> { let payer = read_keypair_file(&config.payer_path)?; let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. + let client = Client::new(url, Rc::new(payer)); let program = client.program(spl_token::id())?; let instructions = program @@ -197,7 +211,7 @@ pub fn close_token_account( &owner.pubkey(), &[], )?) - .signer(owner) + .signer(owner.insecure_clone()) .instructions()?; Ok(instructions) } @@ -211,7 +225,7 @@ pub fn spl_token_transfer_instr( ) -> Result> { let payer = read_keypair_file(&config.payer_path)?; let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. + let client = Client::new(url, Rc::new(payer)); let program = client.program(spl_token::id())?; let instructions = program @@ -224,7 +238,7 @@ pub fn spl_token_transfer_instr( &[], amount, )?) - .signer(from_authority) + .signer(from_authority.insecure_clone()) .instructions()?; Ok(instructions) } @@ -239,7 +253,7 @@ pub fn spl_token_mint_to_instr( ) -> Result> { let payer = read_keypair_file(&config.payer_path)?; let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. + let client = Client::new(url, Rc::new(payer)); let program = if token_program == spl_token::id() { client.program(spl_token::id())? @@ -256,7 +270,7 @@ pub fn spl_token_mint_to_instr( &[], amount, )?) - .signer(mint_authority) + .signer(mint_authority.insecure_clone()) .instructions()?; Ok(instructions) } @@ -268,7 +282,7 @@ pub fn wrap_sol_instr(config: &ClientConfig, amount: u64) -> Result Result> Ok(mint) } +#[allow(dead_code)] #[derive(Debug)] pub struct TransferFeeInfo { pub mint: Pubkey, diff --git a/client/src/main.rs b/client/src/main.rs index e37b3be..8a47f88 100644 --- a/client/src/main.rs +++ b/client/src/main.rs @@ -1,33 +1,29 @@ -#![allow(dead_code)] -use anchor_client::{Client, Cluster}; use anchor_spl::{associated_token::spl_associated_token_account, token::spl_token}; use anyhow::{format_err, Result}; use arrayref::array_ref; use clap::Parser; use configparser::ini::Ini; +use light_client::constants::LOOKUP_TABLE_ADDRESS; +use light_client::rpc::{load_lookup_table, LightClient, LightClientConfig, Rpc}; +use light_compressible_client::account_fetcher::get_compressible_account; +use light_token_client::actions::create_token_pool; +use light_token_client::compressed_token; use solana_client::{rpc_client::RpcClient, rpc_config::RpcTransactionConfig}; use solana_sdk::{ commitment_config::CommitmentConfig, pubkey::Pubkey, signature::{Keypair, Signature, Signer}, - transaction::Transaction, }; use solana_transaction_status::UiTransactionEncoding; -use std::rc::Rc; use std::str::FromStr; mod instructions; use instructions::amm_instructions::*; +use instructions::compression_instructions::*; use instructions::events_instructions_parse::*; use instructions::rpc::*; use instructions::token_instructions::*; use instructions::utils::*; -// use spl_token_2022::{ -// extension::StateWithExtensionsMut, -// state::{Account, Mint}, -// }; - -use crate::instructions::utils; #[derive(Clone, Debug, PartialEq)] pub struct ClientConfig { @@ -107,7 +103,6 @@ pub enum RaydiumCpCommands { }, Withdraw { pool_id: Pubkey, - user_lp_token: Pubkey, lp_token_amount: u64, }, SwapBaseIn { @@ -129,22 +124,24 @@ pub enum RaydiumCpCommands { DecodeTxLog { tx_id: String, }, + InitCompressionConfig {}, + CreateMint { + #[clap(help = "Number of decimal places for the token")] + decimals: u8, + #[clap(short, long, help = "Path to save the mint keypair (optional)")] + save_keypair: Option, + }, } -fn main() -> Result<()> { +#[tokio::main] +async fn main() -> Result<()> { let client_config = "client_config.ini"; let pool_config = load_cfg(&client_config.to_string()).unwrap(); - // cluster params. let payer = read_keypair_file(&pool_config.payer_path)?; - // solana rpc client let rpc_client = RpcClient::new(pool_config.http_url.to_string()); - // anchor client. - let anchor_config = pool_config.clone(); - let url = Cluster::Custom(anchor_config.http_url, anchor_config.ws_url); - let wallet = read_keypair_file(&pool_config.payer_path)?; - let anchor_client = Client::new(url, Rc::new(wallet)); - let program = anchor_client.program(pool_config.raydium_cp_program)?; + // 1. Extend RpcClient with ZK Compression RPC endpoints. + let mut light_client = LightClient::new(LightClientConfig::local()).await?; let opts = Opts::parse(); match opts.command { @@ -156,11 +153,17 @@ fn main() -> Result<()> { open_time, random_pool, } => { + let admin = read_keypair_file(&pool_config.admin_path)?; + + // Initialize compression config once globally. + initialize_compression_config(&rpc_client, &pool_config, &admin).await?; + let (mint0, mint1, init_amount_0, init_amount_1) = if mint0 > mint1 { (mint1, mint0, init_amount_1, init_amount_0) } else { (mint0, mint1, init_amount_0, init_amount_1) }; + let load_pubkeys = vec![mint0, mint1]; let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; let token_0_program = rsps[0].clone().unwrap().owner; @@ -171,7 +174,6 @@ fn main() -> Result<()> { let random_pool_keypair = Keypair::new(); let random_pool_id = if random_pool { let random_pool_id = random_pool_keypair.pubkey(); - println!("random_pool_id:{}", random_pool_id); signers.push(&random_pool_keypair); Some(random_pool_id) } else { @@ -179,6 +181,7 @@ fn main() -> Result<()> { }; let initialize_pool_instr = initialize_pool_instr( + &mut light_client, &pool_config, mint0, mint1, @@ -194,22 +197,24 @@ fn main() -> Result<()> { &mint1, &token_1_program, ), - raydium_cp_swap::create_pool_fee_reveiver::ID, + raydium_cp_swap::create_pool_fee_receiver::ID, random_pool_id, init_amount_0, init_amount_1, open_time, - )?; + ) + .await?; + + let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; - let recent_hash = rpc_client.get_latest_blockhash()?; - let txn = Transaction::new_signed_with_payer( + send_versioned_txn( + &rpc_client, &initialize_pool_instr, - Some(&payer.pubkey()), &signers, - recent_hash, - ); - let signature = send_txn(&rpc_client, &txn, true)?; - println!("{}", signature); + &payer.pubkey(), + &[lookup_table], + true, + )?; } RaydiumCpCommands::Deposit { pool_id, @@ -217,19 +222,30 @@ fn main() -> Result<()> { user_token_1, lp_token_amount, } => { - let pool_state: raydium_cp_swap::states::PoolState = program.account(pool_id)?; - // load account - // pool_account and token vault0, token vault1 must be obtained together to ensure data consistency. - let load_pubkeys = vec![pool_id, pool_state.token_0_vault, pool_state.token_1_vault]; - let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; - let [pool_account, token_0_vault_account, token_1_vault_account] = - array_ref![rsps, 0, 3]; - // docode account let pool_state = - utils::deserialize_anchor_account::( - pool_account.as_ref().unwrap(), + get_compressible_account::( + &pool_id, + &pool_config.raydium_cp_program, + &light_client.get_address_tree_v2(), + &mut light_client, ) - .unwrap(); + .await?; + + decompress_pool_and_observation_idempotent( + &mut light_client, + &rpc_client, + &pool_config, + pool_id, + pool_state.observation_key, + pool_state.amm_config, + pool_state.token_0_mint, + pool_state.token_1_mint, + ) + .await?; + + let load_pubkeys = vec![pool_state.token_0_vault, pool_state.token_1_vault]; + let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; + let [token_0_vault_account, token_1_vault_account] = array_ref![rsps, 0, 2]; let token_0_vault_info = unpack_token(&token_0_vault_account.as_ref().unwrap().data)?; let token_1_vault_info = unpack_token(&token_1_vault_account.as_ref().unwrap().data)?; @@ -237,7 +253,7 @@ fn main() -> Result<()> { u64::from(token_0_vault_info.base.amount), u64::from(token_1_vault_info.base.amount), ); - // calculate amount + let results = raydium_cp_swap::curve::CurveCalculator::lp_tokens_to_trading_tokens( u128::from(lp_token_amount), u128::from(pool_state.lp_supply), @@ -247,11 +263,7 @@ fn main() -> Result<()> { ) .ok_or(raydium_cp_swap::error::ErrorCode::ZeroTradingTokens) .unwrap(); - println!( - "amount_0:{}, amount_1:{}, lp_token_amount:{}", - results.token_0_amount, results.token_1_amount, lp_token_amount - ); - // calc with slippage + let amount_0_with_slippage = amount_with_slippage(results.token_0_amount as u64, pool_config.slippage, true); let amount_1_with_slippage = @@ -264,28 +276,20 @@ fn main() -> Result<()> { amount_0_with_slippage, amount_1_with_slippage, ); - println!( - "transfer_fee_0:{}, transfer_fee_1:{}", - transfer_fee.0.transfer_fee, transfer_fee.1.transfer_fee - ); + let amount_0_max = (amount_0_with_slippage as u64) .checked_add(transfer_fee.0.transfer_fee) .unwrap(); let amount_1_max = (amount_1_with_slippage as u64) .checked_add(transfer_fee.1.transfer_fee) .unwrap(); - println!( - "amount_0_max:{}, amount_1_max:{}", - amount_0_max, amount_1_max - ); + let mut instructions = Vec::new(); - let create_user_lp_token_instr = create_ata_token_account_instr( - &pool_config, - spl_token::id(), - &pool_state.lp_mint, + let owner_lp_token = compressed_token::get_associated_ctoken_address( &payer.pubkey(), - )?; - instructions.extend(create_user_lp_token_instr); + &pool_state.lp_mint, + ); + let deposit_instr = deposit_instr( &pool_config, pool_id, @@ -296,44 +300,57 @@ fn main() -> Result<()> { pool_state.token_1_vault, user_token_0, user_token_1, - spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &pool_state.lp_mint, - ), + owner_lp_token, lp_token_amount, amount_0_max, amount_1_max, )?; instructions.extend(deposit_instr); let signers = vec![&payer]; - let recent_hash = rpc_client.get_latest_blockhash()?; - let txn = Transaction::new_signed_with_payer( + + // Load lookup table + let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; + let lookup_tables = vec![lookup_table]; + + send_versioned_txn( + &rpc_client, &instructions, - Some(&payer.pubkey()), &signers, - recent_hash, - ); - let signature = send_txn(&rpc_client, &txn, true)?; - println!("{}", signature); + &payer.pubkey(), + &lookup_tables, + true, + )?; } RaydiumCpCommands::Withdraw { pool_id, - user_lp_token, lp_token_amount, } => { - let pool_state: raydium_cp_swap::states::PoolState = program.account(pool_id)?; - // load account - // pool_account and token vault0, token vault1 must be obtained together to ensure data consistency. - let load_pubkeys = vec![pool_id, pool_state.token_0_vault, pool_state.token_1_vault]; - let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; - let [pool_account, token_0_vault_account, token_1_vault_account] = - array_ref![rsps, 0, 3]; - // docode account + // Fetch pool state irrespective of whether it's currently + // compressed or decompressed. let pool_state = - utils::deserialize_anchor_account::( - pool_account.as_ref().unwrap(), + get_compressible_account::( + &pool_id, + &pool_config.raydium_cp_program, + &light_client.get_address_tree_v2(), + &mut light_client, ) - .unwrap(); + .await?; + + decompress_pool_and_observation_idempotent( + &mut light_client, + &rpc_client, + &pool_config, + pool_id, + pool_state.observation_key, + pool_state.amm_config, + pool_state.token_0_mint, + pool_state.token_1_mint, + ) + .await?; + + let load_pubkeys = vec![pool_state.token_0_vault, pool_state.token_1_vault]; + let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; + let [token_0_vault_account, token_1_vault_account] = array_ref![rsps, 0, 2]; let token_0_vault_info = unpack_token(&token_0_vault_account.as_ref().unwrap().data)?; let token_1_vault_info = unpack_token(&token_1_vault_account.as_ref().unwrap().data)?; @@ -341,7 +358,7 @@ fn main() -> Result<()> { u64::from(token_0_vault_info.base.amount), u64::from(token_1_vault_info.base.amount), ); - // calculate amount + let results = raydium_cp_swap::curve::CurveCalculator::lp_tokens_to_trading_tokens( u128::from(lp_token_amount), u128::from(pool_state.lp_supply), @@ -351,12 +368,7 @@ fn main() -> Result<()> { ) .ok_or(raydium_cp_swap::error::ErrorCode::ZeroTradingTokens) .unwrap(); - println!( - "amount_0:{}, amount_1:{}, lp_token_amount:{}", - results.token_0_amount, results.token_1_amount, lp_token_amount - ); - // calc with slippage let amount_0_with_slippage = amount_with_slippage(results.token_0_amount as u64, pool_config.slippage, false); let amount_1_with_slippage = @@ -369,20 +381,14 @@ fn main() -> Result<()> { amount_0_with_slippage, amount_1_with_slippage, ); - println!( - "transfer_fee_0:{}, transfer_fee_1:{}", - transfer_fee.0.transfer_fee, transfer_fee.1.transfer_fee - ); + let amount_0_min = amount_0_with_slippage .checked_sub(transfer_fee.0.transfer_fee) .unwrap(); let amount_1_min = amount_1_with_slippage .checked_sub(transfer_fee.1.transfer_fee) .unwrap(); - println!( - "amount_0_min:{}, amount_1_min:{}", - amount_0_min, amount_1_min - ); + let mut instructions = Vec::new(); let create_user_token_0_instr = create_ata_token_account_instr( &pool_config, @@ -398,6 +404,11 @@ fn main() -> Result<()> { &payer.pubkey(), )?; instructions.extend(create_user_token_1_instr); + let owner_lp_token = compressed_token::get_associated_ctoken_address( + &payer.pubkey(), + &pool_state.lp_mint, + ); + let withdraw_instr = withdraw_instr( &pool_config, pool_id, @@ -414,31 +425,55 @@ fn main() -> Result<()> { &payer.pubkey(), &pool_state.token_1_mint, ), - user_lp_token, + owner_lp_token, // Use derived LP token account instead of user_lp_token parameter lp_token_amount, amount_0_min, amount_1_min, )?; instructions.extend(withdraw_instr); let signers = vec![&payer]; - let recent_hash = rpc_client.get_latest_blockhash()?; - let txn = Transaction::new_signed_with_payer( + + // Load lookup table + let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; + let lookup_tables = vec![lookup_table]; + + send_versioned_txn( + &rpc_client, &instructions, - Some(&payer.pubkey()), &signers, - recent_hash, - ); - let signature = send_txn(&rpc_client, &txn, true)?; - println!("{}", signature); + &payer.pubkey(), + &lookup_tables, + true, + )?; } RaydiumCpCommands::SwapBaseIn { pool_id, user_input_token, user_input_amount, } => { - let pool_state: raydium_cp_swap::states::PoolState = program.account(pool_id)?; - // load account - // pool_account and token vault0, token vault1 must be obtained together to ensure data consistency. + // Fetch pool state irrespective of whether it's currently + // compressed or decompressed. + let pool_state = + get_compressible_account::( + &pool_id, + &pool_config.raydium_cp_program, + &light_client.get_address_tree_v2(), + &mut light_client, + ) + .await?; + + decompress_pool_and_observation_idempotent( + &mut light_client, + &rpc_client, + &pool_config, + pool_id, + pool_state.observation_key, + pool_state.amm_config, + pool_state.token_0_mint, + pool_state.token_1_mint, + ) + .await?; + let load_pubkeys = vec![ pool_id, pool_state.amm_config, @@ -452,12 +487,11 @@ fn main() -> Result<()> { let epoch = rpc_client.get_epoch_info().unwrap().epoch; let [pool_account, amm_config_account, token_0_vault_account, token_1_vault_account, token_0_mint_account, token_1_mint_account, user_input_token_account] = array_ref![rsps, 0, 7]; - // docode account - let pool_state = - utils::deserialize_anchor_account::( - pool_account.as_ref().unwrap(), - ) - .unwrap(); + + let pool_state = deserialize_anchor_account::( + pool_account.as_ref().unwrap(), + ) + .unwrap(); let amm_config_state = deserialize_anchor_account::( amm_config_account.as_ref().unwrap(), )?; @@ -523,7 +557,7 @@ fn main() -> Result<()> { get_transfer_fee(&token_1_mint_info, epoch, user_input_amount), ) }; - // Take transfer fees into account for actual amount transferred in + let actual_amount_in = user_input_amount.saturating_sub(transfer_fee); let result = raydium_cp_swap::curve::CurveCalculator::swap_base_input( u128::from(actual_amount_in), @@ -545,7 +579,7 @@ fn main() -> Result<()> { } }; let amount_received = amount_out.checked_sub(transfer_fee).unwrap(); - // calc mint out amount with slippage + let minimum_amount_out = amount_with_slippage(amount_received, pool_config.slippage, false); @@ -575,24 +609,47 @@ fn main() -> Result<()> { )?; instructions.extend(swap_base_in_instr); let signers = vec![&payer]; - let recent_hash = rpc_client.get_latest_blockhash()?; - let txn = Transaction::new_signed_with_payer( + + // Load lookup table + let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; + + send_versioned_txn( + &rpc_client, &instructions, - Some(&payer.pubkey()), &signers, - recent_hash, - ); - let signature = send_txn(&rpc_client, &txn, true)?; - println!("{}", signature); + &payer.pubkey(), + &[lookup_table], + true, + )?; } RaydiumCpCommands::SwapBaseOut { pool_id, user_input_token, amount_out_less_fee, } => { - let pool_state: raydium_cp_swap::states::PoolState = program.account(pool_id)?; - // load account - // pool_account and token vault0, token vault1 must be obtained together to ensure data consistency. + // Fetch pool state irrespective of whether it's currently + // compressed or decompressed. + let pool_state = + get_compressible_account::( + &pool_id, + &pool_config.raydium_cp_program, + &light_client.get_address_tree_v2(), + &mut light_client, + ) + .await?; + + decompress_pool_and_observation_idempotent( + &mut light_client, + &rpc_client, + &pool_config, + pool_id, + pool_state.observation_key, + pool_state.amm_config, + pool_state.token_0_mint, + pool_state.token_1_mint, + ) + .await?; + let load_pubkeys = vec![ pool_id, pool_state.amm_config, @@ -606,12 +663,11 @@ fn main() -> Result<()> { let epoch = rpc_client.get_epoch_info().unwrap().epoch; let [pool_account, amm_config_account, token_0_vault_account, token_1_vault_account, token_0_mint_account, token_1_mint_account, user_input_token_account] = array_ref![rsps, 0, 7]; - // docode account - let pool_state = - utils::deserialize_anchor_account::( - pool_account.as_ref().unwrap(), - ) - .unwrap(); + + let pool_state = deserialize_anchor_account::( + pool_account.as_ref().unwrap(), + ) + .unwrap(); let amm_config_state = deserialize_anchor_account::( amm_config_account.as_ref().unwrap(), )?; @@ -703,7 +759,7 @@ fn main() -> Result<()> { let input_transfer_amount = source_amount_swapped .checked_add(amount_in_transfer_fee) .unwrap(); - // calc max in with slippage + let max_amount_in = amount_with_slippage(input_transfer_amount, pool_config.slippage, true); let mut instructions = Vec::new(); @@ -732,15 +788,18 @@ fn main() -> Result<()> { )?; instructions.extend(swap_base_in_instr); let signers = vec![&payer]; - let recent_hash = rpc_client.get_latest_blockhash()?; - let txn = Transaction::new_signed_with_payer( + + // Load lookup table + let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; + + send_versioned_txn( + &rpc_client, &instructions, - Some(&payer.pubkey()), &signers, - recent_hash, - ); - let signature = send_txn(&rpc_client, &txn, true)?; - println!("{}", signature); + &payer.pubkey(), + &[lookup_table], + true, + )?; } RaydiumCpCommands::DecodeInstruction { instr_hex_data } => { handle_program_instruction(&instr_hex_data, InstructionDecodeType::BaseHex)?; @@ -780,6 +839,90 @@ fn main() -> Result<()> { // decode logs parse_program_event(&pool_config.raydium_cp_program.to_string(), meta.clone())?; } + RaydiumCpCommands::InitCompressionConfig {} => { + let authority = read_keypair_file(&pool_config.admin_path)?; + initialize_compression_config(&rpc_client, &pool_config, &authority).await?; + } + RaydiumCpCommands::CreateMint { + decimals, + save_keypair, + } => { + use crate::instructions::rpc::send_txn; + use crate::instructions::token_instructions::*; + + let mint_keypair = Keypair::new(); + let token_program = spl_token::id(); + let mint_authority = payer.pubkey(); + let freeze_authority = Some(&mint_authority); + + let mut light_client = LightClient::new(LightClientConfig::local()).await?; + + let create_mint_ixs = create_and_init_mint_instr( + &pool_config, + token_program, + &mint_keypair.pubkey(), + &mint_authority, + freeze_authority, + decimals, + ) + .await?; + + let create_ata_ixs = create_ata_token_account_instr( + &pool_config, + token_program, + &mint_keypair.pubkey(), + &payer.pubkey(), + )?; + + let mint_amount = 1_000_000 * 10_u64.pow(decimals as u32); + let ata_address = spl_associated_token_account::get_associated_token_address( + &payer.pubkey(), + &mint_keypair.pubkey(), + ); + + let mint_to_ixs = spl_token_mint_to_instr( + &pool_config, + token_program, + &mint_keypair.pubkey(), + &ata_address, + mint_amount, + &payer, + )?; + + let mut all_instructions = Vec::new(); + all_instructions.extend(create_mint_ixs); + all_instructions.extend(create_ata_ixs); + all_instructions.extend(mint_to_ixs); + + let recent_blockhash = rpc_client.get_latest_blockhash()?; + let transaction = solana_sdk::transaction::Transaction::new_signed_with_payer( + &all_instructions, + Some(&payer.pubkey()), + &[&payer, &mint_keypair], + recent_blockhash, + ); + + let signature = send_txn(&rpc_client, &transaction, true)?; + + // Each SPL mint has to be registered with the compression protocol via a compression token pool. + create_token_pool(&mut light_client, &mint_keypair.pubkey(), false, &payer).await?; + + println!("Mint Address: {}", mint_keypair.pubkey().to_string()); + println!("Your Token Account: {}", ata_address.to_string()); + println!( + "Minted Amount: {} tokens", + mint_amount / 10_u64.pow(decimals as u32) + ); + println!("Transaction Signature: {}", signature.to_string()); + + if let Some(path) = save_keypair { + std::fs::write( + &path, + serde_json::to_string(&mint_keypair.to_bytes().to_vec())?, + )?; + println!("Mint keypair saved to: {}", path); + } + } } Ok(()) } diff --git a/client_config.ini b/client_config.ini index 05caa71..8df7f49 100644 --- a/client_config.ini +++ b/client_config.ini @@ -1,7 +1,9 @@ [Global] -http_url = https://api.devnet.solana.com -ws_url = wss://api.devnet.solana.com/ +http_url = http://127.0.0.1:8899 +ws_url = ws://127.0.0.1:8900/ +# Replace this example path with an absolute path to your solana id.json file +# (often: your_username/.config/solana/id.json) payer_path = id.json -admin_path = adMCyoCgfkg7bQiJ9aBJ59H3BXLY3r5LNLfPpQfMzBe.json -raydium_cp_program = CPMDWBwJDtYax9qW7AyRuVC19Cc4L4Vcy4n2BHAbHkCW +admin_path = id.json +raydium_cp_program = CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C slippage = 0.01 \ No newline at end of file diff --git a/package.json b/package.json index 1545efe..7f9e776 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,14 @@ { "scripts": { "lint:fix": "prettier */*.js \"*/**/*{.js,.ts}\" -w", - "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check" + "lint": "prettier */*.js \"*/**/*{.js,.ts}\" --check", + "test": "./scripts/test-with-light.sh" }, "dependencies": { - "@coral-xyz/anchor": "0.31.0", + "@coral-xyz/anchor": "0.31.1", + "@lightprotocol/compressed-token": "file:../light-protocol/js/compressed-token", + "@lightprotocol/stateless.js": "file:../light-protocol/js/stateless.js", + "@noble/hashes": "^1.8.0", "@solana/spl-token": "^0.4.8", "@solana/web3.js": "^1.95.3" }, @@ -18,4 +22,4 @@ "ts-mocha": "^10.0.0", "typescript": "^4.3.5" } -} \ No newline at end of file +} diff --git a/programs/cp-swap/Cargo.toml b/programs/cp-swap/Cargo.toml index bfd49e6..cba84f1 100644 --- a/programs/cp-swap/Cargo.toml +++ b/programs/cp-swap/Cargo.toml @@ -12,37 +12,44 @@ name = "raydium_cp_swap" [features] no-entrypoint = [] no-log-ix-name = [] +no-idl = [] cpi = ["no-entrypoint"] default = [] enable-log = [] devnet = [] client = [] +anchor-debug = [] idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] test-sbf = [] [dependencies] anchor-lang = { version = "=0.31.1", features = ["init-if-needed", "idl-build"] } -anchor-spl = { version = "=0.31.1", features = ["memo", "metadata", "idl-build"] } +anchor-spl = { version = "=0.31.1", git = "https://github.com/lightprotocol/anchor", rev = "d8a2b3d9", features = ["memo", "metadata", "idl-build"] } spl-token-2022 = { version = "7.0.0", features = ["no-entrypoint"] } spl-math = { version = "0.3", features = ["no-entrypoint"] } uint = "0.10.0" solana-security-txt = "1.1.1" bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] } arrayref = { version = "0.3.6" } -light-sdk = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc", features = ["anchor", "idl-build", "anchor-discriminator-compat"] } -light-sdk-types = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc" } -light-sdk-macros = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc" } -light-hasher = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc", features = ["solana"] } -light-macros = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc", features = ["solana"] } + +light-sdk = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor", "anchor-discriminator-compat", "v2"] } +light-sdk-types = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } +light-hasher = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["solana"] } +light-macros = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["solana"] } +light-sdk-macros = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor-discriminator-compat"] } +light-compressed-account = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } +light-compressed-token-sdk = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } +light-ctoken-types = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } + [dev-dependencies] quickcheck = "1.0.3" proptest = "1.0" rand = "0.9.0" -light-program-test = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc", features = ["v2"] } -light-client = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc", features = ["v2"] } -light-compressible-client = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc", features = ["anchor"] } -light-test-utils = { git = "https://github.com/lightprotocol/light-protocol", branch = "swen-0011-proc" } + +light-program-test = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } +light-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } +light-compressible-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } [profile.release] diff --git a/programs/cp-swap/src/error.rs b/programs/cp-swap/src/error.rs index 6a711d8..5a55cbb 100644 --- a/programs/cp-swap/src/error.rs +++ b/programs/cp-swap/src/error.rs @@ -32,4 +32,11 @@ pub enum ErrorCode { InitLpAmountTooLess, #[msg("TransferFee calculate not match")] TransferFeeCalculateNotMatch, + /// ZK Compression. + #[msg("Invalid account count: PDAs and compressed accounts must match")] + InvalidAccountCount, + #[msg("Rent recipient does not match config")] + InvalidRentRecipient, + #[msg("Invalid LP mint address derivation")] + InvalidLpMintAddress, } diff --git a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs index f5c1765..7da730c 100644 --- a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs @@ -1,5 +1,6 @@ use crate::error::ErrorCode; use crate::states::*; +use crate::utils::ctoken::get_bumps; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_spl::token::Token; @@ -23,23 +24,23 @@ pub struct CollectFundFee<'info> { /// Pool state stores accumulated protocol fee amount #[account(mut)] - pub pool_state: AccountLoader<'info, PoolState>, + pub pool_state: Account<'info, PoolState>, /// Amm config account stores fund_owner - #[account(address = pool_state.load()?.amm_config)] + #[account(address = pool_state.amm_config)] pub amm_config: Account<'info, AmmConfig>, /// The address that holds pool tokens for token_0 #[account( mut, - constraint = token_0_vault.key() == pool_state.load()?.token_0_vault + constraint = token_0_vault.key() == pool_state.token_0_vault )] pub token_0_vault: Box>, /// The address that holds pool tokens for token_1 #[account( mut, - constraint = token_1_vault.key() == pool_state.load()?.token_1_vault + constraint = token_1_vault.key() == pool_state.token_1_vault )] pub token_1_vault: Box>, @@ -65,9 +66,19 @@ pub struct CollectFundFee<'info> { /// The SPL program to perform token transfers pub token_program: Program<'info, Token>, - /// The SPL program 2022 to perform token transfers pub token_program_2022: Program<'info, Token2022>, + + /// CHECK: checked by protocol. + pub compressed_token_program_cpi_authority: AccountInfo<'info>, + /// CHECK: checked by protocol. + pub compressed_token_program: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_0_pool_pda: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_1_pool_pda: AccountInfo<'info>, } pub fn collect_fund_fee( @@ -79,7 +90,7 @@ pub fn collect_fund_fee( let amount_1: u64; let auth_bump: u8; { - let mut pool_state = ctx.accounts.pool_state.load_mut()?; + let pool_state = &mut ctx.accounts.pool_state; amount_0 = amount_0_requested.min(pool_state.fund_fees_token_0); amount_1 = amount_1_requested.min(pool_state.fund_fees_token_1); @@ -88,7 +99,13 @@ pub fn collect_fund_fee( auth_bump = pool_state.auth_bump; pool_state.recent_epoch = Clock::get()?.epoch; } + let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( + ctx.accounts.vault_0_mint.key(), + ctx.accounts.vault_1_mint.key(), + ctx.accounts.compressed_token_program.key(), + ); transfer_from_pool_vault_to_user( + ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.recipient_token_0_account.to_account_info(), @@ -98,12 +115,17 @@ pub fn collect_fund_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_0_pool_pda.to_account_info(), + compressed_token_0_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), amount_0, - ctx.accounts.vault_0_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], )?; transfer_from_pool_vault_to_user( + ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.recipient_token_1_account.to_account_info(), @@ -113,8 +135,12 @@ pub fn collect_fund_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_1_pool_pda.to_account_info(), + compressed_token_1_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), amount_1, - ctx.accounts.vault_1_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], )?; diff --git a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs index 7f55509..520e0ed 100644 --- a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs @@ -1,5 +1,6 @@ use crate::error::ErrorCode; use crate::states::*; +use crate::utils::ctoken::get_bumps; use crate::utils::*; use anchor_lang::prelude::*; use anchor_spl::token::Token; @@ -24,23 +25,23 @@ pub struct CollectProtocolFee<'info> { /// Pool state stores accumulated protocol fee amount #[account(mut)] - pub pool_state: AccountLoader<'info, PoolState>, + pub pool_state: Account<'info, PoolState>, /// Amm config account stores owner - #[account(address = pool_state.load()?.amm_config)] + #[account(address = pool_state.amm_config)] pub amm_config: Account<'info, AmmConfig>, /// The address that holds pool tokens for token_0 #[account( mut, - constraint = token_0_vault.key() == pool_state.load()?.token_0_vault + constraint = token_0_vault.key() == pool_state.token_0_vault )] pub token_0_vault: Box>, /// The address that holds pool tokens for token_1 #[account( mut, - constraint = token_1_vault.key() == pool_state.load()?.token_1_vault + constraint = token_1_vault.key() == pool_state.token_1_vault )] pub token_1_vault: Box>, @@ -69,6 +70,17 @@ pub struct CollectProtocolFee<'info> { /// The SPL program 2022 to perform token transfers pub token_program_2022: Program<'info, Token2022>, + + /// CHECK: checked by protocol. + pub compressed_token_program_cpi_authority: AccountInfo<'info>, + /// CHECK: checked by protocol. + pub compressed_token_program: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_0_pool_pda: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_1_pool_pda: AccountInfo<'info>, } pub fn collect_protocol_fee( @@ -80,7 +92,7 @@ pub fn collect_protocol_fee( let amount_1: u64; let auth_bump: u8; { - let mut pool_state = ctx.accounts.pool_state.load_mut()?; + let pool_state = &mut ctx.accounts.pool_state; amount_0 = amount_0_requested.min(pool_state.protocol_fees_token_0); amount_1 = amount_1_requested.min(pool_state.protocol_fees_token_1); @@ -97,7 +109,15 @@ pub fn collect_protocol_fee( auth_bump = pool_state.auth_bump; pool_state.recent_epoch = Clock::get()?.epoch; } + + let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( + ctx.accounts.vault_0_mint.key(), + ctx.accounts.vault_1_mint.key(), + ctx.accounts.compressed_token_program.key(), + ); + transfer_from_pool_vault_to_user( + ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.recipient_token_0_account.to_account_info(), @@ -107,12 +127,17 @@ pub fn collect_protocol_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_0_pool_pda.to_account_info(), + compressed_token_0_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), amount_0, - ctx.accounts.vault_0_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], )?; transfer_from_pool_vault_to_user( + ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.recipient_token_1_account.to_account_info(), @@ -122,8 +147,12 @@ pub fn collect_protocol_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_1_pool_pda.to_account_info(), + compressed_token_1_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), amount_1, - ctx.accounts.vault_1_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], )?; diff --git a/programs/cp-swap/src/instructions/admin/update_pool_status.rs b/programs/cp-swap/src/instructions/admin/update_pool_status.rs index 97eec1f..d7a20c9 100644 --- a/programs/cp-swap/src/instructions/admin/update_pool_status.rs +++ b/programs/cp-swap/src/instructions/admin/update_pool_status.rs @@ -9,12 +9,12 @@ pub struct UpdatePoolStatus<'info> { pub authority: Signer<'info>, #[account(mut)] - pub pool_state: AccountLoader<'info, PoolState>, + pub pool_state: Account<'info, PoolState>, } pub fn update_pool_status(ctx: Context, status: u8) -> Result<()> { require_gte!(255, status); - let mut pool_state = ctx.accounts.pool_state.load_mut()?; + let pool_state = &mut ctx.accounts.pool_state; pool_state.set_status(status); pool_state.recent_epoch = Clock::get()?.epoch; Ok(()) diff --git a/programs/cp-swap/src/instructions/deposit.rs b/programs/cp-swap/src/instructions/deposit.rs index 79a4970..1f90cf5 100644 --- a/programs/cp-swap/src/instructions/deposit.rs +++ b/programs/cp-swap/src/instructions/deposit.rs @@ -2,10 +2,13 @@ use crate::curve::CurveCalculator; use crate::curve::RoundDirection; use crate::error::ErrorCode; use crate::states::*; +use crate::utils::ctoken::get_bumps; use crate::utils::token::*; +use crate::utils::transfer_ctoken_from_pool_vault_to_user; use anchor_lang::prelude::*; use anchor_spl::token::Token; use anchor_spl::token_interface::{Mint, Token2022, TokenAccount}; +use light_sdk::compressible::HasCompressionInfo; #[derive(Accounts)] pub struct Deposit<'info> { @@ -22,10 +25,10 @@ pub struct Deposit<'info> { pub authority: UncheckedAccount<'info>, #[account(mut)] - pub pool_state: AccountLoader<'info, PoolState>, + pub pool_state: Account<'info, PoolState>, /// Owner lp token account - #[account(mut, token::authority = owner)] + #[account(mut, token::authority = owner)] pub owner_lp_token: Box>, /// The payer's token account for token_0 @@ -47,14 +50,14 @@ pub struct Deposit<'info> { /// The address that holds pool tokens for token_0 #[account( mut, - constraint = token_0_vault.key() == pool_state.load()?.token_0_vault + constraint = token_0_vault.key() == pool_state.token_0_vault )] pub token_0_vault: Box>, /// The address that holds pool tokens for token_1 #[account( mut, - constraint = token_1_vault.key() == pool_state.load()?.token_1_vault + constraint = token_1_vault.key() == pool_state.token_1_vault )] pub token_1_vault: Box>, @@ -76,12 +79,33 @@ pub struct Deposit<'info> { )] pub vault_1_mint: Box>, - /// Lp token mint + /// Lp token vault #[account( mut, - address = pool_state.load()?.lp_mint @ ErrorCode::IncorrectLpMint) - ] - pub lp_mint: Box>, + seeds = [ + POOL_VAULT_SEED.as_bytes(), + pool_state.lp_mint.as_ref() + ], + bump, + token::mint = lp_vault.mint, + token::authority = authority + )] + pub lp_vault: Box>, + + /// CHECK: checked by protocol. + pub compressed_token_program_cpi_authority: AccountInfo<'info>, + /// CHECK: checked by protocol. + pub compressed_token_program: AccountInfo<'info>, + + /// CHECK: checked by protocol. + /// + /// Every mint must be registered in the compression protocol via a + /// compression_token_pool_pda. + #[account(mut)] + pub compressed_token_0_pool_pda: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_1_pool_pda: AccountInfo<'info>, } pub fn deposit( @@ -92,7 +116,7 @@ pub fn deposit( ) -> Result<()> { require_gt!(lp_token_amount, 0); let pool_id = ctx.accounts.pool_state.key(); - let pool_state = &mut ctx.accounts.pool_state.load_mut()?; + let pool_state = &mut ctx.accounts.pool_state; if !pool_state.get_status_by_bit(PoolStatusBitIndex::Deposit) { return err!(ErrorCode::NotApproved); } @@ -131,18 +155,6 @@ pub fn deposit( ) }; - #[cfg(feature = "enable-log")] - msg!( - "results.token_0_amount;{}, results.token_1_amount:{},transfer_token_0_amount:{},transfer_token_0_fee:{}, - transfer_token_1_amount:{},transfer_token_1_fee:{}", - results.token_0_amount, - results.token_1_amount, - transfer_token_0_amount, - transfer_token_0_fee, - transfer_token_1_amount, - transfer_token_1_fee - ); - emit!(LpChangeEvent { pool_id, lp_amount_before: pool_state.lp_supply, @@ -160,6 +172,11 @@ pub fn deposit( { return Err(ErrorCode::ExceededSlippage.into()); } + let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( + ctx.accounts.vault_0_mint.key(), + ctx.accounts.vault_1_mint.key(), + ctx.accounts.compressed_token_program.key(), + ); transfer_from_user_to_pool_vault( ctx.accounts.owner.to_account_info(), @@ -171,8 +188,12 @@ pub fn deposit( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_0_pool_pda.to_account_info(), + compressed_token_0_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), transfer_token_0_amount, - ctx.accounts.vault_0_mint.decimals, )?; transfer_from_user_to_pool_vault( @@ -185,21 +206,28 @@ pub fn deposit( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_1_pool_pda.to_account_info(), + compressed_token_1_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), transfer_token_1_amount, - ctx.accounts.vault_1_mint.decimals, )?; pool_state.lp_supply = pool_state.lp_supply.checked_add(lp_token_amount).unwrap(); - token_mint_to( + transfer_ctoken_from_pool_vault_to_user( ctx.accounts.authority.to_account_info(), - ctx.accounts.token_program.to_account_info(), - ctx.accounts.lp_mint.to_account_info(), + ctx.accounts.lp_vault.to_account_info(), ctx.accounts.owner_lp_token.to_account_info(), lp_token_amount, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; + pool_state.recent_epoch = Clock::get()?.epoch; + // The account was written to, so we must update CompressionInfo. + pool_state.compression_info_mut().bump_last_written_slot()?; + Ok(()) } diff --git a/programs/cp-swap/src/instructions/initialize.rs b/programs/cp-swap/src/instructions/initialize.rs index a4a9a49..80329aa 100644 --- a/programs/cp-swap/src/instructions/initialize.rs +++ b/programs/cp-swap/src/instructions/initialize.rs @@ -6,7 +6,6 @@ use anchor_lang::{ accounts::interface_account::InterfaceAccount, prelude::*, solana_program::{clock, program::invoke, system_instruction}, - system_program, }; use anchor_spl::{ associated_token::AssociatedToken, @@ -14,6 +13,14 @@ use anchor_spl::{ token::Token, token_interface::{Mint, TokenAccount, TokenInterface}, }; +use light_sdk::cpi::CpiAccountsSmall; +use light_sdk::{ + compressible::CompressibleConfig, + instruction::{borsh_compat::ValidityProof, PackedAddressTreeInfo}, +}; +use light_sdk_types::CpiAccountsConfig; + +use crate::LIGHT_CPI_SIGNER; use spl_token_2022; use std::ops::Deref; @@ -37,17 +44,19 @@ pub struct Initialize<'info> { pub authority: UncheckedAccount<'info>, /// CHECK: Initialize an account to store the pool state - /// PDA account: - /// seeds = [ - ///     POOL_SEED.as_bytes(), - ///     amm_config.key().as_ref(), - ///     token_0_mint.key().as_ref(), - ///     token_1_mint.key().as_ref(), - /// ], - /// - /// Or random account: must be signed by cli - #[account(mut)] - pub pool_state: UncheckedAccount<'info>, + #[account( + init, + seeds = [ + POOL_SEED.as_bytes(), + amm_config.key().as_ref(), + token_0_mint.key().as_ref(), + token_1_mint.key().as_ref(), + ], + bump, + payer = creator, + space = PoolState::INIT_SPACE + )] + pub pool_state: Box>, /// Token_0 mint, the key must smaller than token_1 mint. #[account( @@ -62,20 +71,19 @@ pub struct Initialize<'info> { )] pub token_1_mint: Box>, - /// pool lp mint + /// Signer pda used to derive lp_mint and its compressed address. + /// CHECK: checked by protocol. #[account( - init, seeds = [ POOL_LP_MINT_SEED.as_bytes(), pool_state.key().as_ref(), - ], + ], bump, - mint::decimals = 9, - mint::authority = authority, - payer = creator, - mint::token_program = token_program, )] - pub lp_mint: Box>, + pub lp_mint_signer: UncheckedAccount<'info>, + + /// CHECK: checked via mint_signer. + pub lp_mint: UncheckedAccount<'info>, /// payer token0 account #[account( @@ -93,15 +101,20 @@ pub struct Initialize<'info> { )] pub creator_token_1: Box>, - /// creator lp token account + /// CHECK: + #[account(mut)] + pub creator_lp_token: UncheckedAccount<'info>, + + /// CHECK: #[account( - init, - associated_token::mint = lp_mint, - associated_token::authority = creator, - payer = creator, - token::token_program = token_program, + mut, + seeds = [ + POOL_VAULT_SEED.as_bytes(), + lp_mint.key().as_ref() + ], + bump, )] - pub creator_lp_token: Box>, + pub lp_vault: UncheckedAccount<'info>, /// CHECK: Token_0 vault for the pool, created by contract #[account( @@ -130,7 +143,7 @@ pub struct Initialize<'info> { /// create pool fee account #[account( mut, - address= crate::create_pool_fee_reveiver::ID, + address= crate::create_pool_fee_receiver::ID, )] pub create_pool_fee: Box>, @@ -143,9 +156,9 @@ pub struct Initialize<'info> { ], bump, payer = creator, - space = ObservationState::LEN + space = ObservationState::INIT_SPACE )] - pub observation_state: AccountLoader<'info, ObservationState>, + pub observation_state: Box>, /// Program to create mint account and mint tokens pub token_program: Program<'info, Token>, @@ -159,13 +172,38 @@ pub struct Initialize<'info> { pub system_program: Program<'info, System>, /// Sysvar for program account pub rent: Sysvar<'info, Rent>, + + /// CHECK: checked via load_checked. + pub compression_config: AccountInfo<'info>, + /// CHECK: checked in instruction. + #[account(mut)] + pub rent_recipient: AccountInfo<'info>, + /// CHECK: checked by protocol. + pub compressed_token_program_cpi_authority: AccountInfo<'info>, + /// CHECK: checked by protocol. + pub compressed_token_program: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_0_pool_pda: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_1_pool_pda: AccountInfo<'info>, } -pub fn initialize( - ctx: Context, +// This instruction: +// 0. Runs checks and loads compression config. +// 1. Creates token vault accounts for pool tokens as compressible. +// 2. Creates user token accounts as compressible. +// 3. Initializes PoolState and ObservationState as compressible. +// 4. Creates compressed token mint for LP tokens. +// 5. Distributes initial liquidity to user and vault. +// 6. Compresses PoolState and ObservationState. +pub fn initialize<'info>( + ctx: Context<'_, '_, '_, 'info, Initialize<'info>>, init_amount_0: u64, init_amount_1: u64, mut open_time: u64, + compression_params: InitializeCompressionParams, ) -> Result<()> { if !(is_supported_mint(&ctx.accounts.token_0_mint).unwrap() && is_supported_mint(&ctx.accounts.token_1_mint).unwrap()) @@ -176,53 +214,67 @@ pub fn initialize( if ctx.accounts.amm_config.disable_create_pool { return err!(ErrorCode::NotApproved); } + + // ZK Compression Step 1: Load compression config and check rent recipient + let compression_config = + CompressibleConfig::load_checked(&ctx.accounts.compression_config, &crate::ID)?; + let rent_recipient = &ctx.accounts.rent_recipient; + if rent_recipient.key() != compression_config.rent_recipient { + return err!(ErrorCode::InvalidRentRecipient); + } + let block_timestamp = clock::Clock::get()?.unix_timestamp as u64; if open_time <= block_timestamp { open_time = block_timestamp + 1; } - // due to stack/heap limitations, we have to create redundant new accounts ourselves. - create_token_account( + + create_compressible_token_account( &ctx.accounts.authority.to_account_info(), &ctx.accounts.creator.to_account_info(), &ctx.accounts.token_0_vault.to_account_info(), &ctx.accounts.token_0_mint.to_account_info(), &ctx.accounts.system_program.to_account_info(), - &ctx.accounts.token_0_program.to_account_info(), + &ctx.accounts.compressed_token_program.to_account_info(), &[ POOL_VAULT_SEED.as_bytes(), ctx.accounts.pool_state.key().as_ref(), ctx.accounts.token_0_mint.key().as_ref(), &[ctx.bumps.token_0_vault][..], ], + &ctx.accounts.rent.to_account_info(), + &ctx.accounts.rent_recipient.to_account_info(), + compression_config.compression_delay as u64, )?; - create_token_account( + create_compressible_token_account( &ctx.accounts.authority.to_account_info(), &ctx.accounts.creator.to_account_info(), &ctx.accounts.token_1_vault.to_account_info(), &ctx.accounts.token_1_mint.to_account_info(), &ctx.accounts.system_program.to_account_info(), - &ctx.accounts.token_1_program.to_account_info(), + &ctx.accounts.compressed_token_program.to_account_info(), &[ POOL_VAULT_SEED.as_bytes(), ctx.accounts.pool_state.key().as_ref(), ctx.accounts.token_1_mint.key().as_ref(), &[ctx.bumps.token_1_vault][..], ], + &ctx.accounts.rent_recipient.to_account_info(), + &ctx.accounts.rent_recipient.to_account_info(), + compression_config.compression_delay as u64, )?; - let pool_state_loader = create_pool( - &ctx.accounts.creator.to_account_info(), - &ctx.accounts.pool_state.to_account_info(), - &ctx.accounts.amm_config.to_account_info(), - &ctx.accounts.token_0_mint.to_account_info(), - &ctx.accounts.token_1_mint.to_account_info(), - &ctx.accounts.system_program.to_account_info(), - )?; - let pool_state = &mut pool_state_loader.load_init()?; + let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( + ctx.accounts.token_0_mint.key(), + ctx.accounts.token_1_mint.key(), + ctx.accounts.compressed_token_program.key(), + ); - let mut observation_state = ctx.accounts.observation_state.load_init()?; - observation_state.pool_id = ctx.accounts.pool_state.key(); + let pool_state = &mut ctx.accounts.pool_state; + let pool_state_key = pool_state.key(); + let observation_state = &mut ctx.accounts.observation_state; + let observation_state_key = observation_state.key(); + observation_state.pool_id = pool_state_key; transfer_from_user_to_pool_vault( ctx.accounts.creator.to_account_info(), @@ -230,8 +282,12 @@ pub fn initialize( ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.token_0_mint.to_account_info(), ctx.accounts.token_0_program.to_account_info(), + ctx.accounts.compressed_token_0_pool_pda.to_account_info(), + compressed_token_0_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), init_amount_0, - ctx.accounts.token_0_mint.decimals, )?; transfer_from_user_to_pool_vault( @@ -240,8 +296,12 @@ pub fn initialize( ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.token_1_mint.to_account_info(), ctx.accounts.token_1_program.to_account_info(), + ctx.accounts.compressed_token_1_pool_pda.to_account_info(), + compressed_token_1_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), init_amount_1, - ctx.accounts.token_1_mint.decimals, )?; let token_0_vault = @@ -265,30 +325,6 @@ pub fn initialize( CurveCalculator::validate_supply(token_0_vault.amount, token_1_vault.amount)?; - let liquidity = U128::from(token_0_vault.amount) - .checked_mul(token_1_vault.amount.into()) - .unwrap() - .integer_sqrt() - .as_u64(); - let lock_lp_amount = 100; - msg!( - "liquidity:{}, lock_lp_amount:{}, vault_0_amount:{},vault_1_amount:{}", - liquidity, - lock_lp_amount, - token_0_vault.amount, - token_1_vault.amount - ); - token::token_mint_to( - ctx.accounts.authority.to_account_info(), - ctx.accounts.token_program.to_account_info(), - ctx.accounts.lp_mint.to_account_info(), - ctx.accounts.creator_lp_token.to_account_info(), - liquidity - .checked_sub(lock_lp_amount) - .ok_or(ErrorCode::InitLpAmountTooLess)?, - &[&[crate::AUTH_SEED.as_bytes(), &[ctx.bumps.authority]]], - )?; - // Charge the fee to create a pool if ctx.accounts.amm_config.create_pool_fee != 0 { invoke( @@ -314,6 +350,19 @@ pub fn initialize( ], )?; } + let liquidity = U128::from(token_0_vault.amount) + .checked_mul(token_1_vault.amount.into()) + .unwrap() + .integer_sqrt() + .as_u64(); + let lock_lp_amount = 100; + + let user_lp_amount = liquidity + .checked_sub(lock_lp_amount) + .ok_or(ErrorCode::InitLpAmountTooLess)?; + let vault_lp_amount = u64::MAX + .checked_sub(user_lp_amount) + .ok_or(ErrorCode::InitLpAmountTooLess)?; pool_state.initialize( ctx.bumps.authority, @@ -325,56 +374,110 @@ pub fn initialize( ctx.accounts.token_1_vault.key(), &ctx.accounts.token_0_mint, &ctx.accounts.token_1_mint, + &ctx.accounts.lp_vault, &ctx.accounts.lp_mint, - ctx.accounts.observation_state.key(), + observation_state_key, ); - - Ok(()) -} - -pub fn create_pool<'info>( - payer: &AccountInfo<'info>, - pool_account_info: &AccountInfo<'info>, - amm_config: &AccountInfo<'info>, - token_0_mint: &AccountInfo<'info>, - token_1_mint: &AccountInfo<'info>, - system_program: &AccountInfo<'info>, -) -> Result> { - if pool_account_info.owner != &system_program::ID { - return err!(ErrorCode::NotApproved); - } - - let (expect_pda_address, bump) = Pubkey::find_program_address( - &[ - POOL_SEED.as_bytes(), - amm_config.key().as_ref(), - token_0_mint.key().as_ref(), - token_1_mint.key().as_ref(), - ], - &crate::id(), + let pool_auth_bump = pool_state.auth_bump; + + // ZK Compression Step 2: Setup CPI accounts. We compress PDAs **and** + // create a cMint (lp_mint), so we need to use 'with_cpi_context'. + let cpi_accounts = CpiAccountsSmall::new_with_config( + &ctx.accounts.creator, + ctx.remaining_accounts, + CpiAccountsConfig::new_with_cpi_context(LIGHT_CPI_SIGNER), ); - if pool_account_info.key() != expect_pda_address { - require_eq!(pool_account_info.is_signer, true); - } + // ZK Compression Step 3: Compress the PDAs. + compress_pool_and_observation_pdas( + &cpi_accounts, + &pool_state, + &observation_state, + &compression_params, + &rent_recipient, + &compression_config.address_space, + )?; - token::create_or_allocate_account( - &crate::id(), - payer.to_account_info(), - system_program.to_account_info(), - pool_account_info.clone(), + // ZK Compression Step 4: Create ctoken accounts. These match regular + // SPL token accounts but are compressible. + create_compressible_token_account( + &ctx.accounts.authority.to_account_info(), + &ctx.accounts.creator.to_account_info(), + &ctx.accounts.lp_vault.to_account_info(), + &ctx.accounts.lp_mint.to_account_info(), + &ctx.accounts.system_program.to_account_info(), + &ctx.accounts.compressed_token_program.to_account_info(), &[ - POOL_SEED.as_bytes(), - amm_config.key().as_ref(), - token_0_mint.key().as_ref(), - token_1_mint.key().as_ref(), - &[bump], + POOL_VAULT_SEED.as_bytes(), + ctx.accounts.lp_mint.key().as_ref(), + &[ctx.bumps.lp_vault][..], ], - PoolState::LEN, + &ctx.accounts.rent.to_account_info(), + &ctx.accounts.rent_recipient.to_account_info(), + compression_config.compression_delay as u64, + )?; + create_compressible_associated_token_account( + &ctx.accounts.creator.to_account_info(), + &ctx.accounts.creator.to_account_info(), + &ctx.accounts.creator_lp_token.to_account_info(), + &ctx.accounts.lp_mint.to_account_info(), + &ctx.accounts.system_program.to_account_info(), + &ctx.accounts.rent.to_account_info(), + &ctx.accounts.rent_recipient.to_account_info(), + compression_config.compression_delay as u64, + compression_params.creator_lp_token_bump, + )?; + + // ZK Compression Step 5: We create the lp cMint and distribute the lp tokens + // to the lp_vault and user based on the regular LP math. + create_and_mint_lp( + ctx.accounts.creator.to_account_info(), + ctx.accounts.authority.to_account_info(), + &ctx.accounts.lp_mint.key(), + ctx.accounts.lp_vault.to_account_info(), + ctx.accounts.creator_lp_token.to_account_info(), + ctx.accounts.lp_mint_signer.to_account_info(), + &pool_state_key, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), + ctx.accounts.compressed_token_program.to_account_info(), + ctx.bumps.lp_mint_signer, + &compression_params, + &cpi_accounts, + user_lp_amount, + vault_lp_amount, + pool_auth_bump, )?; - Ok(AccountLoad::::try_from_unchecked( - &crate::id(), - &pool_account_info, - )?) + // ZK Compression Step 6: Clean up compressed onchain PDAs. Always do this + // at the end of your instruction. Only PoolState and ObservationState are + // being compressed right away. All other accounts only initialized as + // compressible - for async compression once they're inactive. PoolState and + // ObservationState are compressed atomically for demo purposes. You can + // choose whether to compress_at_init or only after they've become inactive. + // If you compress_at_init, you pay 0 upfront rent, but the first + // transaction to use the account must include a + // decompress_accounts_idempotent instruction in their transaction which + // fronts then rent. Only the first touch will actually decompress the + // account; swap n+1 will still succeed. + pool_state.close(rent_recipient.clone())?; + observation_state.close(rent_recipient.clone())?; + + Ok(()) +} + +#[derive(AnchorSerialize, AnchorDeserialize, Debug)] +pub struct InitializeCompressionParams { + // pool state + pub pool_address_tree_info: PackedAddressTreeInfo, + // observation state + pub observation_address_tree_info: PackedAddressTreeInfo, + // lp mint + pub lp_mint_address_tree_info: PackedAddressTreeInfo, + pub lp_mint_bump: u8, + pub creator_lp_token_bump: u8, + // shared + pub proof: ValidityProof, + pub output_state_tree_index: u8, } diff --git a/programs/cp-swap/src/instructions/swap_base_input.rs b/programs/cp-swap/src/instructions/swap_base_input.rs index f93a49a..359b361 100644 --- a/programs/cp-swap/src/instructions/swap_base_input.rs +++ b/programs/cp-swap/src/instructions/swap_base_input.rs @@ -2,10 +2,12 @@ use crate::curve::calculator::CurveCalculator; use crate::curve::TradeDirection; use crate::error::ErrorCode; use crate::states::*; +use crate::utils::ctoken::get_bumps; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_lang::solana_program; use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; +use light_sdk::compressible::HasCompressionInfo; #[derive(Accounts)] pub struct Swap<'info> { @@ -22,12 +24,12 @@ pub struct Swap<'info> { pub authority: UncheckedAccount<'info>, /// The factory state to read protocol fees - #[account(address = pool_state.load()?.amm_config)] + #[account(address = pool_state.amm_config)] pub amm_config: Box>, /// The program account of the pool in which the swap will be performed #[account(mut)] - pub pool_state: AccountLoader<'info, PoolState>, + pub pool_state: Box>, /// The user token account for input token #[account(mut)] @@ -40,14 +42,14 @@ pub struct Swap<'info> { /// The vault token account for input token #[account( mut, - constraint = input_vault.key() == pool_state.load()?.token_0_vault || input_vault.key() == pool_state.load()?.token_1_vault + constraint = input_vault.key() == pool_state.token_0_vault || input_vault.key() == pool_state.token_1_vault )] pub input_vault: Box>, /// The vault token account for output token #[account( mut, - constraint = output_vault.key() == pool_state.load()?.token_0_vault || output_vault.key() == pool_state.load()?.token_1_vault + constraint = output_vault.key() == pool_state.token_0_vault || output_vault.key() == pool_state.token_1_vault )] pub output_vault: Box>, @@ -69,14 +71,28 @@ pub struct Swap<'info> { )] pub output_token_mint: Box>, /// The program account for the most recent oracle observation - #[account(mut, address = pool_state.load()?.observation_key)] - pub observation_state: AccountLoader<'info, ObservationState>, + #[account(mut, address = pool_state.observation_key)] + pub observation_state: Account<'info, ObservationState>, + + /// CHECK: checked by protocol. + pub compressed_token_program_cpi_authority: AccountInfo<'info>, + /// CHECK: checked by protocol. + pub compressed_token_program: AccountInfo<'info>, + /// CHECK: checked by protocol. + /// + /// Every mint must be registered in the compression protocol via a + /// compression_token_pool_pda. + #[account(mut)] + pub compressed_token_0_pool_pda: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_1_pool_pda: AccountInfo<'info>, } pub fn swap_base_input(ctx: Context, amount_in: u64, minimum_amount_out: u64) -> Result<()> { let block_timestamp = solana_program::clock::Clock::get()?.unix_timestamp as u64; let pool_id = ctx.accounts.pool_state.key(); - let pool_state = &mut ctx.accounts.pool_state.load_mut()?; + let pool_state = &mut ctx.accounts.pool_state; if !pool_state.get_status_by_bit(PoolStatusBitIndex::Swap) || block_timestamp < pool_state.open_time { @@ -225,34 +241,51 @@ pub fn swap_base_input(ctx: Context, amount_in: u64, minimum_amount_out: u }); require_gte!(constant_after, constant_before); + let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( + ctx.accounts.input_token_mint.key(), + ctx.accounts.output_token_mint.key(), + ctx.accounts.compressed_token_program.key(), + ); transfer_from_user_to_pool_vault( ctx.accounts.payer.to_account_info(), ctx.accounts.input_token_account.to_account_info(), ctx.accounts.input_vault.to_account_info(), ctx.accounts.input_token_mint.to_account_info(), ctx.accounts.input_token_program.to_account_info(), + ctx.accounts.compressed_token_0_pool_pda.to_account_info(), + compressed_token_0_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), input_transfer_amount, - ctx.accounts.input_token_mint.decimals, )?; transfer_from_pool_vault_to_user( + ctx.accounts.payer.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.output_vault.to_account_info(), ctx.accounts.output_token_account.to_account_info(), ctx.accounts.output_token_mint.to_account_info(), ctx.accounts.output_token_program.to_account_info(), + ctx.accounts.compressed_token_1_pool_pda.to_account_info(), + compressed_token_1_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), output_transfer_amount, - ctx.accounts.output_token_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; // update the previous price to the observation - ctx.accounts.observation_state.load_mut()?.update( + ctx.accounts.observation_state.update( oracle::block_timestamp(), token_0_price_x64, token_1_price_x64, ); pool_state.recent_epoch = Clock::get()?.epoch; + // The account was written to, so we must update CompressionInfo. + pool_state.compression_info_mut().bump_last_written_slot()?; + Ok(()) } diff --git a/programs/cp-swap/src/instructions/swap_base_output.rs b/programs/cp-swap/src/instructions/swap_base_output.rs index 2ba3731..97fdbfe 100644 --- a/programs/cp-swap/src/instructions/swap_base_output.rs +++ b/programs/cp-swap/src/instructions/swap_base_output.rs @@ -2,9 +2,11 @@ use super::swap_base_input::Swap; use crate::curve::{calculator::CurveCalculator, TradeDirection}; use crate::error::ErrorCode; use crate::states::*; +use crate::utils::ctoken::get_bumps; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_lang::solana_program; +use light_sdk::compressible::HasCompressionInfo; pub fn swap_base_output( ctx: Context, @@ -14,7 +16,7 @@ pub fn swap_base_output( require_gt!(amount_out_less_fee, 0); let block_timestamp = solana_program::clock::Clock::get()?.unix_timestamp as u64; let pool_id = ctx.accounts.pool_state.key(); - let pool_state = &mut ctx.accounts.pool_state.load_mut()?; + let pool_state = &mut ctx.accounts.pool_state; if !pool_state.get_status_by_bit(PoolStatusBitIndex::Swap) || block_timestamp < pool_state.open_time { @@ -165,34 +167,52 @@ pub fn swap_base_output( }); require_gte!(constant_after, constant_before); + let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( + ctx.accounts.input_token_mint.key(), + ctx.accounts.output_token_mint.key(), + ctx.accounts.compressed_token_program.key(), + ); + transfer_from_user_to_pool_vault( ctx.accounts.payer.to_account_info(), ctx.accounts.input_token_account.to_account_info(), ctx.accounts.input_vault.to_account_info(), ctx.accounts.input_token_mint.to_account_info(), ctx.accounts.input_token_program.to_account_info(), + ctx.accounts.compressed_token_0_pool_pda.to_account_info(), + compressed_token_0_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), input_transfer_amount, - ctx.accounts.input_token_mint.decimals, )?; transfer_from_pool_vault_to_user( + ctx.accounts.payer.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.output_vault.to_account_info(), ctx.accounts.output_token_account.to_account_info(), ctx.accounts.output_token_mint.to_account_info(), ctx.accounts.output_token_program.to_account_info(), + ctx.accounts.compressed_token_1_pool_pda.to_account_info(), + compressed_token_1_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), output_transfer_amount, - ctx.accounts.output_token_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; // update the previous price to the observation - ctx.accounts.observation_state.load_mut()?.update( + ctx.accounts.observation_state.update( oracle::block_timestamp(), token_0_price_x64, token_1_price_x64, ); pool_state.recent_epoch = Clock::get()?.epoch; + // The account was written to, so we must update CompressionInfo. + pool_state.compression_info_mut().bump_last_written_slot()?; + Ok(()) } diff --git a/programs/cp-swap/src/instructions/withdraw.rs b/programs/cp-swap/src/instructions/withdraw.rs index 6b60722..60b341f 100644 --- a/programs/cp-swap/src/instructions/withdraw.rs +++ b/programs/cp-swap/src/instructions/withdraw.rs @@ -1,14 +1,17 @@ use crate::curve::CurveCalculator; use crate::curve::RoundDirection; use crate::error::ErrorCode; +use crate::utils::ctoken::get_bumps; use crate::states::*; use crate::utils::token::*; +use crate::utils::transfer_ctoken_from_user_to_pool_vault; use anchor_lang::prelude::*; use anchor_spl::{ memo::spl_memo, token::Token, token_interface::{Mint, Token2022, TokenAccount}, }; +use light_sdk::compressible::HasCompressionInfo; #[derive(Accounts)] pub struct Withdraw<'info> { @@ -26,9 +29,8 @@ pub struct Withdraw<'info> { /// Pool state account #[account(mut)] - pub pool_state: AccountLoader<'info, PoolState>, + pub pool_state: Box>, - /// Owner lp token account #[account( mut, token::authority = owner @@ -52,14 +54,14 @@ pub struct Withdraw<'info> { /// The address that holds pool tokens for token_0 #[account( mut, - constraint = token_0_vault.key() == pool_state.load()?.token_0_vault + constraint = token_0_vault.key() == pool_state.token_0_vault )] pub token_0_vault: Box>, /// The address that holds pool tokens for token_1 #[account( mut, - constraint = token_1_vault.key() == pool_state.load()?.token_1_vault + constraint = token_1_vault.key() == pool_state.token_1_vault )] pub token_1_vault: Box>, @@ -81,12 +83,32 @@ pub struct Withdraw<'info> { )] pub vault_1_mint: Box>, - /// Pool lp token mint + /// Program lp token vault #[account( mut, - address = pool_state.load()?.lp_mint @ ErrorCode::IncorrectLpMint) - ] - pub lp_mint: Box>, + seeds = [ + POOL_VAULT_SEED.as_bytes(), + pool_state.lp_mint.as_ref() + ], + bump, + token::mint = lp_vault.mint, + token::authority = authority + )] + pub lp_vault: InterfaceAccount<'info, TokenAccount>, + + /// CHECK: checked by protocol. + pub compressed_token_program_cpi_authority: AccountInfo<'info>, + /// CHECK: checked by protocol. + pub compressed_token_program: AccountInfo<'info>, + /// CHECK: checked by protocol. + /// + /// Every mint must be registered in the compression protocol via a + /// compression_token_pool_pda. + #[account(mut)] + pub compressed_token_0_pool_pda: AccountInfo<'info>, + /// CHECK: checked by protocol. + #[account(mut)] + pub compressed_token_1_pool_pda: AccountInfo<'info>, /// memo program /// CHECK: @@ -103,9 +125,9 @@ pub fn withdraw( minimum_token_1_amount: u64, ) -> Result<()> { require_gt!(lp_token_amount, 0); - require_gt!(ctx.accounts.lp_mint.supply, 0); + require_gt!(ctx.accounts.lp_vault.amount, 0); let pool_id = ctx.accounts.pool_state.key(); - let pool_state = &mut ctx.accounts.pool_state.load_mut()?; + let pool_state = &mut ctx.accounts.pool_state; if !pool_state.get_status_by_bit(PoolStatusBitIndex::Withdraw) { return err!(ErrorCode::NotApproved); } @@ -175,17 +197,23 @@ pub fn withdraw( return Err(ErrorCode::ExceededSlippage.into()); } - pool_state.lp_supply = pool_state.lp_supply.checked_sub(lp_token_amount).unwrap(); - token_burn( + transfer_ctoken_from_user_to_pool_vault( ctx.accounts.owner.to_account_info(), - ctx.accounts.token_program.to_account_info(), - ctx.accounts.lp_mint.to_account_info(), ctx.accounts.owner_lp_token.to_account_info(), + ctx.accounts.lp_vault.to_account_info(), lp_token_amount, - &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; + pool_state.lp_supply = pool_state.lp_supply.checked_sub(lp_token_amount).unwrap(); + + let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( + ctx.accounts.vault_0_mint.key(), + ctx.accounts.vault_1_mint.key(), + ctx.accounts.compressed_token_program.key(), + ); + transfer_from_pool_vault_to_user( + ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.token_0_account.to_account_info(), @@ -195,12 +223,17 @@ pub fn withdraw( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_0_pool_pda.to_account_info(), + compressed_token_0_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), token_0_amount, - ctx.accounts.vault_0_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; transfer_from_pool_vault_to_user( + ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.token_1_account.to_account_info(), @@ -210,11 +243,19 @@ pub fn withdraw( } else { ctx.accounts.token_program_2022.to_account_info() }, + ctx.accounts.compressed_token_1_pool_pda.to_account_info(), + compressed_token_1_pool_bump, + ctx.accounts + .compressed_token_program_cpi_authority + .to_account_info(), token_1_amount, - ctx.accounts.vault_1_mint.decimals, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; + pool_state.recent_epoch = Clock::get()?.epoch; + // The account was written to, so we must update CompressionInfo. + pool_state.compression_info_mut().bump_last_written_slot().unwrap(); + Ok(()) } diff --git a/programs/cp-swap/src/lib.rs b/programs/cp-swap/src/lib.rs index 516a83b..37aaec6 100644 --- a/programs/cp-swap/src/lib.rs +++ b/programs/cp-swap/src/lib.rs @@ -5,8 +5,13 @@ pub mod states; pub mod utils; use crate::curve::fees::FEE_RATE_DENOMINATOR_VALUE; +pub use crate::instructions::initialize::Initialize; +pub use crate::states::{ObservationState, PoolState}; use anchor_lang::prelude::*; use instructions::*; +use light_sdk::derive_light_cpi_signer; +use light_sdk_macros::add_compressible_instructions; +use light_sdk_types::CpiSigner; #[cfg(not(feature = "no-entrypoint"))] solana_security_txt::security_txt! { @@ -24,6 +29,9 @@ declare_id!("CPMDWBwJDtYax9qW7AyRuVC19Cc4L4Vcy4n2BHAbHkCW"); #[cfg(not(feature = "devnet"))] declare_id!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); +pub const LIGHT_CPI_SIGNER: CpiSigner = + derive_light_cpi_signer!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); + pub mod admin { use super::{pubkey, Pubkey}; #[cfg(feature = "devnet")] @@ -32,7 +40,7 @@ pub mod admin { pub const ID: Pubkey = pubkey!("GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ"); } -pub mod create_pool_fee_reveiver { +pub mod create_pool_fee_receiver { use super::{pubkey, Pubkey}; #[cfg(feature = "devnet")] pub const ID: Pubkey = pubkey!("G11FKBRaAkHAKuLCgLM6K6NUc9rTjPAznRCjZifrTQe2"); @@ -42,8 +50,15 @@ pub mod create_pool_fee_reveiver { pub const AUTH_SEED: &str = "vault_and_lp_mint_auth_seed"; +/// ZK Compression: Auto-generates compress/decompress instructions for the +/// specified accounts. Derives compress_pool_state, compress_observation_state, +/// decompress_accounts_idempotent, initialize_compression_config, and +/// update_compression_config, as well as all relevant structs. Everything is +/// auto-added to the program IDL for consumption by clients. +#[add_compressible_instructions(PoolState, ObservationState)] #[program] pub mod raydium_cp_swap { + use super::*; // The configuration of AMM protocol, include trade fee and protocol fee @@ -146,13 +161,20 @@ pub mod raydium_cp_swap { /// * `init_amount_1` - the initial amount_1 to deposit /// * `open_time` - the timestamp allowed for swap /// - pub fn initialize( - ctx: Context, + pub fn initialize<'info>( + ctx: Context<'_, '_, '_, 'info, Initialize<'info>>, init_amount_0: u64, init_amount_1: u64, open_time: u64, + compression_params: InitializeCompressionParams, ) -> Result<()> { - instructions::initialize(ctx, init_amount_0, init_amount_1, open_time) + instructions::initialize( + ctx, + init_amount_0, + init_amount_1, + open_time, + compression_params, + ) } /// Deposit lp token to the pool diff --git a/programs/cp-swap/src/states/oracle.rs b/programs/cp-swap/src/states/oracle.rs index ed7173b..a8beb7e 100644 --- a/programs/cp-swap/src/states/oracle.rs +++ b/programs/cp-swap/src/states/oracle.rs @@ -1,18 +1,24 @@ /// Oracle provides price data useful for a wide variety of system designs /// use anchor_lang::prelude::*; + +use light_sdk::{ + compressible::{CompressionInfo, HasCompressionInfo}, + sha::LightHasher, + LightDiscriminator, +}; +use light_sdk_macros::Compressible; + #[cfg(test)] use std::time::{SystemTime, UNIX_EPOCH}; /// Seed to derive account address and signature pub const OBSERVATION_SEED: &str = "observation"; // Number of ObservationState element -pub const OBSERVATION_NUM: usize = 100; +pub const OBSERVATION_NUM: usize = 20; pub const OBSERVATION_UPDATE_DURATION_DEFAULT: u64 = 15; /// The element of observations in ObservationState -#[zero_copy(unsafe)] -#[repr(C, packed)] -#[derive(Default, Debug)] +#[derive(Default, Clone, Copy, AnchorSerialize, AnchorDeserialize, InitSpace, Debug)] pub struct Observation { /// The block timestamp of the observation pub block_timestamp: u64, @@ -21,13 +27,15 @@ pub struct Observation { /// the cumulative of token1 price during the duration time, Q32.32, the remaining 64 bit for overflow pub cumulative_token_1_price_x32: u128, } -impl Observation { - pub const LEN: usize = 8 + 16 + 16; -} - -#[account(zero_copy(unsafe))] -#[repr(C, packed)] -#[cfg_attr(feature = "client", derive(Debug))] +/// Tip: The 'Compressible' macro derives compress/decompress methods for the +/// account. CompressionInfo tracks the last_written_slot. Whenever a +/// compressible account is written to, last_written_slot must be updated. If +/// last_written_slot >= threshold (compression_delay), the account becomes +/// eligible for compression. Eligible accounts can be compressed +/// asynchronously. +#[account] +#[derive(LightHasher, LightDiscriminator, Compressible, InitSpace, Debug)] +#[compress_as(observations = None)] pub struct ObservationState { /// Whether the ObservationState is initialized pub initialized: bool, @@ -35,7 +43,11 @@ pub struct ObservationState { pub observation_index: u16, pub pool_id: Pubkey, /// observation array - pub observations: [Observation; OBSERVATION_NUM], + pub observations: Option<[Observation; OBSERVATION_NUM]>, + /// #[skip] is required. When the account is compressed, compression_info is + /// None. and (Some) when decompressed. + #[skip] + pub compression_info: Option, /// padding for feature update pub padding: [u64; 4], } @@ -47,15 +59,14 @@ impl Default for ObservationState { initialized: false, observation_index: 0, pool_id: Pubkey::default(), - observations: [Observation::default(); OBSERVATION_NUM], + observations: None, + compression_info: None, padding: [0u64; 4], } } } impl ObservationState { - pub const LEN: usize = 8 + 1 + 2 + 32 + (Observation::LEN * OBSERVATION_NUM) + 8 * 4; - // Writes an oracle observation to the account, returning the next observation_index. /// Writable at most once per second. Index represents the most recently written element. /// If the index is at the end of the allowable array length (100 - 1), the next index will turn to 0. @@ -78,14 +89,23 @@ impl ObservationState { token_1_price_x32: u128, ) { let observation_index = self.observation_index; + if !self.initialized { + let observations = self + .observations + .get_or_insert_with(|| [Observation::default(); OBSERVATION_NUM]); // skip the pool init price self.initialized = true; - self.observations[observation_index as usize].block_timestamp = block_timestamp; - self.observations[observation_index as usize].cumulative_token_0_price_x32 = 0; - self.observations[observation_index as usize].cumulative_token_1_price_x32 = 0; + observations[observation_index as usize].block_timestamp = block_timestamp; + observations[observation_index as usize].cumulative_token_0_price_x32 = 0; + observations[observation_index as usize].cumulative_token_1_price_x32 = 0; + + // The account is being initialized, so we must set compression_info. + self.compression_info = Some(CompressionInfo::new_decompressed().unwrap()); } else { - let last_observation = self.observations[observation_index as usize]; + let observations = &mut self.observations.as_mut().unwrap(); + + let last_observation = observations[observation_index as usize]; let delta_time = block_timestamp.saturating_sub(last_observation.block_timestamp); if delta_time < OBSERVATION_UPDATE_DURATION_DEFAULT { return; @@ -97,17 +117,22 @@ impl ObservationState { } else { observation_index + 1 }; - self.observations[next_observation_index as usize].block_timestamp = block_timestamp; + observations[next_observation_index as usize].block_timestamp = block_timestamp; // cumulative_token_price_x32 only occupies the first 64 bits, and the remaining 64 bits are used to store overflow data - self.observations[next_observation_index as usize].cumulative_token_0_price_x32 = + observations[next_observation_index as usize].cumulative_token_0_price_x32 = last_observation .cumulative_token_0_price_x32 .wrapping_add(delta_token_0_price_x32); - self.observations[next_observation_index as usize].cumulative_token_1_price_x32 = + observations[next_observation_index as usize].cumulative_token_1_price_x32 = last_observation .cumulative_token_1_price_x32 .wrapping_add(delta_token_1_price_x32); self.observation_index = next_observation_index; + + // The account was written to, so we must update CompressionInfo. + self.compression_info_mut() + .bump_last_written_slot() + .unwrap(); } } } @@ -125,16 +150,3 @@ pub fn block_timestamp_mock() -> u64 { .unwrap() .as_secs() } - -#[cfg(test)] -pub mod observation_test { - use super::*; - - #[test] - fn observation_state_size_test() { - assert_eq!( - std::mem::size_of::(), - ObservationState::LEN - 8 - ) - } -} diff --git a/programs/cp-swap/src/states/pool.rs b/programs/cp-swap/src/states/pool.rs index c80606c..bacc9dd 100644 --- a/programs/cp-swap/src/states/pool.rs +++ b/programs/cp-swap/src/states/pool.rs @@ -1,5 +1,8 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface::Mint; +use light_sdk::{compressible::CompressionInfo, sha::LightHasher, LightDiscriminator}; + +use light_sdk_macros::Compressible; use std::ops::{BitAnd, BitOr, BitXor}; /// Seed to derive account address and signature pub const POOL_SEED: &str = "pool"; @@ -20,9 +23,15 @@ pub enum PoolStatusBitFlag { Disable, } -#[account(zero_copy(unsafe))] -#[repr(C, packed)] -#[derive(Default, Debug)] +/// Tip: The 'Compressible' macro derives compress/decompress methods for the +/// account. CompressionInfo tracks the last_written_slot. Whenever a +/// compressible account is written to, last_written_slot must be updated. If +/// last_written_slot >= threshold (compression_delay), the account becomes +/// eligible for compression. Eligible accounts can be compressed +/// asynchronously. +#[account] +#[repr(C)] +#[derive(Default, Debug, LightHasher, LightDiscriminator, Compressible, InitSpace)] pub struct PoolState { /// Which config the pool belongs pub amm_config: Pubkey, @@ -36,6 +45,8 @@ pub struct PoolState { /// Pool tokens are issued when A or B tokens are deposited. /// Pool tokens can be withdrawn back to the original A or B token. pub lp_mint: Pubkey, + /// Holds all LP tokens. Compressible. + pub lp_vault: Pubkey, /// Mint information for token A pub token_0_mint: Pubkey, /// Mint information for token B @@ -74,13 +85,15 @@ pub struct PoolState { pub open_time: u64, /// recent epoch pub recent_epoch: u64, + /// #[skip] is required. When the account is compressed, compression_info is + /// None. and (Some) when decompressed. + #[skip] + pub compression_info: Option, /// padding for future updates - pub padding: [u64; 31], + pub padding: [u64; 1], } impl PoolState { - pub const LEN: usize = 8 + 10 * 32 + 1 * 5 + 8 * 7 + 8 * 31; - pub fn initialize( &mut self, auth_bump: u8, @@ -92,7 +105,8 @@ impl PoolState { token_1_vault: Pubkey, token_0_mint: &InterfaceAccount, token_1_mint: &InterfaceAccount, - lp_mint: &InterfaceAccount, + lp_vault: &AccountInfo, + lp_mint: &AccountInfo, observation_key: Pubkey, ) { self.amm_config = amm_config.key(); @@ -100,13 +114,14 @@ impl PoolState { self.token_0_vault = token_0_vault; self.token_1_vault = token_1_vault; self.lp_mint = lp_mint.key(); + self.lp_vault = lp_vault.key(); self.token_0_mint = token_0_mint.key(); self.token_1_mint = token_1_mint.key(); self.token_0_program = *token_0_mint.to_account_info().owner; self.token_1_program = *token_1_mint.to_account_info().owner; self.observation_key = observation_key; self.auth_bump = auth_bump; - self.lp_mint_decimals = lp_mint.decimals; + self.lp_mint_decimals = 9; // LP mint decimals are fixed at 9 self.mint_0_decimals = token_0_mint.decimals; self.mint_1_decimals = token_1_mint.decimals; self.lp_supply = lp_supply; @@ -116,11 +131,11 @@ impl PoolState { self.fund_fees_token_1 = 0; self.open_time = open_time; self.recent_epoch = Clock::get().unwrap().epoch; - self.padding = [0u64; 31]; + self.padding = [0u64; 1]; } pub fn set_status(&mut self, status: u8) { - self.status = status + self.status = status; } pub fn set_status_by_bit(&mut self, bit: PoolStatusBitIndex, flag: PoolStatusBitFlag) { @@ -163,11 +178,6 @@ impl PoolState { pub mod pool_test { use super::*; - #[test] - fn pool_state_size_test() { - assert_eq!(std::mem::size_of::(), PoolState::LEN - 8) - } - mod pool_status_test { use super::*; diff --git a/programs/cp-swap/src/utils/account_load.rs b/programs/cp-swap/src/utils/account_load.rs deleted file mode 100644 index e215750..0000000 --- a/programs/cp-swap/src/utils/account_load.rs +++ /dev/null @@ -1,169 +0,0 @@ -use anchor_lang::{ - error::{Error, ErrorCode}, - solana_program::{account_info::AccountInfo, pubkey::Pubkey}, - Key, Owner, Result, ToAccountInfos, ZeroCopy, -}; -use arrayref::array_ref; -use std::cell::{Ref, RefMut}; -use std::marker::PhantomData; -use std::mem; -use std::ops::DerefMut; - -#[derive(Clone)] -pub struct AccountLoad<'info, T: ZeroCopy + Owner> { - acc_info: AccountInfo<'info>, - phantom: PhantomData<&'info T>, -} - -impl<'info, T: ZeroCopy + Owner> AccountLoad<'info, T> { - fn new(acc_info: AccountInfo<'info>) -> AccountLoad<'info, T> { - Self { - acc_info, - phantom: PhantomData, - } - } - - /// Constructs a new `Loader` from a previously initialized account. - #[inline(never)] - pub fn try_from(acc_info: &AccountInfo<'info>) -> Result> { - if acc_info.owner != &T::owner() { - return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram) - .with_pubkeys((*acc_info.owner, T::owner()))); - } - let data: &[u8] = &acc_info.try_borrow_data()?; - if data.len() < T::DISCRIMINATOR.len() { - return Err(ErrorCode::AccountDiscriminatorNotFound.into()); - } - // Discriminator must match. - let disc_bytes = array_ref![data, 0, 8]; - if disc_bytes != &T::DISCRIMINATOR { - return Err(ErrorCode::AccountDiscriminatorMismatch.into()); - } - - Ok(AccountLoad::new(acc_info.clone())) - } - - /// Constructs a new `Loader` from an uninitialized account. - #[inline(never)] - pub fn try_from_unchecked( - _program_id: &Pubkey, - acc_info: &AccountInfo<'info>, - ) -> Result> { - if acc_info.owner != &T::owner() { - return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram) - .with_pubkeys((*acc_info.owner, T::owner()))); - } - Ok(AccountLoad::new(acc_info.clone())) - } - - /// Returns a `RefMut` to the account data structure for reading or writing. - /// Should only be called once, when the account is being initialized. - pub fn load_init(&self) -> Result> { - // AccountInfo api allows you to borrow mut even if the account isn't - // writable, so add this check for a better dev experience. - if !self.acc_info.is_writable { - return Err(ErrorCode::AccountNotMutable.into()); - } - - let mut data = self.acc_info.try_borrow_mut_data()?; - - // The discriminator should be zero, since we're initializing. - let mut disc_bytes = [0u8; 8]; - disc_bytes.copy_from_slice(&data[..8]); - let discriminator = u64::from_le_bytes(disc_bytes); - if discriminator != 0 { - return Err(ErrorCode::AccountDiscriminatorAlreadySet.into()); - } - - // write discriminator - data[..8].copy_from_slice(&T::DISCRIMINATOR); - - Ok(RefMut::map(data, |data| { - bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::() + 8]) - })) - } - - /// Returns a `RefMut` to the account data structure for reading or writing directly. - /// There is no need to convert AccountInfo to AccountLoad. - /// So it is necessary to check the owner - pub fn load_data_mut<'a>(acc_info: &'a AccountInfo) -> Result> { - if acc_info.owner != &T::owner() { - return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram) - .with_pubkeys((*acc_info.owner, T::owner()))); - } - if !acc_info.is_writable { - return Err(ErrorCode::AccountNotMutable.into()); - } - - let data = acc_info.try_borrow_mut_data()?; - if data.len() < T::DISCRIMINATOR.len() { - return Err(ErrorCode::AccountDiscriminatorNotFound.into()); - } - - let disc_bytes = array_ref![data, 0, 8]; - if disc_bytes != &T::DISCRIMINATOR { - return Err(ErrorCode::AccountDiscriminatorMismatch.into()); - } - - Ok(RefMut::map(data, |data| { - bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::() + 8]) - })) - } - - /// Returns a Ref to the account data structure for reading. - pub fn load(&self) -> Result> { - let data = self.acc_info.try_borrow_data()?; - if data.len() < T::DISCRIMINATOR.len() { - return Err(ErrorCode::AccountDiscriminatorNotFound.into()); - } - - let disc_bytes = array_ref![data, 0, 8]; - if disc_bytes != &T::DISCRIMINATOR { - return Err(ErrorCode::AccountDiscriminatorMismatch.into()); - } - - Ok(Ref::map(data, |data| { - bytemuck::from_bytes(&data[8..mem::size_of::() + 8]) - })) - } - - /// Returns a `RefMut` to the account data structure for reading or writing. - pub fn load_mut(&self) -> Result> { - // AccountInfo api allows you to borrow mut even if the account isn't - // writable, so add this check for a better dev experience. - if !self.acc_info.is_writable { - return Err(ErrorCode::AccountNotMutable.into()); - } - - let data = self.acc_info.try_borrow_mut_data()?; - if data.len() < T::DISCRIMINATOR.len() { - return Err(ErrorCode::AccountDiscriminatorNotFound.into()); - } - - let disc_bytes = array_ref![data, 0, 8]; - if disc_bytes != &T::DISCRIMINATOR { - return Err(ErrorCode::AccountDiscriminatorMismatch.into()); - } - - Ok(RefMut::map(data, |data| { - bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::() + 8]) - })) - } -} - -impl<'info, T: ZeroCopy + Owner> AsRef> for AccountLoad<'info, T> { - fn as_ref(&self) -> &AccountInfo<'info> { - &self.acc_info - } -} -impl<'info, T: ZeroCopy + Owner> ToAccountInfos<'info> for AccountLoad<'info, T> { - fn to_account_infos(&self) -> Vec> { - vec![self.acc_info.clone()] - } -} - -impl<'info, T: ZeroCopy + Owner> Key for AccountLoad<'info, T> { - fn key(&self) -> Pubkey { - *self.acc_info.key - } -} diff --git a/programs/cp-swap/src/utils/compression.rs b/programs/cp-swap/src/utils/compression.rs new file mode 100644 index 0000000..2953868 --- /dev/null +++ b/programs/cp-swap/src/utils/compression.rs @@ -0,0 +1,110 @@ +use crate::instructions::InitializeCompressionParams; +use crate::states::*; +use anchor_lang::prelude::*; +use light_compressed_account::address::derive_address; +use light_sdk::compressible::prepare_accounts_for_compression_on_init; +use light_sdk::cpi::CpiAccountsSmall; +use light_sdk::cpi::CpiInputs; +use light_sdk_types::cpi_context_write::CpiContextWriteAccounts; + +use crate::LIGHT_CPI_SIGNER; + +// The order in which new compressed accounts are passed to the CPI. +pub const POOL_STATE_CREATION_INDEX: u8 = 0; +pub const OBSERVATION_STATE_CREATION_INDEX: u8 = 1; +pub const LP_MINT_CREATION_INDEX: u8 = 2; + +pub fn compress_pool_and_observation_pdas<'a, 'b, 'info>( + cpi_accounts: &CpiAccountsSmall<'b, 'info>, + pool_state: &Account<'info, PoolState>, + observation_state: &Account<'info, ObservationState>, + compression_params: &InitializeCompressionParams, + rent_recipient: &AccountInfo<'info>, + address_space: &[Pubkey], +) -> Result<()> { + // 1. Prepare new address params + let pool_new_address_params = compression_params + .pool_address_tree_info + .into_new_address_params_assigned_packed( + pool_state.key().to_bytes(), + true, + Some(POOL_STATE_CREATION_INDEX), + ); + let observation_new_address_params = compression_params + .observation_address_tree_info + .into_new_address_params_assigned_packed( + observation_state.key().to_bytes(), + true, + Some(OBSERVATION_STATE_CREATION_INDEX), + ); + // To save CU in exchange for ix data, you canpass the addresses via client. + let pool_compressed_address = derive_address( + &pool_state.key().to_bytes(), + &cpi_accounts + .get_tree_address(pool_new_address_params.address_merkle_tree_account_index) + .unwrap() + .key + .to_bytes(), + &crate::ID.to_bytes(), + ); + + let observation_compressed_address = derive_address( + &observation_state.key().to_bytes(), + &cpi_accounts + .get_tree_address(observation_new_address_params.address_merkle_tree_account_index) + .unwrap() + .key + .to_bytes(), + &crate::ID.to_bytes(), + ); + + // 2. Prepare accounts for compression + // prepare_accounts_for_compression_on_init is for direct compression. To + // write to the accounts, as user then has to add a + // decompress_accounts_idempotent instruction to the first transaction. Many + // users can try to decompress the account concurrently. If you instead want + // to start in a "decompressed" state, and only compress later, use + // 'compress_empty_account_on_init'. + let mut all_compressed_infos = Vec::with_capacity(2); + + let pool_state_compressed_info = prepare_accounts_for_compression_on_init::( + &[pool_state], + &[pool_compressed_address], + &[pool_new_address_params], + &[compression_params.output_state_tree_index], + &cpi_accounts, + &address_space, + rent_recipient, + )?; + all_compressed_infos.extend(pool_state_compressed_info); + + let observation_compressed_infos = prepare_accounts_for_compression_on_init::( + &[observation_state], + &[observation_compressed_address], + &[observation_new_address_params], + &[compression_params.output_state_tree_index], + &cpi_accounts, + &address_space, + rent_recipient, + )?; + all_compressed_infos.extend(observation_compressed_infos); + + // 3. Compress. We invoke the cpi_context here to save CU, because we still + // create a cmint later in the instruction. Only then will the state + // transition be fully settled. Notice we're using 'new_first_cpi' here + // instead of 'CompressedCpiContext::last_cpi_create_mint'. + let cpi_inputs = CpiInputs::new_first_cpi( + all_compressed_infos, + vec![pool_new_address_params, observation_new_address_params], + ); + let cpi_context = cpi_accounts.cpi_context().unwrap(); + let cpi_context_accounts = CpiContextWriteAccounts { + fee_payer: cpi_accounts.fee_payer(), + authority: cpi_accounts.authority().unwrap(), + cpi_context, + cpi_signer: LIGHT_CPI_SIGNER, + }; + cpi_inputs.invoke_light_system_program_cpi_context(cpi_context_accounts)?; + + Ok(()) +} \ No newline at end of file diff --git a/programs/cp-swap/src/utils/ctoken.rs b/programs/cp-swap/src/utils/ctoken.rs new file mode 100644 index 0000000..281b9e3 --- /dev/null +++ b/programs/cp-swap/src/utils/ctoken.rs @@ -0,0 +1,264 @@ +use crate::{ + instructions::InitializeCompressionParams, + states::POOL_LP_MINT_SEED, + utils::{create_or_allocate_account, LP_MINT_CREATION_INDEX}, +}; +use anchor_lang::{ + prelude::*, + solana_program::program::{invoke, invoke_signed}, +}; +use light_compressed_token_sdk::{ + instructions::{ + create_compressible_associated_token_account_with_bump as initialize_compressible_associated_token_account_with_bump, + create_compressible_token_account as initialize_compressible_token_account, + create_mint_action_cpi, derive_compressed_mint_from_spl_mint, transfer, transfer_signed, + CreateCompressibleAssociatedTokenAccountInputs, CreateCompressibleTokenAccount, + MintActionInputs, MintActionType, + }, + CompressedProof, +}; +use light_ctoken_types::{ + instructions::mint_action::CompressedMintWithContext, + instructions::mint_action::CpiContext as CompressedCpiContext, COMPRESSIBLE_TOKEN_ACCOUNT_SIZE, +}; +use light_sdk::cpi::CpiAccountsSmall; + +pub fn transfer_ctoken_from_user_to_pool_vault<'a>( + authority: AccountInfo<'a>, + from: AccountInfo<'a>, + to_vault: AccountInfo<'a>, + amount: u64, +) -> Result<()> { + if amount == 0 { + return Ok(()); + } + + transfer(&from, &to_vault, &authority, amount)?; + Ok(()) +} + +pub fn transfer_ctoken_from_pool_vault_to_user<'a>( + authority: AccountInfo<'a>, + from_vault: AccountInfo<'a>, + to: AccountInfo<'a>, + amount: u64, + signer_seeds: &[&[&[u8]]], +) -> Result<()> { + if amount == 0 { + return Ok(()); + } + transfer_signed(&from_vault, &to, &authority, amount, signer_seeds)?; + Ok(()) +} + +pub fn create_compressible_token_account<'a>( + authority: &AccountInfo<'a>, + payer: &AccountInfo<'a>, + token_account: &AccountInfo<'a>, + mint_account: &AccountInfo<'a>, + system_program: &AccountInfo<'a>, + token_program: &AccountInfo<'a>, + signer_seeds: &[&[u8]], + rent_authority: &AccountInfo<'a>, + rent_recipient: &AccountInfo<'a>, + slots_until_compression: u64, +) -> Result<()> { + let space = COMPRESSIBLE_TOKEN_ACCOUNT_SIZE as usize; + + create_or_allocate_account( + token_program.key, + payer.to_account_info(), + system_program.to_account_info(), + token_account.to_account_info(), + signer_seeds, + space, + )?; + + let init_ix = initialize_compressible_token_account(CreateCompressibleTokenAccount { + account_pubkey: *token_account.key, + mint_pubkey: *mint_account.key, + owner_pubkey: *authority.key, + rent_authority: *rent_authority.key, + rent_recipient: *rent_recipient.key, + slots_until_compression, + }) + .map_err(|e| ProgramError::from(e))?; + + invoke( + &init_ix, + &[ + token_account.to_account_info(), + mint_account.to_account_info(), + authority.to_account_info(), + rent_authority.to_account_info(), + rent_recipient.to_account_info(), + ], + )?; + + Ok(()) +} + +pub fn create_compressible_associated_token_account<'a>( + owner: &AccountInfo<'a>, + payer: &AccountInfo<'a>, + associated_token_account: &AccountInfo<'a>, + mint_account: &AccountInfo<'a>, + system_program: &AccountInfo<'a>, + rent_authority: &AccountInfo<'a>, + rent_recipient: &AccountInfo<'a>, + slots_until_compression: u64, + bump: u8, +) -> Result<()> { + let init_ix = initialize_compressible_associated_token_account_with_bump( + CreateCompressibleAssociatedTokenAccountInputs { + payer: *payer.key, + mint: *mint_account.key, + owner: *owner.key, + rent_authority: *rent_authority.key, + rent_recipient: *rent_recipient.key, + slots_until_compression, + }, + *associated_token_account.key, + bump, + ) + .map_err(|e| ProgramError::from(e))?; + + invoke( + &init_ix, + &[ + payer.to_account_info(), + associated_token_account.to_account_info(), + mint_account.to_account_info(), + owner.to_account_info(), + system_program.to_account_info(), + ], + )?; + + Ok(()) +} + +// To reduce CU usage, you can instead also pass the bumps as instruction data. +pub fn get_bumps( + token_0_mint: Pubkey, + token_1_mint: Pubkey, + compressed_token_program: Pubkey, +) -> (u8, u8) { + let compressed_token_0_pool_bump = Pubkey::find_program_address( + &[b"pool".as_ref(), token_0_mint.as_ref()], + &compressed_token_program, + ) + .1; + let compressed_token_1_pool_bump = Pubkey::find_program_address( + &[b"pool".as_ref(), token_1_mint.as_ref()], + &compressed_token_program, + ) + .1; + (compressed_token_0_pool_bump, compressed_token_1_pool_bump) +} + +pub fn create_and_mint_lp<'a, 'b, 'info>( + creator: AccountInfo<'info>, + authority: AccountInfo<'info>, + lp_mint_key: &Pubkey, + lp_vault: AccountInfo<'info>, + creator_lp_token: AccountInfo<'info>, + lp_mint_signer: AccountInfo<'info>, + pool_state_key: &Pubkey, + compressed_token_program_cpi_authority: AccountInfo<'info>, + compressed_token_program: AccountInfo<'info>, + lp_mint_signer_bump: u8, + compression_params: &InitializeCompressionParams, + cpi_accounts: &CpiAccountsSmall<'b, 'info>, + user_lp_amount: u64, + vault_lp_amount: u64, + pool_auth_bump: u8, +) -> Result<()> { + // Get tree accounts + let output_state_queue_idx: u8 = 0; + let address_tree_idx: u8 = 1; + let output_state_queue = + *cpi_accounts.tree_accounts().unwrap()[output_state_queue_idx as usize].key; + let address_tree_pubkey = *cpi_accounts.tree_accounts().unwrap()[address_tree_idx as usize].key; + + let mint_compressed_address = + derive_compressed_mint_from_spl_mint(lp_mint_key, &address_tree_pubkey); + + let compressed_mint_with_context = CompressedMintWithContext::new( + mint_compressed_address, + compression_params.lp_mint_address_tree_info.root_index, + 9, // Our Lp mints always have 9 decimals. + Some(authority.key().into()), + Some(authority.key().into()), + lp_mint_key.into(), + ); + + // The cmint creation is implicit. Here we additionally + // mint to the creator and the pool vault. + let actions = vec![ + MintActionType::MintToDecompressed { + account: creator_lp_token.key(), + amount: user_lp_amount, + }, + MintActionType::MintToDecompressed { + account: lp_vault.key(), + amount: vault_lp_amount, + }, + ]; + + let mint_action_instruction: anchor_lang::solana_program::instruction::Instruction = + create_mint_action_cpi( + MintActionInputs::new_for_create_mint( + compressed_mint_with_context, + actions, + output_state_queue, + address_tree_pubkey, + lp_mint_signer.key(), + Some(compression_params.lp_mint_bump), + authority.key().into(), + creator.key(), + compression_params.proof.0.map(|p| CompressedProof::from(p)), + ), + Some(CompressedCpiContext::last_cpi_create_mint( + address_tree_idx, + output_state_queue_idx, + LP_MINT_CREATION_INDEX, + )), + Some(cpi_accounts.cpi_context().unwrap().key()), + ) + .map_err(|e| ProgramError::from(e))?; + + // Extend the account infos with the accounts needed for the cmint creation. + let mut account_infos = cpi_accounts.to_account_infos(); + account_infos.extend([ + compressed_token_program_cpi_authority, + compressed_token_program, + authority, + lp_mint_signer, + creator, + // accounts used by the additional mint actions: + lp_vault, + creator_lp_token, + ]); + + // Invoke. We batch settle all compression related CPIs here, hence the + // signer_seeds for the PDAs. + invoke_signed( + &mint_action_instruction, + &account_infos, + &[ + // The mint creation is checked before the PDA actions, so its + // signer_seeds come first. + &[ + POOL_LP_MINT_SEED.as_bytes(), + pool_state_key.as_ref(), + &[lp_mint_signer_bump], + ], + // Since we also create 2 compressed PDAs in our instruction cia + // cpi_context, now we need to settle via the pda authority's + // signer_seeds. + &[crate::AUTH_SEED.as_bytes(), &[pool_auth_bump]], + ], + )?; + + Ok(()) +} diff --git a/programs/cp-swap/src/utils/mod.rs b/programs/cp-swap/src/utils/mod.rs index 43cda1c..d7ca8de 100644 --- a/programs/cp-swap/src/utils/mod.rs +++ b/programs/cp-swap/src/utils/mod.rs @@ -1,7 +1,9 @@ -pub mod account_load; +pub mod compression; +pub mod ctoken; pub mod math; pub mod token; -pub use account_load::*; +pub use compression::*; +pub use ctoken::*; pub use math::*; pub use token::*; diff --git a/programs/cp-swap/src/utils/token.rs b/programs/cp-swap/src/utils/token.rs index e40ba75..8828369 100644 --- a/programs/cp-swap/src/utils/token.rs +++ b/programs/cp-swap/src/utils/token.rs @@ -5,6 +5,9 @@ use anchor_spl::{ token_2022, token_interface::{initialize_account3, InitializeAccount3, Mint}, }; +use light_compressed_token_sdk::instructions::transfer2::{ + transfer_ctoken_to_spl_signed, transfer_spl_to_ctoken, +}; use spl_token_2022::{ self, extension::{ @@ -21,105 +24,65 @@ const MINT_WHITELIST: [&'static str; 4] = [ "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", ]; -pub fn transfer_from_user_to_pool_vault<'a>( +pub fn transfer_from_user_to_pool_vault<'a, 'b>( authority: AccountInfo<'a>, from: AccountInfo<'a>, to_vault: AccountInfo<'a>, mint: AccountInfo<'a>, - token_program: AccountInfo<'a>, + spl_token_program: AccountInfo<'a>, + compressed_token_pool_pda: AccountInfo<'a>, + compressed_token_pool_pda_bump: u8, + compressed_token_program_authority: AccountInfo<'a>, amount: u64, - mint_decimals: u8, ) -> Result<()> { if amount == 0 { return Ok(()); } - token_2022::transfer_checked( - CpiContext::new( - token_program.to_account_info(), - token_2022::TransferChecked { - from, - to: to_vault, - authority, - mint, - }, - ), + transfer_spl_to_ctoken( + authority.clone(), + authority, + from, + to_vault, + mint, + spl_token_program, + compressed_token_pool_pda, + compressed_token_pool_pda_bump, + compressed_token_program_authority, amount, - mint_decimals, - ) + )?; + Ok(()) } pub fn transfer_from_pool_vault_to_user<'a>( + payer: AccountInfo<'a>, authority: AccountInfo<'a>, from_vault: AccountInfo<'a>, to: AccountInfo<'a>, mint: AccountInfo<'a>, - token_program: AccountInfo<'a>, + spl_token_program: AccountInfo<'a>, + compressed_token_pool_pda: AccountInfo<'a>, + compressed_token_pool_pda_bump: u8, + compressed_token_program_authority: AccountInfo<'a>, amount: u64, - mint_decimals: u8, signer_seeds: &[&[&[u8]]], ) -> Result<()> { if amount == 0 { return Ok(()); } - token_2022::transfer_checked( - CpiContext::new_with_signer( - token_program.to_account_info(), - token_2022::TransferChecked { - from: from_vault, - to, - authority, - mint, - }, - signer_seeds, - ), - amount, - mint_decimals, - ) -} - -/// Issue a spl_token `MintTo` instruction. -pub fn token_mint_to<'a>( - authority: AccountInfo<'a>, - token_program: AccountInfo<'a>, - mint: AccountInfo<'a>, - destination: AccountInfo<'a>, - amount: u64, - signer_seeds: &[&[&[u8]]], -) -> Result<()> { - token_2022::mint_to( - CpiContext::new_with_signer( - token_program, - token_2022::MintTo { - to: destination, - authority, - mint, - }, - signer_seeds, - ), + transfer_ctoken_to_spl_signed( + payer, + authority, + from_vault, + to, + mint, + spl_token_program, + compressed_token_pool_pda, + compressed_token_pool_pda_bump, + compressed_token_program_authority, amount, - ) -} - -pub fn token_burn<'a>( - authority: AccountInfo<'a>, - token_program: AccountInfo<'a>, - mint: AccountInfo<'a>, - from: AccountInfo<'a>, - amount: u64, - signer_seeds: &[&[&[u8]]], -) -> Result<()> { - token_2022::burn( - CpiContext::new_with_signer( - token_program.to_account_info(), - token_2022::Burn { - from, - authority, - mint, - }, - signer_seeds, - ), - amount, - ) + signer_seeds, + )?; + Ok(()) } /// Calculate the fee for output amount @@ -188,12 +151,7 @@ pub fn is_supported_mint(mint_account: &InterfaceAccount) -> Result let mint = StateWithExtensions::::unpack(&mint_data)?; let extensions = mint.get_extension_types()?; for e in extensions { - if e != ExtensionType::TransferFeeConfig - && e != ExtensionType::MetadataPointer - && e != ExtensionType::TokenMetadata - && e != ExtensionType::InterestBearingConfig - && e != ExtensionType::ScaledUiAmount - { + if e != ExtensionType::TokenMetadata { return Ok(false); } } @@ -248,7 +206,7 @@ pub fn create_or_allocate_account<'a>( payer: AccountInfo<'a>, system_program: AccountInfo<'a>, target_account: AccountInfo<'a>, - siger_seed: &[&[u8]], + signer_seed: &[&[u8]], space: usize, ) -> Result<()> { let rent = Rent::get()?; @@ -262,7 +220,7 @@ pub fn create_or_allocate_account<'a>( }; let cpi_context = CpiContext::new(system_program.clone(), cpi_accounts); system_program::create_account( - cpi_context.with_signer(&[siger_seed]), + cpi_context.with_signer(&[signer_seed]), lamports, u64::try_from(space).unwrap(), program_id, @@ -285,7 +243,7 @@ pub fn create_or_allocate_account<'a>( }; let cpi_context = CpiContext::new(system_program.clone(), cpi_accounts); system_program::allocate( - cpi_context.with_signer(&[siger_seed]), + cpi_context.with_signer(&[signer_seed]), u64::try_from(space).unwrap(), )?; @@ -293,7 +251,7 @@ pub fn create_or_allocate_account<'a>( account_to_assign: target_account.clone(), }; let cpi_context = CpiContext::new(system_program.clone(), cpi_accounts); - system_program::assign(cpi_context.with_signer(&[siger_seed]), program_id)?; + system_program::assign(cpi_context.with_signer(&[signer_seed]), program_id)?; } Ok(()) } diff --git a/scripts/lut.json b/scripts/lut.json new file mode 100644 index 0000000..fadb3b3 --- /dev/null +++ b/scripts/lut.json @@ -0,0 +1 @@ +{"account":{"data":["AQAAAP//////////AAAAAAAAAAAjAQFfKLpxtXVJdt0K8yLckTFEIuQhmYfmVBFu2pUHcB7pAADmyRiwvXzPkVREinq/ao85eCmh6P0Ip/DQs6q4eFL8MganVfghOQVNRCSxWvDEMM8vS3+YeTraElLUjzZmxsvOHuvEjPsyZLvDS/XFpag0/GdQAG8phtlvI1vIh1703UQLvA/Au0fKL3TEES6UqxPPo8Y05dwX6ssDzRojzX54fPuzKHUQXK6FtbREdgftv+FFJ7+0I5EcpAQjv9FSeiZ1CSw27CL1F4MA/bRKqmr/z/Ckbhy8ZBwOPtCdoTue9QgNAckoq0XTZVlaNOh3F/uwAIoZ0i8FLJ2h+YjEfFfeOguzCf2uDjrUg+kHQ7Tbp9KFUZWBkiLHcl2rauSSjP1VCKbpdecSJePoAVrHCv9ueLC92ILkkip+g4YPN4HoZU8IqnLs6kC6LnFYzDAA3P4bI+a9VH85QjlqZUSm8DujjAkVo1cjeU6Ptl0HW2tyaZw43QLllIt1sOWgQY6Al1tEBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKkBXyi6cbV1SXbdCvMi3JExRCLkIZmH5lQRbtqVB3Ae6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt324e51j94YQl285GzN2rYa/E2DuQ0n/r35KNihi/wNAckoq0XTZVlaNOh3F/uwAIoZ0i8FLJ2h+YjEfFfeOguzCf2uDjrUg+kHQ7Tbp9KFUZWBkiLHcl2rauSSjP1VDQHJSTjmAlqoRvR63cIxy1VM6ev50lx9reTflsEae74Lswoa1RVJ0Mu8LffQ6X1uPzdaf1F4vE9YrAOb/3cFlg0ByVALKmF5+LZAuuTourIKXBRnlL+ueKqjmO2NT1YiC7MKL1NY6ztCiuxrOujiAu6LiQSD7ayhhKZ8zgIv+NoNAcl29p0oXdXdmJAZucjHinlDm0UdLZpmjkYlR7pjWAuzCj+l+30neNOGxmwvUYcBH5BcgmYI9bQ1G93CnQlFDQHJjHsR9+0RfSd6DupgTsrnyeMV7FkYPMUi9B72m0ELswpaaVYQ3FdNhY1zYZ6pCnZacHb3QkTqquAA790JMg0ByaKlHaua0II3lex12tecwzKR80ACCNv3pH4Uyo+nC7MKd57DjFifOFFdPZW8pdEs/3900yXEUGr46QcKMK8NAcm2aClU5SxQxOIA5pDWNyFEzGgedDouKX5Q/jSz2wuzCo8pqKAANMsHa1t957TmV6lEy1bPZfPPgZLRjHVsDQHJxMBQw9Ct1uCfVyi+5wxWd0O75gXvV0AhZ3pGjX4LswqjxSORQaRTjRJlkOMKDsJ0yZAyJlqje0FDEap/gg0BydoNu62NBXntAkJwqhoi8SO5svaEsnL1rvZDx6HSC7MKrILMRdfDTRC6TFZYXXbWukd/yxes5+TD3Rr5FDUNAcn7Dl44tSSTIed69Ah/g/iwTX7zFHBaoQ5CON87uguzCs6Ej4Y5TeYX2JLbRYORxgDKe+RqLb3KTQFD6xl9BqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAACMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WQ==","base64"],"executable":false,"lamports":9521280,"owner":"AddressLookupTab1e1111111111111111111111111","rentEpoch":18446744073709551615,"space":1240},"pubkey":"9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ"} \ No newline at end of file diff --git a/scripts/test-with-light.sh b/scripts/test-with-light.sh new file mode 100755 index 0000000..83b936d --- /dev/null +++ b/scripts/test-with-light.sh @@ -0,0 +1,19 @@ +#!/bin/bash + +# Starts solana-test-validator with all ZK Compression programs, prover, photon +# indexer, cp-amm accounts, and a lookup table. Also deploys the +# cp-swap program. +./../light-protocol/cli/test_bin/run test-validator --validator-args "--clone DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8 \ + --clone D4FPEruKEHrG5TenZ2mpDGEfu1iUvTiqBxvpU8HLBvC2 \ + --account 9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ ./scripts/lut.json \ + --url https://api.mainnet-beta.solana.com \ + --upgradeable-program CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C target/deploy/raydium_cp_swap.so ~/.config/solana/id.json" + +PHOTON_PID=$(pgrep -f photon) +PROVER_PID=$(pgrep -f prover) +VALIDATOR_PID=$(pgrep -f solana-test-validator) + +solana airdrop 1000 ~/.config/solana/id.json --url "localhost" + +echo "Running anchor test..." +anchor test --skip-local-validator --skip-deploy \ No newline at end of file diff --git a/tests/deposit.test.ts b/tests/deposit.test.ts index 70ce31a..55ace9d 100644 --- a/tests/deposit.test.ts +++ b/tests/deposit.test.ts @@ -7,9 +7,14 @@ import { deposit, getUserAndPoolVaultAmount, setupDepositTest, + fetchCompressibleAccount, } from "./utils"; import { assert } from "chai"; import { MAX_FEE_BASIS_POINTS, TOKEN_PROGRAM_ID } from "@solana/spl-token"; +import { + createRpc, + getDefaultAddressTreeInfo, +} from "@lightprotocol/stateless.js"; describe("deposit test", () => { anchor.setProvider(anchor.AnchorProvider.env()); @@ -17,6 +22,9 @@ describe("deposit test", () => { const program = anchor.workspace.RaydiumCpSwap as Program; + // Extend connection with zkcompression endpoints + const connection = createRpc(); + const confirmOptions = { skipPreflight: true, }; @@ -25,7 +33,7 @@ describe("deposit test", () => { /// deposit without fee const { poolAddress, poolState } = await setupDepositTest( program, - anchor.getProvider().connection, + connection, owner, { config_index: 0, @@ -38,8 +46,8 @@ describe("deposit test", () => { ); const { - onwerToken0Account: ownerToken0AccountBefore, - onwerToken1Account: ownerToken1AccountBefore, + ownerToken0Account: ownerToken0AccountBefore, + ownerToken1Account: ownerToken1AccountBefore, poolVault0TokenAccount: poolVault0TokenAccountBefore, poolVault1TokenAccount: poolVault1TokenAccountBefore, } = await getUserAndPoolVaultAmount( @@ -66,12 +74,19 @@ describe("deposit test", () => { new BN(20000000000), confirmOptions ); - const newPoolState = await program.account.poolState.fetch(poolAddress); + + const { account: newPoolState } = await fetchCompressibleAccount( + poolAddress, + getDefaultAddressTreeInfo(), + program, + "poolState", + connection + ); assert(newPoolState.lpSupply.eq(liquidity.add(poolState.lpSupply))); const { - onwerToken0Account: ownerToken0AccountAfter, - onwerToken1Account: ownerToken1AccountAfter, + ownerToken0Account: ownerToken0AccountAfter, + ownerToken1Account: ownerToken1AccountAfter, poolVault0TokenAccount: poolVault0TokenAccountAfter, poolVault1TokenAccount: poolVault1TokenAccountAfter, } = await getUserAndPoolVaultAmount( @@ -96,17 +111,17 @@ describe("deposit test", () => { input_token1_amount ); - /// deposit with fee + // TransferFeeConfig extension is not supported. const transferFeeConfig = { - transferFeeBasisPoints: 100, - MaxFee: 50000000000, - }; // %10 + transferFeeBasisPoints: 0, + MaxFee: 0, + }; // %0 // Ensure that the initialization state is the same with depsoit without fee const { poolAddress: poolAddress2, poolState: poolState2 } = await setupDepositTest( program, - anchor.getProvider().connection, + connection, owner, { config_index: 0, @@ -139,8 +154,8 @@ describe("deposit test", () => { } ); const { - onwerToken0Account: onwerToken0AccountBefore2, - onwerToken1Account: onwerToken1AccountBefore2, + ownerToken0Account: ownerToken0AccountBefore2, + ownerToken1Account: ownerToken1AccountBefore2, poolVault0TokenAccount: poolVault0TokenAccountBefore2, poolVault1TokenAccount: poolVault1TokenAccountBefore2, } = await getUserAndPoolVaultAmount( @@ -152,6 +167,7 @@ describe("deposit test", () => { poolState2.token0Vault, poolState2.token1Vault ); + // check vault init state assert.equal( poolVault0TokenAccountBefore2.amount, @@ -175,12 +191,20 @@ describe("deposit test", () => { new BN(200000000000), confirmOptions ); - const newPoolState2 = await program.account.poolState.fetch(poolAddress2); + + const { account: newPoolState2 } = await fetchCompressibleAccount( + poolAddress2, + getDefaultAddressTreeInfo(), + program, + "poolState", + connection + ); + assert(newPoolState2.lpSupply.eq(liquidity.add(poolState2.lpSupply))); const { - onwerToken0Account: onwerToken0AccountAfter2, - onwerToken1Account: onwerToken1AccountAfter2, + ownerToken0Account: ownerToken0AccountAfter2, + ownerToken1Account: ownerToken1AccountAfter2, poolVault0TokenAccount: poolVault0TokenAccountAfter2, poolVault1TokenAccount: poolVault1TokenAccountAfter2, } = await getUserAndPoolVaultAmount( @@ -194,9 +218,9 @@ describe("deposit test", () => { ); const input_token0_amount_with_fee = - onwerToken0AccountBefore2.amount - onwerToken0AccountAfter2.amount; + ownerToken0AccountBefore2.amount - ownerToken0AccountAfter2.amount; const input_token1_amount_with_fee = - onwerToken1AccountBefore2.amount - onwerToken1AccountAfter2.amount; + ownerToken1AccountBefore2.amount - ownerToken1AccountAfter2.amount; assert(input_token0_amount_with_fee >= input_token0_amount); assert(input_token1_amount_with_fee >= input_token1_amount); @@ -239,7 +263,8 @@ describe("deposit test", () => { ); }); - it("deposit test with 100% transferFeeConfig, reache maximum fee limit", async () => { + // t22 transferFeeConfig is not supported. + it.skip("deposit test with 100% transferFeeConfig, reache maximum fee limit", async () => { const transferFeeConfig = { transferFeeBasisPoints: MAX_FEE_BASIS_POINTS, MaxFee: 5000000000, @@ -247,7 +272,7 @@ describe("deposit test", () => { const { poolAddress, poolState } = await setupDepositTest( program, - anchor.getProvider().connection, + connection, owner, { config_index: 0, @@ -260,8 +285,8 @@ describe("deposit test", () => { ); const { - onwerToken0Account: ownerToken0AccountBefore, - onwerToken1Account: ownerToken1AccountBefore, + ownerToken0Account: ownerToken0AccountBefore, + ownerToken1Account: ownerToken1AccountBefore, poolVault0TokenAccount: poolVault0TokenAccountBefore, poolVault1TokenAccount: poolVault1TokenAccountBefore, } = await getUserAndPoolVaultAmount( @@ -292,8 +317,8 @@ describe("deposit test", () => { assert(newPoolState.lpSupply.eq(liquidity.add(poolState.lpSupply))); const { - onwerToken0Account: ownerToken0AccountAfter, - onwerToken1Account: ownerToken1AccountAfter, + ownerToken0Account: ownerToken0AccountAfter, + ownerToken1Account: ownerToken1AccountAfter, poolVault0TokenAccount: poolVault0TokenAccountAfter, poolVault1TokenAccount: poolVault1TokenAccountAfter, } = await getUserAndPoolVaultAmount( diff --git a/tests/initialize.test.ts b/tests/initialize.test.ts index f352600..cde64d7 100644 --- a/tests/initialize.test.ts +++ b/tests/initialize.test.ts @@ -1,11 +1,13 @@ import * as anchor from "@coral-xyz/anchor"; import { Program, BN } from "@coral-xyz/anchor"; import { RaydiumCpSwap } from "../target/types/raydium_cp_swap"; - import { getAccount, TOKEN_PROGRAM_ID } from "@solana/spl-token"; import { setupInitializeTest, initialize, calculateFee } from "./utils"; import { assert } from "chai"; +import { createRpc, featureFlags, VERSION } from "@lightprotocol/stateless.js"; +import { CompressedTokenProgram } from "@lightprotocol/compressed-token"; +featureFlags.version = VERSION.V2; describe("initialize test", () => { anchor.setProvider(anchor.AnchorProvider.env()); const owner = anchor.Wallet.local().payer; @@ -16,12 +18,14 @@ describe("initialize test", () => { const confirmOptions = { skipPreflight: true, }; + // Extend connection with zkcompression endpoints + const connection = createRpc(); it("create pool without fee", async () => { const { configAddress, token0, token0Program, token1, token1Program } = await setupInitializeTest( program, - anchor.getProvider().connection, + connection, owner, { config_index: 0, @@ -48,18 +52,18 @@ describe("initialize test", () => { { initAmount0, initAmount1 } ); let vault0 = await getAccount( - anchor.getProvider().connection, + connection, poolState.token0Vault, "processed", - poolState.token0Program + CompressedTokenProgram.programId ); assert.equal(vault0.amount.toString(), initAmount0.toString()); let vault1 = await getAccount( - anchor.getProvider().connection, + connection, poolState.token1Vault, "processed", - poolState.token1Program + CompressedTokenProgram.programId ); assert.equal(vault1.amount.toString(), initAmount1.toString()); }); @@ -68,7 +72,7 @@ describe("initialize test", () => { const { configAddress, token0, token0Program, token1, token1Program } = await setupInitializeTest( program, - anchor.getProvider().connection, + connection, owner, { config_index: 0, @@ -95,10 +99,10 @@ describe("initialize test", () => { { initAmount0, initAmount1 } ); let vault0 = await getAccount( - anchor.getProvider().connection, + connection, poolState.token0Vault, "processed", - poolState.token0Program + CompressedTokenProgram.programId ); assert.equal(vault0.amount.toString(), initAmount0.toString()); @@ -106,17 +110,18 @@ describe("initialize test", () => { anchor.getProvider().connection, poolState.token1Vault, "processed", - poolState.token1Program + CompressedTokenProgram.programId ); assert.equal(vault1.amount.toString(), initAmount1.toString()); }); - it("create pool with token2022 mint has transfer fee", async () => { + // t22 transferFeeConfig is not supported. + it.skip("create pool with token2022 mint has transfer fee", async () => { const transferFeeConfig = { transferFeeBasisPoints: 100, MaxFee: 50000000 }; // %10 const { configAddress, token0, token0Program, token1, token1Program } = await setupInitializeTest( program, - anchor.getProvider().connection, + connection, owner, { config_index: 0, diff --git a/tests/utils/instruction.ts b/tests/utils/instruction.ts index 39b1cac..e866f08 100644 --- a/tests/utils/instruction.ts +++ b/tests/utils/instruction.ts @@ -1,4 +1,4 @@ -import { Program, BN } from "@coral-xyz/anchor"; +import { Program, BN, IdlTypes } from "@coral-xyz/anchor"; import { RaydiumCpSwap } from "../../target/types/raydium_cp_swap"; import { Connection, @@ -8,11 +8,13 @@ import { Signer, SystemProgram, SYSVAR_RENT_PUBKEY, + ComputeBudgetProgram, } from "@solana/web3.js"; import { TOKEN_PROGRAM_ID, TOKEN_2022_PROGRAM_ID, getAssociatedTokenAddressSync, + ASSOCIATED_TOKEN_PROGRAM_ID, } from "@solana/spl-token"; import { accountExist, @@ -23,14 +25,52 @@ import { getPoolLpMintAddress, getPoolVaultAddress, createTokenMintAndAssociatedTokenAccount, - getOrcleAccountAddress, + getOracleAccountAddress, + fetchCompressibleAccount, + POOL_SEED, + ORACLE_SEED, + getLpVaultAddress, + getPoolLpMintSignerAddress, + getPoolLpMintCompressedAddress, } from "./index"; +import { + createRpc, + bn, + sendAndConfirmTx, + featureFlags, + VERSION, + Rpc, + deriveAddressV2, + initializeCompressionConfig, + selectStateTreeInfo, + getDefaultAddressTreeInfo, + packTreeInfos, + deriveCompressionConfigAddress, + createPackedAccountsSmall, + buildAndSignTx, + PackedStateTreeInfo, + createPackedAccountsSmallWithCpiContext, +} from "@lightprotocol/stateless.js"; + +import { + CompressedTokenProgram, + createTokenPool, + getAssociatedCTokenAddressAndBump, +} from "@lightprotocol/compressed-token"; +import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; -import { ASSOCIATED_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token"; +featureFlags.version = VERSION.V2; +const COMPRESSION_DELAY = 100; +const ADDRESS_SPACE = [ + new PublicKey("EzKE84aVTkCUhDHLELqyJaq1Y7UVVmqxXqZjVHwHY3rK"), +]; + +type CompressedAccountVariant = + IdlTypes["compressedAccountVariant"]; export async function setupInitializeTest( program: Program, - connection: Connection, + connection: Rpc, owner: Signer, config: { config_index: number; @@ -63,6 +103,19 @@ export async function setupInitializeTest( config.create_fee, confirmOptions ); + + const [address, _] = deriveCompressionConfigAddress(program.programId); + if (!(await accountExist(connection, address))) { + await initializeCompressionConfig( + connection, + owner, + program.programId, + program.provider.wallet.payer, + COMPRESSION_DELAY, + program.provider.wallet.payer.publicKey, + ADDRESS_SPACE + ); + } return { configAddress, token0, @@ -109,6 +162,22 @@ export async function setupDepositTest( confirmOptions ); + const [address, _] = deriveCompressionConfigAddress(program.programId); + if (!(await accountExist(connection, address))) { + // Extend connection with zkcompression endpoints + const rpc = createRpc(); + const txId = await initializeCompressionConfig( + rpc, + owner, + program.programId, + program.provider.wallet.payer, + COMPRESSION_DELAY, + program.provider.wallet.payer.publicKey, + ADDRESS_SPACE + ); + console.log("initializeCompressionConfig signature:", txId); + } + while (1) { const [{ token0, token0Program }, { token1, token1Program }] = await createTokenMintAndAssociatedTokenAccount( @@ -180,6 +249,21 @@ export async function setupSwapTest( confirmOptions ); + const [address, _] = deriveCompressionConfigAddress(program.programId); + if (!(await accountExist(connection, address))) { + // Extend connection with zkcompression endpoints + const rpc = createRpc(); + await initializeCompressionConfig( + rpc, + owner, + program.programId, + program.provider.wallet.payer, + COMPRESSION_DELAY, + program.provider.wallet.payer.publicKey, + ADDRESS_SPACE + ); + } + const [{ token0, token0Program }, { token1, token1Program }] = await createTokenMintAndAssociatedTokenAccount( connection, @@ -212,7 +296,11 @@ export async function setupSwapTest( new BN(100000000000), confirmOptions ); - return { configAddress, poolAddress, poolState }; + return { + configAddress: poolState.ammConfig, + poolAddress, + poolState, + }; } export async function createAmmConfig( @@ -249,8 +337,8 @@ export async function createAmmConfig( }) .instruction(); - const tx = await sendTransaction(connection, [ix], [owner], confirmOptions); - console.log("init amm config tx: ", tx); + await sendTransaction(connection, [ix], [owner], confirmOptions); + return address; } @@ -269,17 +357,37 @@ export async function initialize( }, createPoolFee = new PublicKey("DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8") ) { - const [auth] = await getAuthAddress(program.programId); + // Extend connection with zkcompression endpoints + const rpc = createRpc(); + + const addressTreeInfo = getDefaultAddressTreeInfo(); + const stateTreeInfo = selectStateTreeInfo(await rpc.getStateTreeInfos()); + + const [auth, authBump] = await getAuthAddress(program.programId); + const [poolAddress] = await getPoolAddress( configAddress, token0, token1, program.programId ); - const [lpMintAddress] = await getPoolLpMintAddress( + + // 1. mintSigner + const [lpMintSignerAddress] = getPoolLpMintSignerAddress( poolAddress, program.programId ); + // 2. lpMint + const [lpMintAddress, lpMintBump] = await getPoolLpMintAddress( + lpMintSignerAddress + ); + + // 3. cMint + const lpMintCompressedAddress = getPoolLpMintCompressedAddress( + lpMintSignerAddress, + addressTreeInfo + ); + const [vault0] = await getPoolVaultAddress( poolAddress, token0, @@ -290,16 +398,8 @@ export async function initialize( token1, program.programId ); - const [creatorLpTokenAddress] = await PublicKey.findProgramAddress( - [ - creator.publicKey.toBuffer(), - TOKEN_PROGRAM_ID.toBuffer(), - lpMintAddress.toBuffer(), - ], - ASSOCIATED_PROGRAM_ID - ); - const [observationAddress] = await getOrcleAccountAddress( + const [observationAddress] = await getOracleAccountAddress( poolAddress, program.programId ); @@ -316,9 +416,87 @@ export async function initialize( false, token1Program ); - await program.methods - .initialize(initAmount.initAmount0, initAmount.initAmount1, new BN(0)) - .accountsPartial({ + + // 1. Derive compressed addresses + const poolCompressedAddress = deriveAddressV2( + poolAddress.toBytes(), + addressTreeInfo.tree.toBytes(), + program.programId.toBytes() + ); + + const observationCompressedAddress = deriveAddressV2( + observationAddress.toBytes(), + addressTreeInfo.tree.toBytes(), + program.programId.toBytes() + ); + + // Get validity proof + // Must match the ordering used by the program when invoking the cpi. + const proofRpcResult = await rpc.getValidityProofV0( + [], + [ + { + tree: addressTreeInfo.tree, + queue: addressTreeInfo.queue, + address: bn(poolCompressedAddress), + }, + { + tree: addressTreeInfo.tree, + queue: addressTreeInfo.queue, + address: bn(observationCompressedAddress), + }, + { + tree: addressTreeInfo.tree, + queue: addressTreeInfo.queue, + address: bn(lpMintCompressedAddress), + }, + ] + ); + + // Set up compression-related accounts + const remainingAccounts = createPackedAccountsSmallWithCpiContext( + program.programId, + stateTreeInfo.cpiContext + ); + // adds state tree and address tree + const outputStateTreeIndex = remainingAccounts.insertOrGet( + stateTreeInfo.queue + ); + const packedTreeInfos = packTreeInfos(proofRpcResult, remainingAccounts); + + const [creatorLpToken, creatorLpTokenBump] = + getAssociatedCTokenAddressAndBump(creator.publicKey, lpMintAddress); + + // Create compression-related ix data + // 229 Bytes +1 + const compressionParams = { + // poolstate + poolAddressTreeInfo: packedTreeInfos.addressTrees[0], + // observation + observationAddressTreeInfo: packedTreeInfos.addressTrees[1], + // mint + lpMintAddressTreeInfo: packedTreeInfos.addressTrees[2], + lpMintBump, + // shared + proof: { 0: proofRpcResult.compressedProof }, + outputStateTreeIndex, + creatorLpTokenBump, + }; + // Get compression config PDA + const [compressionConfig] = deriveCompressionConfigAddress(program.programId); + + const packedAccountMetas = remainingAccounts.toAccountMetas(); + + const [lpVault] = await getLpVaultAddress(lpMintAddress, program.programId); + + const initializeIx = await program.methods + .initialize( + initAmount.initAmount0, + initAmount.initAmount1, + new BN(0), + compressionParams + ) + .accountsStrict({ creator: creator.publicKey, ammConfig: configAddress, authority: auth, @@ -328,7 +506,8 @@ export async function initialize( lpMint: lpMintAddress, creatorToken0, creatorToken1, - creatorLpToken: creatorLpTokenAddress, + creatorLpToken, + lpVault, token0Vault: vault0, token1Vault: vault1, createPoolFee, @@ -336,14 +515,203 @@ export async function initialize( tokenProgram: TOKEN_PROGRAM_ID, token0Program: token0Program, token1Program: token1Program, + associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, systemProgram: SystemProgram.programId, rent: SYSVAR_RENT_PUBKEY, + compressionConfig, + rentRecipient: creator.publicKey, + lpMintSigner: lpMintSignerAddress, + compressedTokenProgramCpiAuthority: + CompressedTokenProgram.deriveCpiAuthorityPda, + compressedTokenProgram: CompressedTokenProgram.programId, + compressedToken0PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(token0), + compressedToken1PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(token1), }) - .rpc(confirmOptions); - const poolState = await program.account.poolState.fetch(poolAddress); + .remainingAccounts(packedAccountMetas.remainingAccounts) + .instruction(); + + const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ + units: 1_200_000, + }); + const { blockhash } = await program.provider.connection.getLatestBlockhash(); + const { value: lookupTableAccount } = await rpc.getAddressLookupTable( + new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") + ); + + const tx = buildAndSignTx( + [computeBudgetIx, initializeIx], + creator, + blockhash, + [], + [lookupTableAccount] + ); + const txId = await sendAndConfirmTx(rpc, tx, confirmOptions); + console.log("initialize signature:", txId); + + const { account: poolState } = await fetchCompressibleAccount( + poolAddress, + addressTreeInfo, + program, + "poolState", + rpc + ); + + if (!poolState) { + throw new Error("Failed to fetch pool state"); + } + return { poolAddress, poolState }; } +export async function decompressIdempotent( + program: Program, + owner: Signer, + poolAddress: PublicKey, + poolBump: number, + observationAddress: PublicKey, + observationBump: number, + configAddress: PublicKey, + token0: PublicKey, + token1: PublicKey, + rpc: Rpc, + confirmOptions?: ConfirmOptions +): Promise { + const addressTreeInfo = getDefaultAddressTreeInfo(); + + // Fetch pool state + const { account: poolState, merkleContext: poolMerkleContext } = + await fetchCompressibleAccount( + poolAddress, + addressTreeInfo, + program, + "poolState", + rpc + ); + + // Fetch observation state + const { account: observationState, merkleContext: observationMerkleContext } = + await fetchCompressibleAccount( + observationAddress, + addressTreeInfo, + program, + "observationState", + rpc + ); + + if (!poolMerkleContext && !observationMerkleContext) return; + + // Derive compressed addresses + const poolCompressedAddress = deriveAddressV2( + poolAddress.toBytes(), + addressTreeInfo.tree.toBytes(), + program.programId.toBytes() + ); + + const observationCompressedAddress = deriveAddressV2( + observationAddress.toBytes(), + addressTreeInfo.tree.toBytes(), + program.programId.toBytes() + ); + + const proof = await rpc.getValidityProofV0([ + { + hash: poolMerkleContext.hash, + tree: poolMerkleContext.treeInfo.tree, + queue: poolMerkleContext.treeInfo.queue, + }, + { + hash: observationMerkleContext.hash, + tree: observationMerkleContext.treeInfo.tree, + queue: observationMerkleContext.treeInfo.queue, + }, + ]); + + // Prepare remaining accounts + const remainingAccounts = createPackedAccountsSmall(program.programId); + remainingAccounts.addPreAccountsMeta({ + isSigner: false, + isWritable: true, + pubkey: poolAddress, + }); + remainingAccounts.addPreAccountsMeta({ + isSigner: false, + isWritable: true, + pubkey: observationAddress, + }); + const packedTreeInfos = packTreeInfos(proof, remainingAccounts); + + // Prepare compressed accounts data + const compressedAccountsData: { + meta: { + treeInfo: PackedStateTreeInfo; + address: number[]; + outputStateTreeIndex: number; + }; + data: CompressedAccountVariant; + seeds: Buffer[]; + }[] = [ + { + meta: { + treeInfo: packedTreeInfos.stateTrees.packedTreeInfos[0], + address: Array.from(poolCompressedAddress), + outputStateTreeIndex: packedTreeInfos.stateTrees.outputTreeIndex, + }, + data: { poolState: [poolState] }, + seeds: [ + POOL_SEED, + configAddress.toBuffer(), + token0.toBuffer(), + token1.toBuffer(), + ], + }, + { + meta: { + treeInfo: packedTreeInfos.stateTrees.packedTreeInfos[1], + address: Array.from(observationCompressedAddress), + outputStateTreeIndex: packedTreeInfos.stateTrees.outputTreeIndex, + }, + data: { observationState: [observationState] }, + seeds: [ORACLE_SEED, poolAddress.toBuffer()], + }, + ]; + + const decompressIx = await program.methods + .decompressAccountsIdempotent( + { 0: proof.compressedProof }, + compressedAccountsData, + Buffer.from([poolBump, observationBump]), + compressedAccountsData.length + ) + .accountsStrict({ + feePayer: owner.publicKey, + rentPayer: owner.publicKey, + config: deriveCompressionConfigAddress(program.programId)[0], + }) + .remainingAccounts(remainingAccounts.toAccountMetas().remainingAccounts) + .instruction(); + + // Build and send transaction + const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ + units: 1_200_000, + }); + const { blockhash } = await program.provider.connection.getLatestBlockhash(); + const { value: lookupTableAccount } = await rpc.getAddressLookupTable( + new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") + ); + const tx = buildAndSignTx( + [computeBudgetIx, decompressIx], + owner, + blockhash, + [], + [lookupTableAccount] + ); + const decompressTxId = await sendAndConfirmTx(rpc, tx, confirmOptions); + + return decompressTxId; +} + export async function deposit( program: Program, owner: Signer, @@ -357,18 +725,26 @@ export async function deposit( maximum_token_1_amount: BN, confirmOptions?: ConfirmOptions ) { + // Extend connection with zkcompression endpoints + const rpc = createRpc(); const [auth] = await getAuthAddress(program.programId); - const [poolAddress] = await getPoolAddress( + const [poolAddress, poolBump] = await getPoolAddress( configAddress, token0, token1, program.programId ); - const [lpMintAddress] = await getPoolLpMintAddress( + const [mintSigner] = getPoolLpMintSignerAddress( poolAddress, program.programId ); + const [lpMintAddress] = await getPoolLpMintAddress(mintSigner); + const [lpVaultAddress] = await getLpVaultAddress( + lpMintAddress, + program.programId + ); + const [vault0] = await getPoolVaultAddress( poolAddress, token0, @@ -379,47 +755,91 @@ export async function deposit( token1, program.programId ); - const [ownerLpToken] = await PublicKey.findProgramAddress( - [ - owner.publicKey.toBuffer(), - TOKEN_PROGRAM_ID.toBuffer(), - lpMintAddress.toBuffer(), - ], - ASSOCIATED_PROGRAM_ID + const ownerLpToken = getAssociatedTokenAddressSync( + lpMintAddress, + owner.publicKey, + false, + CompressedTokenProgram.programId, + CompressedTokenProgram.programId ); - const onwerToken0 = getAssociatedTokenAddressSync( + const ownerToken0 = getAssociatedTokenAddressSync( token0, owner.publicKey, false, token0Program ); - const onwerToken1 = getAssociatedTokenAddressSync( + const ownerToken1 = getAssociatedTokenAddressSync( token1, owner.publicKey, false, token1Program ); - const tx = await program.methods + // Fetch observation address + const [observationAddress, observationBump] = await getOracleAccountAddress( + poolAddress, + program.programId + ); + + // Decompress accounts + await decompressIdempotent( + program, + owner, + poolAddress, + poolBump, + observationAddress, + observationBump, + configAddress, + token0, + token1, + rpc, + confirmOptions + ); + + const depositIx = await program.methods .deposit(lp_token_amount, maximum_token_0_amount, maximum_token_1_amount) - .accounts({ + .accountsStrict({ owner: owner.publicKey, authority: auth, poolState: poolAddress, ownerLpToken, - token0Account: onwerToken0, - token1Account: onwerToken1, + token0Account: ownerToken0, + token1Account: ownerToken1, token0Vault: vault0, token1Vault: vault1, tokenProgram: TOKEN_PROGRAM_ID, tokenProgram2022: TOKEN_2022_PROGRAM_ID, vault0Mint: token0, vault1Mint: token1, - lpMint: lpMintAddress, + lpVault: lpVaultAddress, + compressedTokenProgram: CompressedTokenProgram.programId, + compressedTokenProgramCpiAuthority: + CompressedTokenProgram.deriveCpiAuthorityPda, + compressedToken0PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(token0), + compressedToken1PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(token1), }) - .rpc(confirmOptions); - return tx; + .instruction(); + + const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ + units: 1_200_000, + }); + const { blockhash } = await program.provider.connection.getLatestBlockhash(); + const { value: lookupTableAccount } = await rpc.getAddressLookupTable( + new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") + ); + const depositTx = buildAndSignTx( + [computeBudgetIx, depositIx], + owner, + blockhash, + [], + [lookupTableAccount] + ); + const depositTxId = await sendAndConfirmTx(rpc, depositTx, confirmOptions); + console.log("deposit signature:", depositTxId); + return depositTxId; } export async function withdraw( @@ -443,10 +863,16 @@ export async function withdraw( program.programId ); - const [lpMintAddress] = await getPoolLpMintAddress( + const [lpMintSignerAddress] = getPoolLpMintSignerAddress( poolAddress, program.programId ); + const [lpMintAddress] = await getPoolLpMintAddress(lpMintSignerAddress); + + const [lpVaultAddress] = await getLpVaultAddress( + lpMintAddress, + program.programId + ); const [vault0] = await getPoolVaultAddress( poolAddress, token0, @@ -457,50 +883,72 @@ export async function withdraw( token1, program.programId ); - const [ownerLpToken] = await PublicKey.findProgramAddress( - [ - owner.publicKey.toBuffer(), - TOKEN_PROGRAM_ID.toBuffer(), - lpMintAddress.toBuffer(), - ], - ASSOCIATED_PROGRAM_ID + const ownerLpToken = getAssociatedTokenAddressSync( + lpMintAddress, + owner.publicKey, + false, + CompressedTokenProgram.programId, + CompressedTokenProgram.programId ); - const onwerToken0 = getAssociatedTokenAddressSync( + const ownerToken0 = getAssociatedTokenAddressSync( token0, owner.publicKey, false, token0Program ); - const onwerToken1 = getAssociatedTokenAddressSync( + const ownerToken1 = getAssociatedTokenAddressSync( token1, owner.publicKey, false, token1Program ); - const tx = await program.methods + const withdrawIx = await program.methods .withdraw(lp_token_amount, minimum_token_0_amount, minimum_token_1_amount) - .accounts({ + .accountsStrict({ owner: owner.publicKey, authority: auth, poolState: poolAddress, ownerLpToken, - token0Account: onwerToken0, - token1Account: onwerToken1, + token0Account: ownerToken0, + token1Account: ownerToken1, token0Vault: vault0, token1Vault: vault1, tokenProgram: TOKEN_PROGRAM_ID, tokenProgram2022: TOKEN_2022_PROGRAM_ID, vault0Mint: token0, vault1Mint: token1, - lpMint: lpMintAddress, + lpVault: lpVaultAddress, + compressedTokenProgram: CompressedTokenProgram.programId, + compressedTokenProgramCpiAuthority: + CompressedTokenProgram.deriveCpiAuthorityPda, + compressedToken0PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(token0), + compressedToken1PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(token1), memoProgram: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"), }) - .rpc(confirmOptions) - .catch(); + .instruction(); - return tx; + const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ + units: 1_200_000, + }); + const rpc = createRpc(); + const { blockhash } = await program.provider.connection.getLatestBlockhash(); + const { value: lookupTableAccount } = await rpc.getAddressLookupTable( + new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") + ); + const withdrawTx = buildAndSignTx( + [computeBudgetIx, withdrawIx], + owner, + blockhash, + [], + [lookupTableAccount] + ); + const withdrawTxId = await sendAndConfirmTx(rpc, withdrawTx, confirmOptions); + console.log("withdraw signature:", withdrawTxId); + return withdrawTxId; } export async function swap_base_input( @@ -546,14 +994,17 @@ export async function swap_base_input( false, outputTokenProgram ); - const [observationAddress] = await getOrcleAccountAddress( + const [observationAddress] = await getOracleAccountAddress( poolAddress, program.programId ); + const observationState = await program.account.observationState.fetch( + observationAddress + ); - const tx = await program.methods + const ix = await program.methods .swapBaseInput(amount_in, minimum_amount_out) - .accounts({ + .accountsStrict({ payer: owner.publicKey, authority: auth, ammConfig: configAddress, @@ -567,9 +1018,22 @@ export async function swap_base_input( inputTokenMint: inputToken, outputTokenMint: outputToken, observationState: observationAddress, + compressedTokenProgram: CompressedTokenProgram.programId, + compressedTokenProgramCpiAuthority: + CompressedTokenProgram.deriveCpiAuthorityPda, + compressedToken0PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(inputToken), + compressedToken1PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(outputToken), }) - .rpc(confirmOptions); - + .instruction(); + const tx = await sendTransaction( + program.provider.connection, + [ix], + [owner], + confirmOptions + ); + console.log("swap signature:", tx); return tx; } @@ -616,14 +1080,14 @@ export async function swap_base_output( false, outputTokenProgram ); - const [observationAddress] = await getOrcleAccountAddress( + const [observationAddress] = await getOracleAccountAddress( poolAddress, program.programId ); const tx = await program.methods .swapBaseOutput(max_amount_in, amount_out_less_fee) - .accounts({ + .accountsStrict({ payer: owner.publicKey, authority: auth, ammConfig: configAddress, @@ -637,8 +1101,17 @@ export async function swap_base_output( inputTokenMint: inputToken, outputTokenMint: outputToken, observationState: observationAddress, + compressedTokenProgram: CompressedTokenProgram.programId, + compressedTokenProgramCpiAuthority: + CompressedTokenProgram.deriveCpiAuthorityPda, + compressedToken0PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(inputToken), + compressedToken1PoolPda: + CompressedTokenProgram.deriveTokenPoolPda(outputToken), }) .rpc(confirmOptions); + console.log("swap signature:", tx); + return tx; } diff --git a/tests/utils/pda.ts b/tests/utils/pda.ts index 094089d..849c495 100644 --- a/tests/utils/pda.ts +++ b/tests/utils/pda.ts @@ -1,5 +1,11 @@ import * as anchor from "@coral-xyz/anchor"; import { PublicKey } from "@solana/web3.js"; +import { TreeInfo } from "@lightprotocol/stateless.js"; +import { + deriveCompressedMintAddress, + findMintAddress, +} from "@lightprotocol/compressed-token"; + export const AMM_CONFIG_SEED = Buffer.from( anchor.utils.bytes.utf8.encode("amm_config") ); @@ -89,9 +95,26 @@ export async function getPoolAddress( ], programId ); + return [address, bump]; } +export function getPoolSignerSeeds( + ammConfig: PublicKey, + tokenMint0: PublicKey, + tokenMint1: PublicKey, + programId: PublicKey +): Buffer[] { + const seeds = [ + POOL_SEED, + ammConfig.toBuffer(), + tokenMint0.toBuffer(), + tokenMint1.toBuffer(), + ]; + const [_, bump] = PublicKey.findProgramAddressSync(seeds, programId); + return Array.from(seeds).concat([Buffer.from([bump])]); +} + export async function getPoolVaultAddress( pool: PublicKey, vaultTokenMint: PublicKey, @@ -103,19 +126,36 @@ export async function getPoolVaultAddress( ); return [address, bump]; } - -export async function getPoolLpMintAddress( - pool: PublicKey, +export async function getLpVaultAddress( + lpMint: PublicKey, programId: PublicKey ): Promise<[PublicKey, number]> { const [address, bump] = await PublicKey.findProgramAddress( + [POOL_VAULT_SEED, lpMint.toBuffer()], + programId + ); + return [address, bump]; +} + +// pda used to derive lp_mint and its compressed address. +export function getPoolLpMintSignerAddress( + pool: PublicKey, + programId: PublicKey +): [PublicKey, number] { + const [address, bump] = PublicKey.findProgramAddressSync( [POOL_LPMINT_SEED, pool.toBuffer()], programId ); return [address, bump]; } -export async function getOrcleAccountAddress( +export async function getPoolLpMintAddress( + mintSignerAddress: PublicKey +): Promise<[PublicKey, number]> { + return findMintAddress(mintSignerAddress); +} + +export async function getOracleAccountAddress( pool: PublicKey, programId: PublicKey ): Promise<[PublicKey, number]> { @@ -123,5 +163,20 @@ export async function getOrcleAccountAddress( [ORACLE_SEED, pool.toBuffer()], programId ); + return [address, bump]; } + +/** + * Derives the compressed mint address from the mint seed and address tree. + * @param mintSeed The mint seed public key. + * @param addressTreePubkey The address tree public key. + * @returns Buffer (32 bytes) compressed mint address. + */ + +export function getPoolLpMintCompressedAddress( + mintSigner: PublicKey, + addressTreeInfo: TreeInfo +): number[] { + return deriveCompressedMintAddress(mintSigner, addressTreeInfo); +} diff --git a/tests/utils/util.ts b/tests/utils/util.ts index a58c233..907e454 100644 --- a/tests/utils/util.ts +++ b/tests/utils/util.ts @@ -24,6 +24,14 @@ import { getAccount, } from "@solana/spl-token"; import { sendTransaction } from "./index"; +import { + COMPRESSED_TOKEN_PROGRAM_ID, + createRpc, +} from "@lightprotocol/stateless.js"; +import { + CompressedTokenProgram, + createTokenPool, +} from "@lightprotocol/compressed-token"; // create a token mint and a token2022 mint with transferFeeConfig export async function createTokenMintAndAssociatedTokenAccount( @@ -57,12 +65,15 @@ export async function createTokenMintAndAssociatedTokenAccount( ); tokenArray.push({ address: token0, program: TOKEN_PROGRAM_ID }); - let token1 = await createMintWithTransferFee( + let token1 = await createMint( connection, - payer, mintAuthority, - Keypair.generate(), - transferFeeConfig + mintAuthority.publicKey, + null, + 9, + undefined, + undefined, + TOKEN_2022_PROGRAM_ID ); tokenArray.push({ address: token1, program: TOKEN_2022_PROGRAM_ID }); @@ -119,12 +130,6 @@ export async function createTokenMintAndAssociatedTokenAccount( { skipPreflight: true }, token0Program ); - - // console.log( - // "ownerToken0Account key: ", - // ownerToken0Account.address.toString() - // ); - const ownerToken1Account = await getOrCreateAssociatedTokenAccount( connection, payer, @@ -135,10 +140,7 @@ export async function createTokenMintAndAssociatedTokenAccount( { skipPreflight: true }, token1Program ); - // console.log( - // "ownerToken1Account key: ", - // ownerToken1Account.address.toString() - // ); + await mintTo( connection, payer, @@ -151,6 +153,24 @@ export async function createTokenMintAndAssociatedTokenAccount( token1Program ); + // SPL mints have to be registered in the compression protocol. + const rpc = createRpc(); + await createTokenPool( + rpc, + payer, + token0, + { skipPreflight: true }, + token0Program + ); + + await createTokenPool( + rpc, + payer, + token1, + { skipPreflight: true }, + token1Program + ); + return [ { token0, token0Program }, { token1, token1Program }, @@ -218,30 +238,30 @@ export async function getUserAndPoolVaultAmount( poolToken0Vault: PublicKey, poolToken1Vault: PublicKey ) { - const onwerToken0AccountAddr = getAssociatedTokenAddressSync( + const ownerToken0AccountAddr = getAssociatedTokenAddressSync( token0Mint, owner, false, token0Program ); - const onwerToken1AccountAddr = getAssociatedTokenAddressSync( + const ownerToken1AccountAddr = getAssociatedTokenAddressSync( token1Mint, owner, false, token1Program ); - const onwerToken0Account = await getAccount( + const ownerToken0Account = await getAccount( anchor.getProvider().connection, - onwerToken0AccountAddr, + ownerToken0AccountAddr, "processed", token0Program ); - const onwerToken1Account = await getAccount( + const ownerToken1Account = await getAccount( anchor.getProvider().connection, - onwerToken1AccountAddr, + ownerToken1AccountAddr, "processed", token1Program ); @@ -250,23 +270,57 @@ export async function getUserAndPoolVaultAmount( anchor.getProvider().connection, poolToken0Vault, "processed", - token0Program + CompressedTokenProgram.programId ); const poolVault1TokenAccount = await getAccount( anchor.getProvider().connection, poolToken1Vault, "processed", - token1Program + CompressedTokenProgram.programId ); + return { - onwerToken0Account, - onwerToken1Account, + ownerToken0Account, + ownerToken1Account, poolVault0TokenAccount, poolVault1TokenAccount, }; } +export async function getUserAndPoolLpAmount( + owner: PublicKey, + lpMint: PublicKey, + lpVault: PublicKey +) { + const userLpTokenAddr = getAssociatedTokenAddressSync( + lpMint, + owner, + undefined, + COMPRESSED_TOKEN_PROGRAM_ID, + COMPRESSED_TOKEN_PROGRAM_ID + ); + + const userLpAccount = await getAccount( + anchor.getProvider().connection, + userLpTokenAddr, + "processed", + COMPRESSED_TOKEN_PROGRAM_ID + ); + + const poolLpVaultAccount = await getAccount( + anchor.getProvider().connection, + lpVault, + "processed", + COMPRESSED_TOKEN_PROGRAM_ID + ); + + return { + userLpAccount, + poolLpVaultAccount, + }; +} + export function isEqual(amount1: bigint, amount2: bigint) { if ( BigInt(amount1) === BigInt(amount2) || diff --git a/tests/utils/web3.ts b/tests/utils/web3.ts index 73b53de..91f4d5c 100644 --- a/tests/utils/web3.ts +++ b/tests/utils/web3.ts @@ -1,4 +1,5 @@ import * as anchor from "@coral-xyz/anchor"; +import { Program, Idl, IdlAccounts } from "@coral-xyz/anchor"; import { Connection, Signer, @@ -6,7 +7,9 @@ import { TransactionInstruction, TransactionSignature, ConfirmOptions, + PublicKey, } from "@solana/web3.js"; +import { Rpc, TreeInfo, MerkleContext } from "@lightprotocol/stateless.js"; export async function accountExist( connection: anchor.web3.Connection, @@ -63,3 +66,37 @@ export async function getBlockTimestamp( let slot = await connection.getSlot(); return await connection.getBlockTime(slot); } + +// Anchor-only +export async function fetchCompressibleAccount< + TIdl extends Idl, + TAccountName extends keyof IdlAccounts +>( + address: PublicKey, + addressTreeInfo: TreeInfo, + anchorProgram: Program, + accountName: TAccountName, + rpc: Rpc +): Promise<{ + account: IdlAccounts[TAccountName]; + merkleContext?: MerkleContext; +} | null> { + // Fetches account info irrespective of whether it's currently compressed or + // decompressed. + const info = await rpc.getCompressibleAccountInfo( + address, + anchorProgram.programId, + addressTreeInfo, + rpc + ); + + if (info) { + const account = anchorProgram.coder.accounts.decode( + accountName as string, + info.accountInfo.data + ) as IdlAccounts[TAccountName]; + return { account, merkleContext: info.merkleContext }; + } + + return null; +} diff --git a/tests/withdraw.test.ts b/tests/withdraw.test.ts index c530d87..c21fd0d 100644 --- a/tests/withdraw.test.ts +++ b/tests/withdraw.test.ts @@ -61,6 +61,7 @@ describe("withdraw test", () => { confirmOptions ); const newPoolState = await program.account.poolState.fetch(poolAddress); + assert(newPoolState.lpSupply.eq(liquidity.divn(2).add(poolState.lpSupply))); }); @@ -80,8 +81,8 @@ describe("withdraw test", () => { ); const liquidity = new BN(10000000000); const { - onwerToken0Account: ownerToken0AccountBefore, - onwerToken1Account: ownerToken1AccountBefore, + ownerToken0Account: ownerToken0AccountBefore, + ownerToken1Account: ownerToken1AccountBefore, poolVault0TokenAccount: poolVault0TokenAccountBefore, poolVault1TokenAccount: poolVault1TokenAccountBefore, } = await getUserAndPoolVaultAmount( @@ -125,8 +126,8 @@ describe("withdraw test", () => { assert(newPoolState.lpSupply.eq(poolState.lpSupply)); const { - onwerToken0Account: ownerToken0AccountAfter, - onwerToken1Account: ownerToken1AccountAfter, + ownerToken0Account: ownerToken0AccountAfter, + ownerToken1Account: ownerToken1AccountAfter, poolVault0TokenAccount: poolVault0TokenAccountAfter, poolVault1TokenAccount: poolVault1TokenAccountAfter, } = await getUserAndPoolVaultAmount( diff --git a/yarn.lock b/yarn.lock index 17fa4be..8256119 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7,18 +7,18 @@ resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.27.6.tgz#ec4070a04d76bae8ddbb10770ba55714a417b7c6" integrity sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q== -"@coral-xyz/anchor-errors@^0.31.0": +"@coral-xyz/anchor-errors@^0.31.1": version "0.31.1" resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.31.1.tgz#d635cbac2533973ae6bfb5d3ba1de89ce5aece2d" integrity sha512-NhNEku4F3zzUSBtrYz84FzYWm48+9OvmT1Hhnwr6GnPQry2dsEqH/ti/7ASjjpoFTWRnPXrjAIT1qM6Isop+LQ== -"@coral-xyz/anchor@0.31.0": - version "0.31.0" - resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.31.0.tgz#76b84541e6fdfbd6c661584cdc418453a6416f12" - integrity sha512-Yb1NwP1s4cWhAw7wL7vOLHSWWw3cD5D9pRCVSeJpdqPaI+w7sfRLScnVJL6ViYMZynB7nAG/5HcUPKUnY0L9rw== +"@coral-xyz/anchor@0.31.1": + version "0.31.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.31.1.tgz#0fdeebf45a3cb2e47e8ebbb815ca98542152962c" + integrity sha512-QUqpoEK+gi2S6nlYc2atgT2r41TT3caWr/cPUEL8n8Md9437trZ68STknq897b82p5mW0XrTBNOzRbmIRJtfsA== dependencies: - "@coral-xyz/anchor-errors" "^0.31.0" - "@coral-xyz/borsh" "^0.31.0" + "@coral-xyz/anchor-errors" "^0.31.1" + "@coral-xyz/borsh" "^0.31.1" "@noble/hashes" "^1.3.1" "@solana/web3.js" "^1.69.0" bn.js "^5.1.2" @@ -31,7 +31,15 @@ superstruct "^0.15.4" toml "^3.0.0" -"@coral-xyz/borsh@^0.31.0": +"@coral-xyz/borsh@^0.29.0": + version "0.29.0" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.29.0.tgz#79f7045df2ef66da8006d47f5399c7190363e71f" + integrity sha512-s7VFVa3a0oqpkuRloWVPdCK7hMbAMY270geZOGfCnaqexrP5dTIpbEHL33req6IYPPJ0hYa71cdvJ1h6V55/oQ== + dependencies: + bn.js "^5.1.2" + buffer-layout "^1.2.0" + +"@coral-xyz/borsh@^0.31.1": version "0.31.1" resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.31.1.tgz#5328e1e0921b75d7f4a62dd3f61885a938bc7241" integrity sha512-9N8AU9F0ubriKfNE3g1WF0/4dtlGXoBN/hd1PvbNBamBNwRgHxH4P+o3Zt7rSEloW1HUs6LfZEchlx9fW7POYw== @@ -39,6 +47,26 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" +"@lightprotocol/compressed-token@file:../light-protocol/js/compressed-token": + version "0.22.0" + dependencies: + "@coral-xyz/borsh" "^0.29.0" + bn.js "^5.2.1" + buffer "6.0.3" + +"@lightprotocol/stateless.js@file:../light-protocol/js/stateless.js": + version "0.22.0" + dependencies: + "@coral-xyz/borsh" "^0.29.0" + "@noble/hashes" "1.5.0" + bn.js "^5.2.1" + bs58 "^6.0.0" + buffer "6.0.3" + buffer-layout "^1.2.2" + camelcase "^8.0.0" + camelcase-keys "^9.1.3" + superstruct "2.0.2" + "@noble/curves@^1.4.2": version "1.9.3" resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.9.3.tgz#822c61359875a4d3bfdacaa724ceca6c5e6708c3" @@ -46,7 +74,12 @@ dependencies: "@noble/hashes" "1.8.0" -"@noble/hashes@1.8.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0": +"@noble/hashes@1.5.0": + version "1.5.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.5.0.tgz#abadc5ca20332db2b1b2aa3e496e9af1213570b0" + integrity sha512-1j6kQFb7QRru7eKN3ZDvRcP13rugwdxZqCjbiAVZfIJwgj2A65UmT4TgARXGlXgnRkORLTDTrO19ZErt7+QXgA== + +"@noble/hashes@1.8.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0", "@noble/hashes@^1.8.0": version "1.8.0" resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.8.0.tgz#cee43d801fcef9644b11b8194857695acd5f815a" integrity sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A== @@ -331,6 +364,11 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" +base-x@^5.0.0: + version "5.0.1" + resolved "https://registry.yarnpkg.com/base-x/-/base-x-5.0.1.tgz#16bf35254be1df8aca15e36b7c1dda74b2aa6b03" + integrity sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg== + base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" @@ -401,6 +439,13 @@ bs58@^4.0.0, bs58@^4.0.1: dependencies: base-x "^3.0.2" +bs58@^6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/bs58/-/bs58-6.0.0.tgz#a2cda0130558535dd281a2f8697df79caaf425d8" + integrity sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw== + dependencies: + base-x "^5.0.0" + buffer-from@^1.0.0, buffer-from@^1.1.0: version "1.1.2" resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" @@ -426,11 +471,26 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "^4.3.0" +camelcase-keys@^9.1.3: + version "9.1.3" + resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-9.1.3.tgz#6367b2f9ec5724af541f58f0dcfee9b200022e5c" + integrity sha512-Rircqi9ch8AnZscQcsA1C47NFdaO3wukpmIRzYcDOrmvgt78hM/sj5pZhZNec2NM12uk5vTwRHZ4anGcrC4ZTg== + dependencies: + camelcase "^8.0.0" + map-obj "5.0.0" + quick-lru "^6.1.1" + type-fest "^4.3.2" + camelcase@^6.0.0, camelcase@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== +camelcase@^8.0.0: + version "8.0.0" + resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-8.0.0.tgz#c0d36d418753fb6ad9c5e0437579745c1c14a534" + integrity sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA== + chai@^4.3.4: version "4.5.0" resolved "https://registry.yarnpkg.com/chai/-/chai-4.5.0.tgz#707e49923afdd9b13a8b0b47d33d732d13812fd8" @@ -825,6 +885,11 @@ make-error@^1.1.1: resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== +map-obj@5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-5.0.0.tgz#126c98596b63927d7360f287cccc67177aa1938b" + integrity sha512-2L3MIgJynYrZ3TYMriLDLWocz15okFakV6J12HXvMXDHui2x/zgChzg1u9mFFGbbGWE+GsLpQByt4POb9Or+uA== + minimatch@4.2.1: version "4.2.1" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" @@ -964,6 +1029,11 @@ prettier@^2.6.2: resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.8.8.tgz#e8c5d7e98a4305ffe3de2e1fc4aca1a71c28b1da" integrity sha512-tdN8qQGvNjw4CHbY+XXk0JgCXn9QiF21a55rBe5LJAU+kDyC4WQn4+awm2Xfk2lQMk5fKup9XgzTZtGkjBdP9Q== +quick-lru@^6.1.1: + version "6.1.2" + resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-6.1.2.tgz#e9a90524108629be35287d0b864e7ad6ceb3659e" + integrity sha512-AAFUA5O1d83pIHEhJwWCq/RQcRukCkn/NSm2QsTEMle5f2hP0ChI2+3Xb051PZCkLryI/Ir1MVKviT2FIloaTQ== + randombytes@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -1062,16 +1132,16 @@ strip-json-comments@3.1.1: resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== +superstruct@2.0.2, superstruct@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" + integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== + 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== -superstruct@^2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" - integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== - supports-color@8.1.1: version "8.1.1" resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" @@ -1151,6 +1221,11 @@ type-detect@^4.0.0, type-detect@^4.1.0: resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.1.0.tgz#deb2453e8f08dcae7ae98c626b13dddb0155906c" integrity sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw== +type-fest@^4.3.2: + version "4.41.0" + resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-4.41.0.tgz#6ae1c8e5731273c2bf1f58ad39cbae2c91a46c58" + integrity sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA== + typescript@^4.3.5: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" From cc0f77243632b3927cc2316276c9fa29aed3e2a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Mon, 25 Aug 2025 21:22:07 +0100 Subject: [PATCH 02/15] update readme.md (#9) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index af96c36..d90d00c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # raydium-cp-swap -A constant product AMM program reference implementation based to Raydiun's CP AMM. +A constant product AMM program reference implementation based on Raydiun's CP AMM. We added: From 53cb9ea032a1b871430ee5aac339520a149973a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Mon, 25 Aug 2025 21:51:51 +0100 Subject: [PATCH 03/15] update readme.md (#10) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d90d00c..56934a4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # raydium-cp-swap -A constant product AMM program reference implementation based on Raydiun's CP AMM. +An AMM reference implementation based on Raydium's CP AMM. We added: From 9a5ed2aa705bc8b52e6ad15d5e4b64d39189347f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Tue, 26 Aug 2025 01:47:07 +0100 Subject: [PATCH 04/15] chore: update readme.md (#11) * update readme.md * update readme.md --- README.md | 15 ++++++++++++--- package.json | 4 ++-- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 56934a4..8adebce 100644 --- a/README.md +++ b/README.md @@ -35,17 +35,26 @@ Original readme: # Installing using Anchor version manager (avm) cargo install --git https://github.com/coral-xyz/anchor avm --locked --force # Install anchor - avm install 0.31.0 + avm install 0.31.1 ``` ## Quickstart -Clone the repository and test the program. +1. install the latest compression dependencies + +```shell +npm i -g @lightprotocol/zk-compression-cli@alpha --force + +cargo install --git https://github.com/lightprotocol/photon.git --rev 6ba6813 --locked --force +``` + +2. Clone the repository and test the program. ```shell git clone https://github.com/raydium-io/raydium-cp-swap -cd raydium-cp-swap && yarn && anchor test + +cd raydium-cp-swap && yarn && yarn test ``` ## License diff --git a/package.json b/package.json index 7f9e776..1c11a02 100644 --- a/package.json +++ b/package.json @@ -6,8 +6,8 @@ }, "dependencies": { "@coral-xyz/anchor": "0.31.1", - "@lightprotocol/compressed-token": "file:../light-protocol/js/compressed-token", - "@lightprotocol/stateless.js": "file:../light-protocol/js/stateless.js", + "@lightprotocol/compressed-token": "0.22.1-alpha.0", + "@lightprotocol/stateless.js": "0.22.1-alpha.0", "@noble/hashes": "^1.8.0", "@solana/spl-token": "^0.4.8", "@solana/web3.js": "^1.95.3" From cccb427a85b9e72e9753725e27b186bacf6e93be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Tue, 26 Aug 2025 04:00:08 +0100 Subject: [PATCH 05/15] update test-with-light.sh (#12) --- scripts/test-with-light.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/scripts/test-with-light.sh b/scripts/test-with-light.sh index 83b936d..f23beee 100755 --- a/scripts/test-with-light.sh +++ b/scripts/test-with-light.sh @@ -3,7 +3,7 @@ # Starts solana-test-validator with all ZK Compression programs, prover, photon # indexer, cp-amm accounts, and a lookup table. Also deploys the # cp-swap program. -./../light-protocol/cli/test_bin/run test-validator --validator-args "--clone DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8 \ +light test-validator --validator-args "--clone DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8 \ --clone D4FPEruKEHrG5TenZ2mpDGEfu1iUvTiqBxvpU8HLBvC2 \ --account 9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ ./scripts/lut.json \ --url https://api.mainnet-beta.solana.com \ From 14d97764fdff1f0baec4a979ffa7e7e397399d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Tue, 26 Aug 2025 04:03:20 +0100 Subject: [PATCH 06/15] update readme.md (#13) --- README.md | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 8adebce..082caec 100644 --- a/README.md +++ b/README.md @@ -48,13 +48,19 @@ npm i -g @lightprotocol/zk-compression-cli@alpha --force cargo install --git https://github.com/lightprotocol/photon.git --rev 6ba6813 --locked --force ``` -2. Clone the repository and test the program. +2. Clone the repository and install node dependencies ```shell git clone https://github.com/raydium-io/raydium-cp-swap -cd raydium-cp-swap && yarn && yarn test +cd raydium-cp-swap && yarn +``` + +3. Run the tests + +```shell +yarn test ``` ## License From 320557b3a958356e36ddb05fc4588bc9c6237b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Tue, 26 Aug 2025 13:51:15 +0100 Subject: [PATCH 07/15] update readme.me (#14) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 082caec..f4a55e9 100644 --- a/README.md +++ b/README.md @@ -52,7 +52,7 @@ cargo install --git https://github.com/lightprotocol/photon.git --rev 6ba6813 -- ```shell -git clone https://github.com/raydium-io/raydium-cp-swap +git clone https://github.com/Lightprotocol/cp-swap-reference cd raydium-cp-swap && yarn ``` From 2be17e4e7a76845072250a5a612b492bbcaabefa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Tue, 26 Aug 2025 17:18:55 +0100 Subject: [PATCH 08/15] update yarn.lock (#15) --- yarn.lock | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/yarn.lock b/yarn.lock index 8256119..f5ed182 100644 --- a/yarn.lock +++ b/yarn.lock @@ -47,15 +47,19 @@ bn.js "^5.1.2" buffer-layout "^1.2.0" -"@lightprotocol/compressed-token@file:../light-protocol/js/compressed-token": - version "0.22.0" +"@lightprotocol/compressed-token@0.22.1-alpha.0": + version "0.22.1-alpha.0" + resolved "https://registry.yarnpkg.com/@lightprotocol/compressed-token/-/compressed-token-0.22.1-alpha.0.tgz#3ce080bf07f916bbee05644a9e380374a564fc81" + integrity sha512-MNJ4hcWelFqtKiqyUbSdod3qE/TDyiWqCp3vgkTxK65t4HQOmdMmKmB97DXN4vWKdA3N045SIt1WtYIoZWMbnQ== dependencies: "@coral-xyz/borsh" "^0.29.0" bn.js "^5.2.1" buffer "6.0.3" -"@lightprotocol/stateless.js@file:../light-protocol/js/stateless.js": - version "0.22.0" +"@lightprotocol/stateless.js@0.22.1-alpha.0": + version "0.22.1-alpha.0" + resolved "https://registry.yarnpkg.com/@lightprotocol/stateless.js/-/stateless.js-0.22.1-alpha.0.tgz#a603723e0bdd0ee3189e084a0ca9cc220b1245d6" + integrity sha512-w8Jy+wv2T8vdkvjwFT7bObsHiNOsOeCxR9fGYNBBSojp1jBQPOWG9no7/Kdhf24TV61tLhFXWuFKG0ipxpevag== dependencies: "@coral-xyz/borsh" "^0.29.0" "@noble/hashes" "1.5.0" From 6561537354e1aea49284d29215e7bd3876de6a4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= <42959314+SwenSchaeferjohann@users.noreply.github.com> Date: Tue, 26 Aug 2025 17:39:46 +0100 Subject: [PATCH 09/15] cleanup (#16) --- client/src/instructions/utils.rs | 1 - .../src/instructions/admin/collect_fund_fee.rs | 1 + programs/cp-swap/src/instructions/deposit.rs | 3 +-- programs/cp-swap/src/instructions/withdraw.rs | 1 - programs/cp-swap/src/states/oracle.rs | 4 ++-- programs/cp-swap/src/states/pool.rs | 4 ++-- programs/cp-swap/src/utils/compression.rs | 15 ++++----------- 7 files changed, 10 insertions(+), 19 deletions(-) diff --git a/client/src/instructions/utils.rs b/client/src/instructions/utils.rs index ce29050..ff3f57a 100644 --- a/client/src/instructions/utils.rs +++ b/client/src/instructions/utils.rs @@ -27,7 +27,6 @@ pub fn unpack_mint(token_data: &[u8]) -> Result> Ok(mint) } -#[allow(dead_code)] #[derive(Debug)] pub struct TransferFeeInfo { pub mint: Pubkey, diff --git a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs index 7da730c..9442c6c 100644 --- a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs @@ -66,6 +66,7 @@ pub struct CollectFundFee<'info> { /// The SPL program to perform token transfers pub token_program: Program<'info, Token>, + /// The SPL program 2022 to perform token transfers pub token_program_2022: Program<'info, Token2022>, diff --git a/programs/cp-swap/src/instructions/deposit.rs b/programs/cp-swap/src/instructions/deposit.rs index 1f90cf5..adbfb76 100644 --- a/programs/cp-swap/src/instructions/deposit.rs +++ b/programs/cp-swap/src/instructions/deposit.rs @@ -28,7 +28,7 @@ pub struct Deposit<'info> { pub pool_state: Account<'info, PoolState>, /// Owner lp token account - #[account(mut, token::authority = owner)] + #[account(mut, token::authority = owner)] pub owner_lp_token: Box>, /// The payer's token account for token_0 @@ -223,7 +223,6 @@ pub fn deposit( lp_token_amount, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; - pool_state.recent_epoch = Clock::get()?.epoch; // The account was written to, so we must update CompressionInfo. diff --git a/programs/cp-swap/src/instructions/withdraw.rs b/programs/cp-swap/src/instructions/withdraw.rs index 60b341f..28c77bb 100644 --- a/programs/cp-swap/src/instructions/withdraw.rs +++ b/programs/cp-swap/src/instructions/withdraw.rs @@ -251,7 +251,6 @@ pub fn withdraw( token_1_amount, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], )?; - pool_state.recent_epoch = Clock::get()?.epoch; // The account was written to, so we must update CompressionInfo. diff --git a/programs/cp-swap/src/states/oracle.rs b/programs/cp-swap/src/states/oracle.rs index a8beb7e..b2754db 100644 --- a/programs/cp-swap/src/states/oracle.rs +++ b/programs/cp-swap/src/states/oracle.rs @@ -44,8 +44,8 @@ pub struct ObservationState { pub pool_id: Pubkey, /// observation array pub observations: Option<[Observation; OBSERVATION_NUM]>, - /// #[skip] is required. When the account is compressed, compression_info is - /// None. and (Some) when decompressed. + /// #[skip] is required. Is Some when the account is decompressed and None + /// when compressed. #[skip] pub compression_info: Option, /// padding for feature update diff --git a/programs/cp-swap/src/states/pool.rs b/programs/cp-swap/src/states/pool.rs index bacc9dd..52909e2 100644 --- a/programs/cp-swap/src/states/pool.rs +++ b/programs/cp-swap/src/states/pool.rs @@ -85,8 +85,8 @@ pub struct PoolState { pub open_time: u64, /// recent epoch pub recent_epoch: u64, - /// #[skip] is required. When the account is compressed, compression_info is - /// None. and (Some) when decompressed. + /// #[skip] is required. Is Some when the account is decompressed and None + /// when compressed. #[skip] pub compression_info: Option, /// padding for future updates diff --git a/programs/cp-swap/src/utils/compression.rs b/programs/cp-swap/src/utils/compression.rs index 2953868..fe15078 100644 --- a/programs/cp-swap/src/utils/compression.rs +++ b/programs/cp-swap/src/utils/compression.rs @@ -37,7 +37,7 @@ pub fn compress_pool_and_observation_pdas<'a, 'b, 'info>( true, Some(OBSERVATION_STATE_CREATION_INDEX), ); - // To save CU in exchange for ix data, you canpass the addresses via client. + // To save CU in exchange for ix data, you can also pass the addresses via client. let pool_compressed_address = derive_address( &pool_state.key().to_bytes(), &cpi_accounts @@ -47,7 +47,6 @@ pub fn compress_pool_and_observation_pdas<'a, 'b, 'info>( .to_bytes(), &crate::ID.to_bytes(), ); - let observation_compressed_address = derive_address( &observation_state.key().to_bytes(), &cpi_accounts @@ -58,13 +57,7 @@ pub fn compress_pool_and_observation_pdas<'a, 'b, 'info>( &crate::ID.to_bytes(), ); - // 2. Prepare accounts for compression - // prepare_accounts_for_compression_on_init is for direct compression. To - // write to the accounts, as user then has to add a - // decompress_accounts_idempotent instruction to the first transaction. Many - // users can try to decompress the account concurrently. If you instead want - // to start in a "decompressed" state, and only compress later, use - // 'compress_empty_account_on_init'. + // 2. Prepare the PDA accounts for direct compression_on_init. let mut all_compressed_infos = Vec::with_capacity(2); let pool_state_compressed_info = prepare_accounts_for_compression_on_init::( @@ -90,7 +83,7 @@ pub fn compress_pool_and_observation_pdas<'a, 'b, 'info>( all_compressed_infos.extend(observation_compressed_infos); // 3. Compress. We invoke the cpi_context here to save CU, because we still - // create a cmint later in the instruction. Only then will the state + // create a cMint later in the instruction. Only then will the state // transition be fully settled. Notice we're using 'new_first_cpi' here // instead of 'CompressedCpiContext::last_cpi_create_mint'. let cpi_inputs = CpiInputs::new_first_cpi( @@ -107,4 +100,4 @@ pub fn compress_pool_and_observation_pdas<'a, 'b, 'info>( cpi_inputs.invoke_light_system_program_cpi_context(cpi_context_accounts)?; Ok(()) -} \ No newline at end of file +} From 2377be9c0417d8012bdf86e2731b77b6627bc343 Mon Sep 17 00:00:00 2001 From: ananas-block <58553958+ananas-block@users.noreply.github.com> Date: Mon, 19 Jan 2026 09:33:19 +0000 Subject: [PATCH 10/15] chore: update sdk (#19) * wip * wip - resolve build * wip * bump sdk * cleanup * cleanup --------- Co-authored-by: Swenschaeferjohann --- .gitignore | 1 + Cargo.lock | 4100 +++++++---------- Cargo.toml | 5 +- SECURITY.md | 82 - client/Cargo.toml | 50 - client/src/instructions/amm_instructions.rs | 494 -- .../instructions/compression_instructions.rs | 235 - .../instructions/events_instructions_parse.rs | 507 -- client/src/instructions/mod.rs | 6 - client/src/instructions/rpc.rs | 85 - client/src/instructions/token_instructions.rs | 310 -- client/src/instructions/utils.rs | 136 - client/src/main.rs | 928 ---- client_config.ini | 9 - programs/cp-swap/Cargo.toml | 44 +- programs/cp-swap/src/error.rs | 2 + .../instructions/admin/collect_fund_fee.rs | 39 +- .../admin/collect_protocol_fee.rs | 39 +- programs/cp-swap/src/instructions/deposit.rs | 91 +- .../cp-swap/src/instructions/initialize.rs | 434 +- .../src/instructions/swap_base_input.rs | 47 +- .../src/instructions/swap_base_output.rs | 28 +- programs/cp-swap/src/instructions/withdraw.rs | 84 +- programs/cp-swap/src/lib.rs | 57 +- programs/cp-swap/src/states/oracle.rs | 104 +- programs/cp-swap/src/states/pool.rs | 71 +- programs/cp-swap/src/utils/compression.rs | 103 - programs/cp-swap/src/utils/ctoken.rs | 264 -- programs/cp-swap/src/utils/mod.rs | 4 - programs/cp-swap/src/utils/token.rs | 118 +- programs/cp-swap/tests/functional_test.rs | 217 + programs/cp-swap/tests/helpers.rs | 754 +++ scripts/lut.json | 1 - scripts/test-with-light.sh | 19 - tests/deposit.test.ts | 362 -- tests/initialize.test.ts | 188 - tests/swap.test.ts | 200 - tests/utils/fee.ts | 46 - tests/utils/index.ts | 5 - tests/utils/instruction.ts | 1117 ----- tests/utils/pda.ts | 182 - tests/utils/util.ts | 333 -- tests/utils/web3.ts | 102 - tests/withdraw.test.ts | 162 - 44 files changed, 2972 insertions(+), 9193 deletions(-) delete mode 100644 SECURITY.md delete mode 100644 client/Cargo.toml delete mode 100644 client/src/instructions/amm_instructions.rs delete mode 100644 client/src/instructions/compression_instructions.rs delete mode 100644 client/src/instructions/events_instructions_parse.rs delete mode 100644 client/src/instructions/mod.rs delete mode 100644 client/src/instructions/rpc.rs delete mode 100644 client/src/instructions/token_instructions.rs delete mode 100644 client/src/instructions/utils.rs delete mode 100644 client/src/main.rs delete mode 100644 client_config.ini delete mode 100644 programs/cp-swap/src/utils/compression.rs delete mode 100644 programs/cp-swap/src/utils/ctoken.rs create mode 100644 programs/cp-swap/tests/functional_test.rs create mode 100644 programs/cp-swap/tests/helpers.rs delete mode 100644 scripts/lut.json delete mode 100755 scripts/test-with-light.sh delete mode 100644 tests/deposit.test.ts delete mode 100644 tests/initialize.test.ts delete mode 100644 tests/swap.test.ts delete mode 100644 tests/utils/fee.ts delete mode 100644 tests/utils/index.ts delete mode 100644 tests/utils/instruction.ts delete mode 100644 tests/utils/pda.ts delete mode 100644 tests/utils/util.ts delete mode 100644 tests/utils/web3.ts delete mode 100644 tests/withdraw.test.ts diff --git a/.gitignore b/.gitignore index 7d49943..9d2ca43 100644 --- a/.gitignore +++ b/.gitignore @@ -9,3 +9,4 @@ test-ledger .yarn Makefile +expand.rs diff --git a/Cargo.lock b/Cargo.lock index bc75f05..dc7cad7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,39 +12,6 @@ dependencies = [ "regex", ] -[[package]] -name = "account-compression" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "aligned-sized", - "anchor-lang", - "bytemuck", - "light-account-checks", - "light-batched-merkle-tree", - "light-bounded-vec", - "light-compressed-account", - "light-concurrent-merkle-tree", - "light-hash-set", - "light-hasher", - "light-indexed-merkle-tree", - "light-merkle-tree-metadata", - "light-zero-copy", - "num-bigint 0.4.6", - "solana-sdk", - "solana-security-txt", - "zerocopy", -] - -[[package]] -name = "addr2line" -version = "0.24.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfbe277e56a376000877090da837660b4427aad530e3028d44e0bffe4f89a1c1" -dependencies = [ - "gimli", -] - [[package]] name = "adler2" version = "2.0.1" @@ -87,6 +54,53 @@ dependencies = [ "zeroize", ] +[[package]] +name = "agave-feature-set" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a2c365c0245cbb8959de725fc2b44c754b673fdf34c9a7f9d4a25c35a7bf1" +dependencies = [ + "ahash", + "solana-epoch-schedule", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", + "solana-svm-feature-set", +] + +[[package]] +name = "agave-precompiles" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60d73657792af7f2464e9181d13c3979e94bb09841d9ffa014eef4ef0492b77" +dependencies = [ + "agave-feature-set", + "bincode", + "digest 0.10.7", + "ed25519-dalek", + "libsecp256k1", + "openssl", + "sha3", + "solana-ed25519-program", + "solana-message", + "solana-precompile-error", + "solana-pubkey", + "solana-sdk-ids", + "solana-secp256k1-program", + "solana-secp256r1-program", +] + +[[package]] +name = "agave-reserved-account-keys" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8289c8a8a2ef5aa10ce49a070f360f4e035ee3410b8d8f3580fb39d8cf042581" +dependencies = [ + "agave-feature-set", + "solana-pubkey", + "solana-sdk-ids", +] + [[package]] name = "ahash" version = "0.8.12" @@ -94,7 +108,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -102,9 +116,9 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.3" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] @@ -112,11 +126,11 @@ dependencies = [ [[package]] name = "aligned-sized" version = "1.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -216,46 +230,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "anchor-client" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49b3e91b12501d37c8f07de9da8c7d22067998a7760a515231187afb47ded225" -dependencies = [ - "anchor-lang", - "anyhow", - "futures", - "regex", - "serde", - "solana-account-decoder", - "solana-client", - "solana-sdk", - "thiserror 1.0.69", - "tokio", - "url", -] - -[[package]] -name = "anchor-compressed-token" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "account-compression", - "anchor-lang", - "anchor-spl 0.31.1 (registry+https://github.com/rust-lang/crates.io-index)", - "light-compressed-account", - "light-ctoken-types", - "light-hasher", - "light-heap", - "light-system-program-anchor", - "light-zero-copy", - "solana-sdk", - "solana-security-txt", - "spl-token", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "zerocopy", -] - [[package]] name = "anchor-derive-accounts" version = "0.31.1" @@ -343,32 +317,16 @@ dependencies = [ [[package]] name = "anchor-spl" version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c08cb5d762c0694f74bd02c9a5b04ea53cefc496e2c27b3234acffca5cd076b" -dependencies = [ - "anchor-lang", - "spl-associated-token-account", - "spl-pod", - "spl-token", - "spl-token-2022 6.0.0", - "spl-token-group-interface", - "spl-token-metadata-interface", -] - -[[package]] -name = "anchor-spl" -version = "0.31.1" -source = "git+https://github.com/lightprotocol/anchor?rev=d8a2b3d9#d8a2b3d99d61ef900d1f6cdaabcef14eb9af6279" +source = "git+https://github.com/lightprotocol/anchor?rev=da005d7f#da005d7f1f977d5220eaa65da26cdae2df0fe25e" dependencies = [ "anchor-lang", - "mpl-token-metadata", - "spl-associated-token-account", + "spl-associated-token-account 6.0.0", "spl-memo", "spl-pod", - "spl-token", + "spl-token 7.0.0", "spl-token-2022 6.0.0", - "spl-token-group-interface", - "spl-token-metadata-interface", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", ] [[package]] @@ -390,12 +348,6 @@ dependencies = [ "thiserror 1.0.69", ] -[[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" @@ -414,61 +366,11 @@ dependencies = [ "winapi", ] -[[package]] -name = "anstream" -version = "0.6.19" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" -dependencies = [ - "anstyle", - "anstyle-parse", - "anstyle-query", - "anstyle-wincon", - "colorchoice", - "is_terminal_polyfill", - "utf8parse", -] - -[[package]] -name = "anstyle" -version = "1.0.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" - -[[package]] -name = "anstyle-parse" -version = "0.2.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" -dependencies = [ - "utf8parse", -] - -[[package]] -name = "anstyle-query" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" -dependencies = [ - "windows-sys 0.59.0", -] - -[[package]] -name = "anstyle-wincon" -version = "3.0.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" -dependencies = [ - "anstyle", - "once_cell_polyfill", - "windows-sys 0.59.0", -] - [[package]] name = "anyhow" -version = "1.0.98" +version = "1.0.100" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e16d2d3311acee920a9eb8d33b8cbc1787ce4a264e85f964c2404b969bdcd487" +checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" [[package]] name = "ark-bn254" @@ -522,7 +424,7 @@ dependencies = [ "ark-std 0.5.0", "educe 0.6.0", "fnv", - "hashbrown 0.15.4", + "hashbrown 0.15.2", "itertools 0.13.0", "num-bigint 0.4.6", "num-integer", @@ -587,7 +489,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -613,7 +515,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -641,7 +543,7 @@ dependencies = [ "ark-std 0.5.0", "educe 0.6.0", "fnv", - "hashbrown 0.15.4", + "hashbrown 0.15.2", ] [[package]] @@ -688,7 +590,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -730,90 +632,27 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" -[[package]] -name = "asn1-rs" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f6fd5ddaf0351dff5b8da21b2fb4ff8e08ddd02857f0bf69c47639106c0fff0" -dependencies = [ - "asn1-rs-derive", - "asn1-rs-impl", - "displaydoc", - "nom", - "num-traits", - "rusticata-macros", - "thiserror 1.0.69", - "time", -] - -[[package]] -name = "asn1-rs-derive" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "726535892e8eae7e70657b4c8ea93d26b8553afb1ce617caee529ef96d7dee6c" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "synstructure 0.12.6", -] - -[[package]] -name = "asn1-rs-impl" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2777730b2039ac0f95f093556e61b6d26cebed5393ca6f152717777cec3a42ed" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", -] - -[[package]] -name = "async-channel" -version = "1.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" -dependencies = [ - "concurrent-queue", - "event-listener 2.5.3", - "futures-core", -] - [[package]] name = "async-compression" -version = "0.4.27" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ddb939d66e4ae03cee6091612804ba446b12878410cfa17f785f4dd67d4014e8" +checksum = "d10e4f991a553474232bc0a31799f6d24b034a84c0971d80d2e2f78b2e576e40" dependencies = [ - "brotli", - "flate2", - "futures-core", - "memchr", + "compression-codecs", + "compression-core", "pin-project-lite", "tokio", ] -[[package]] -name = "async-lock" -version = "3.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" -dependencies = [ - "event-listener 5.4.0", - "event-listener-strategy", - "pin-project-lite", -] - [[package]] name = "async-trait" -version = "0.1.88" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e539d3fca749fcee5236ab05e93a52867dd549cc157c8cb7f99595f3cedffdb5" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -828,7 +667,7 @@ version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" dependencies = [ - "hermit-abi 0.1.19", + "hermit-abi", "libc", "winapi", ] @@ -839,21 +678,6 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" -[[package]] -name = "backtrace" -version = "0.3.75" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6806a6321ec58106fea15becdad98371e28d92ccbc7c8f1b3b6dd724fe8f1002" -dependencies = [ - "addr2line", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", - "windows-targets 0.52.6", -] - [[package]] name = "base64" version = "0.12.3" @@ -910,11 +734,11 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.9.1" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b8e56985ec62d17e9c1001dc89c88ecd7dc08e47eba5ec7c29c7b5eeecde967" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -973,11 +797,11 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" dependencies = [ - "borsh-derive 1.5.7", + "borsh-derive 1.6.0", "cfg_aliases", ] @@ -996,15 +820,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" dependencies = [ "once_cell", - "proc-macro-crate 3.3.0", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1031,9 +855,9 @@ dependencies = [ [[package]] name = "brotli" -version = "8.0.1" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9991eea70ea4f293524138648e41ee89b0b2b12ddef3b255effa43c8056e0e0d" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -1061,9 +885,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.19.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" [[package]] name = "bv" @@ -1083,22 +907,22 @@ checksum = "175812e0be2bccb6abe50bb8d566126198344f707e304f45c648fd8f2cc0365e" [[package]] name = "bytemuck" -version = "1.23.1" +version = "1.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c76a5792e44e4abe34d3abf15636779261d45a7450612059293d1d2cfc63422" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.10.0" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "441473f2b4b0459a68628c744bc61d23e730fb00128b841d30fa4bb3972257e4" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1109,19 +933,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71b6127be86fdcfddb610f7182ac57211d4b18a3e9c82eb2d17662f2227ad6a" - -[[package]] -name = "caps" -version = "0.5.5" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" -dependencies = [ - "libc", - "thiserror 1.0.69", -] +checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" [[package]] name = "cargo_toml" @@ -1135,26 +949,21 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.30" +version = "1.2.53" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deec109607ca693028562ed836a5f1c4b8bd77755c4e132fc5ce11b0b6211ae7" +checksum = "755d2fce177175ffca841e9a06afdb2c4ab0f593d53b4dee48147dfaade85932" dependencies = [ + "find-msvc-tools", "jobserver", "libc", "shlex", ] -[[package]] -name = "cesu8" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" - [[package]] name = "cfg-if" -version = "1.0.1" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" [[package]] name = "cfg_aliases" @@ -1170,16 +979,15 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "chrono" -version = "0.4.41" +version = "0.4.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c469d952047f47f91b68d1cba3f10d63c11d73e4636f24f08daf0278abf01c4d" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" dependencies = [ - "android-tzdata", "iana-time-zone", "js-sys", "num-traits", @@ -1199,161 +1007,64 @@ dependencies = [ ] [[package]] -name = "clap" -version = "4.5.41" +name = "combine" +version = "3.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "be92d32e80243a54711e5d7ce823c35c41c9d929dc4ab58e1276f625841aadf9" +checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" dependencies = [ - "clap_builder", - "clap_derive", + "ascii", + "byteorder", + "either", + "memchr", + "unreachable", ] [[package]] -name = "clap_builder" -version = "4.5.41" +name = "compression-codecs" +version = "0.4.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "707eab41e9622f9139419d573eca0900137718000c517d47da73045f54331c3d" +checksum = "00828ba6fd27b45a448e57dbfe84f1029d4c9f26b368157e9a448a5f49a2ec2a" dependencies = [ - "anstream", - "anstyle", - "clap_lex", - "strsim", + "brotli", + "compression-core", + "flate2", + "memchr", ] [[package]] -name = "clap_derive" -version = "4.5.41" +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + +[[package]] +name = "console" +version = "0.15.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef4f52386a59ca4c860f7393bcf8abd8dfd91ecccc0f774635ff68e92eeef491" +checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" dependencies = [ - "heck 0.5.0", - "proc-macro2", - "quote", - "syn 2.0.104", + "encode_unicode", + "libc", + "once_cell", + "unicode-width", + "windows-sys 0.59.0", ] [[package]] -name = "clap_lex" -version = "0.7.5" +name = "console_error_panic_hook" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b94f61472cee1439c0b966b47e3aca9ae07e45d070759512cd390ea2bebc6675" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] [[package]] -name = "client" -version = "0.1.0" -dependencies = [ - "anchor-client", - "anchor-lang", - "anchor-spl 0.31.1 (git+https://github.com/lightprotocol/anchor?rev=d8a2b3d9)", - "anyhow", - "arrayref", - "base64 0.21.7", - "bincode", - "borsh 1.5.7", - "bs58", - "bytemuck", - "clap", - "colorful", - "configparser", - "futures", - "hex", - "light-client", - "light-compressed-account", - "light-compressible-client", - "light-program-test", - "light-sdk", - "light-token-client", - "rand 0.9.2", - "raydium-cp-swap", - "regex", - "serde", - "serde_json", - "solana-account-decoder", - "solana-client", - "solana-message", - "solana-sdk", - "solana-transaction-status", - "tokio", -] - -[[package]] -name = "colorchoice" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" - -[[package]] -name = "colorful" -version = "0.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffb474a9c3219a8254ead020421ecf1b90427f29b55f6aae9a2471fa62c126ef" - -[[package]] -name = "combine" -version = "3.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" -dependencies = [ - "ascii", - "byteorder", - "either", - "memchr", - "unreachable", -] - -[[package]] -name = "combine" -version = "4.6.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" -dependencies = [ - "bytes", - "memchr", -] - -[[package]] -name = "concurrent-queue" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" -dependencies = [ - "crossbeam-utils", -] - -[[package]] -name = "configparser" -version = "3.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e57e3272f0190c3f1584272d613719ba5fc7df7f4942fe542e63d949cf3a649b" - -[[package]] -name = "console" -version = "0.15.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "054ccb5b10f9f2cbf51eb355ca1d05c2d279ce1804688d0db74b4733a5aeafd8" -dependencies = [ - "encode_unicode", - "libc", - "once_cell", - "unicode-width", - "windows-sys 0.59.0", -] - -[[package]] -name = "console_error_panic_hook" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" -dependencies = [ - "cfg-if", - "wasm-bindgen", -] - -[[package]] -name = "console_log" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" dependencies = [ "log", "web-sys", @@ -1375,16 +1086,6 @@ dependencies = [ "libc", ] -[[package]] -name = "core-foundation" -version = "0.10.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" -dependencies = [ - "core-foundation-sys", - "libc", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1451,9 +1152,9 @@ checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", "rand_core 0.6.4", @@ -1518,14 +1219,14 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "darling" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ "darling_core", "darling_macro", @@ -1533,70 +1234,37 @@ dependencies = [ [[package]] name = "darling_core" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", "strsim", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "darling_macro" -version = "0.20.11" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ "darling_core", "quote", - "syn 2.0.104", -] - -[[package]] -name = "dashmap" -version = "5.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" -dependencies = [ - "cfg-if", - "hashbrown 0.14.5", - "lock_api", - "once_cell", - "parking_lot_core", -] - -[[package]] -name = "data-encoding" -version = "2.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" - -[[package]] -name = "der-parser" -version = "8.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbd676fbbab537128ef0278adb5576cf363cff6aa22a7b24effe97347cfab61e" -dependencies = [ - "asn1-rs", - "displaydoc", - "nom", - "num-bigint 0.4.6", - "num-traits", - "rusticata-macros", + "syn 2.0.114", ] [[package]] name = "deranged" -version = "0.4.0" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c9e6a11ca8224451684bc0d7d5a7adbf8f2fd6887261a1cfc3c0432f9d4068e" +checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -1644,30 +1312,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", -] - -[[package]] -name = "dlopen2" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b4f5f101177ff01b8ec4ecc81eead416a8aa42819a2869311b3420fa114ffa" -dependencies = [ - "dlopen2_derive", - "libc", - "once_cell", - "winapi", -] - -[[package]] -name = "dlopen2_derive" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1735,10 +1380,10 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" dependencies = [ - "enum-ordinalize 4.3.0", + "enum-ordinalize 4.3.2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1773,13 +1418,13 @@ dependencies = [ [[package]] name = "enum-iterator-derive" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1792,27 +1437,27 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "enum-ordinalize" -version = "4.3.0" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fea0dcfa4e54eeb516fe454635a95753ddd39acda650ce703031c6973e315dd5" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" dependencies = [ "enum-ordinalize-derive", ] [[package]] name = "enum-ordinalize-derive" -version = "4.3.1" +version = "4.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d28318a75d4aead5c4db25382e8ef717932d0346600cacae6357eb5941bc5ff" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -1846,51 +1491,12 @@ checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.13" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "778e2ac28f6c47af28e4907f13ffd1e1ddbd400980a9abd7c8df189bf578a5ad" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.60.2", -] - -[[package]] -name = "event-listener" -version = "2.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" - -[[package]] -name = "event-listener" -version = "5.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3492acde4c3fc54c845eaab3eed8bd00c7a7d881f78bfc801e43a93dec1331ae" -dependencies = [ - "concurrent-queue", - "parking", - "pin-project-lite", -] - -[[package]] -name = "event-listener-strategy" -version = "0.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" -dependencies = [ - "event-listener 5.4.0", - "pin-project-lite", -] - -[[package]] -name = "fastbloom" -version = "0.9.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27cea6e7f512d43b098939ff4d5a5d6fe3db07971e1d05176fe26c642d33f5b8" -dependencies = [ - "getrandom 0.3.3", - "rand 0.9.2", - "siphasher 1.0.1", - "wide", + "windows-sys 0.61.2", ] [[package]] @@ -1911,6 +1517,21 @@ version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" +[[package]] +name = "find-msvc-tools" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8591b0bcc8a98a64310a2fae1bb3e9b8564dd10e381e6e28010fde8e8e8568db" + +[[package]] +name = "five8" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" +dependencies = [ + "five8_core", +] + [[package]] name = "five8_const" version = "0.1.4" @@ -1928,9 +1549,9 @@ checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" [[package]] name = "flate2" -version = "1.1.2" +version = "1.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3d7db9596fecd151c5f638c0ee5d5bd487b6e0ea232e5dc96d5250f6f94b1d" +checksum = "b375d6465b98090a5f25b1c7703f3859783755aa9a80433b36e0379a3ec2f369" dependencies = [ "crc32fast", "miniz_oxide", @@ -1942,6 +1563,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -1959,9 +1586,9 @@ checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] @@ -2028,7 +1655,7 @@ checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -2043,12 +1670,6 @@ version = "0.3.31" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" -[[package]] -name = "futures-timer" -version = "3.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" - [[package]] name = "futures-util" version = "0.3.31" @@ -2102,9 +1723,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -2115,44 +1736,18 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.3.3" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" dependencies = [ "cfg-if", "js-sys", "libc", "r-efi", - "wasi 0.14.2+wasi-0.2.4", + "wasip2", "wasm-bindgen", ] -[[package]] -name = "gimli" -version = "0.31.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "07e28edb80900c19c28f1072f2e8aeca7fa06b23cd4169cefe1af5aa3260783f" - -[[package]] -name = "governor" -version = "0.6.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" -dependencies = [ - "cfg-if", - "dashmap", - "futures", - "futures-timer", - "no-std-compat", - "nonzero_ext", - "parking_lot", - "portable-atomic", - "quanta", - "rand 0.8.5", - "smallvec", - "spinning_top", -] - [[package]] name = "groth16-solana" version = "0.2.0" @@ -2180,37 +1775,37 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.10.0", + "indexmap 2.13.0", "slab", "tokio", - "tokio-util 0.7.15", + "tokio-util 0.7.18", "tracing", ] [[package]] name = "h2" -version = "0.4.11" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17da50a276f1e01e0ba6c029e47b7100754904ee8a278f886546e98575380785" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.3.1", - "indexmap 2.10.0", + "http 1.4.0", + "indexmap 2.13.0", "slab", "tokio", - "tokio-util 0.7.15", + "tokio-util 0.7.18", "tracing", ] [[package]] name = "hash32" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" dependencies = [ "byteorder", ] @@ -2232,18 +1827,20 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.14.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] [[package]] name = "hashbrown" -version = "0.15.4" +version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5971ac85611da7067dbfcabef3c70ebb5606018acd9e2a3903a0da507521e0d5" -dependencies = [ - "allocator-api2", -] +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" [[package]] name = "heck" @@ -2254,12 +1851,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "heck" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" - [[package]] name = "heck" version = "0.5.0" @@ -2275,24 +1866,12 @@ dependencies = [ "libc", ] -[[package]] -name = "hermit-abi" -version = "0.5.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" - [[package]] name = "hex" version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" -[[package]] -name = "histogram" -version = "0.6.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "12cb882ccb290b8646e554b157ab0b71e64e8d5bef775cd66b6531e52d302669" - [[package]] name = "hmac" version = "0.8.1" @@ -2336,12 +1915,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -2363,7 +1941,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -2374,7 +1952,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2393,9 +1971,9 @@ checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" [[package]] name = "humantime" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b112acc8b3adf4b107a8ec20977da0273a8c386765a3ec0229bd500a1443f9f" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] name = "hyper" @@ -2423,19 +2001,21 @@ dependencies = [ [[package]] name = "hyper" -version = "1.6.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc2b571658e38e0c01b1fdca3bbbe93c00d3d71693ff2770043f8c29bc7d6f80" +checksum = "2ab2d4f250c3d7b1c9fcdff1cece94ea4e2dfbec68614f7b87cb205f24ca9d11" dependencies = [ + "atomic-waker", "bytes", "futures-channel", - "futures-util", - "h2 0.4.11", - "http 1.3.1", + "futures-core", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "httparse", "itoa", "pin-project-lite", + "pin-utils", "smallvec", "tokio", "want", @@ -2461,14 +2041,15 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", - "hyper 1.6.0", + "http 1.4.0", + "hyper 1.8.1", "hyper-util", - "rustls 0.23.29", + "rustls 0.23.36", "rustls-pki-types", "tokio", - "tokio-rustls 0.26.2", + "tokio-rustls 0.26.4", "tower-service", + "webpki-roots 1.0.5", ] [[package]] @@ -2492,7 +2073,7 @@ checksum = "70206fc6890eaca9fde8a0bf71caa2ddfc9fe045ac9e5c70df101a7dbde866e0" dependencies = [ "bytes", "http-body-util", - "hyper 1.6.0", + "hyper 1.8.1", "hyper-util", "native-tls", "tokio", @@ -2502,23 +2083,23 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.16" +version = "0.1.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9b05277c7e8da2c93a568989bb6207bef0112e8d17df7a6eda4a3cf143bc5e" +checksum = "727805d60e7938b76b826a6ef209eb70eaa1812794f9424d4a4e2d740662df5f" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", - "hyper 1.6.0", + "hyper 1.8.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.0", + "socket2 0.6.1", "system-configuration 0.6.1", "tokio", "tower-service", @@ -2528,9 +2109,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.63" +version = "0.1.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c919e5debc312ad217002b8048a17b7d83f80703865bbfcfebb0458b0b27d8" +checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2552,9 +2133,9 @@ dependencies = [ [[package]] name = "icu_collections" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "200072f5d0e3614556f94a9930d5dc3e0662a652823904c3a75dc3b0af7fee47" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" dependencies = [ "displaydoc", "potential_utf", @@ -2565,9 +2146,9 @@ dependencies = [ [[package]] name = "icu_locale_core" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0cde2700ccaed3872079a65fb1a78f6c0a36c91570f28755dda67bc8f7d9f00a" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" dependencies = [ "displaydoc", "litemap", @@ -2578,11 +2159,10 @@ dependencies = [ [[package]] name = "icu_normalizer" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "436880e8e18df4d7bbc06d58432329d6458cc84531f7ac5f024e93deadb37979" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" dependencies = [ - "displaydoc", "icu_collections", "icu_normalizer_data", "icu_properties", @@ -2593,42 +2173,38 @@ dependencies = [ [[package]] name = "icu_normalizer_data" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "00210d6893afc98edb752b664b8890f0ef174c8adbb8d0be9710fa66fbbf72d3" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "016c619c1eeb94efb86809b015c58f479963de65bdb6253345c1a1276f22e32b" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ - "displaydoc", "icu_collections", "icu_locale_core", "icu_properties_data", "icu_provider", - "potential_utf", "zerotrie", "zerovec", ] [[package]] name = "icu_properties_data" -version = "2.0.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "298459143998310acd25ffe6810ed544932242d3f07083eee1084d83a71bd632" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" -version = "2.0.0" +version = "2.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03c80da27b5f4187909049ee2d72f276f0d9f99a42c306bd0131ecfe04d8e5af" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" dependencies = [ "displaydoc", "icu_locale_core", - "stable_deref_trait", - "tinystr", "writeable", "yoke", "zerofrom", @@ -2644,9 +2220,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "1.0.3" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "686f825264d630750a544639377bae737628043f20d38bbc029e8f29ea968a7e" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" dependencies = [ "idna_adapter", "smallvec", @@ -2676,13 +2252,14 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.10.0" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe4cd85333e22411419a0bcae1297d25e58c9443848b11dc6a86fefe8c78a661" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", - "hashbrown 0.15.4", + "hashbrown 0.16.1", "serde", + "serde_core", ] [[package]] @@ -2708,38 +2285,21 @@ dependencies = [ ] [[package]] -name = "io-uring" -version = "0.7.9" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d93587f37623a1a17d94ef2bc9ada592f5465fe7732084ab7beefabe5c77c0c4" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "libc", -] - -[[package]] -name = "ipnet" -version = "2.11.0" +name = "ipnet" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" [[package]] name = "iri-string" -version = "0.7.8" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dbc5ebe9c3a1a7a5127f920a418f7585e9e758e911d0466ed004f393b0e380b2" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", ] -[[package]] -name = "is_terminal_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" - [[package]] name = "itertools" version = "0.10.5" @@ -2778,47 +2338,25 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" - -[[package]] -name = "jni" -version = "0.21.1" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" -dependencies = [ - "cesu8", - "cfg-if", - "combine 4.6.7", - "jni-sys", - "log", - "thiserror 1.0.69", - "walkdir", - "windows-sys 0.45.0", -] - -[[package]] -name = "jni-sys" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jobserver" -version = "0.1.33" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38f262f097c174adebe41eb73d66ae9c06b2844fb0da69969647bbddd9b0538a" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.77" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" dependencies = [ "once_cell", "wasm-bindgen", @@ -2839,6 +2377,16 @@ dependencies = [ "serde_json", ] +[[package]] +name = "kaigan" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ba15de5aeb137f0f65aa3bf82187647f1285abfe5b20c80c2c37f7007ad519a" +dependencies = [ + "borsh 0.10.4", + "serde", +] + [[package]] name = "keccak" version = "0.1.5" @@ -2856,9 +2404,9 @@ checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.174" +version = "0.2.180" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" +checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc" [[package]] name = "libsecp256k1" @@ -2910,22 +2458,29 @@ dependencies = [ [[package]] name = "light-account-checks" -version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.6.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ - "pinocchio", "solana-account-info", "solana-msg", "solana-program-error", "solana-pubkey", "solana-sysvar", - "thiserror 2.0.12", + "thiserror 2.0.18", +] + +[[package]] +name = "light-array-map" +version = "0.1.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +dependencies = [ + "tinyvec", ] [[package]] name = "light-batched-merkle-tree" -version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.7.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -2942,27 +2497,27 @@ dependencies = [ "solana-program-error", "solana-pubkey", "solana-sysvar", - "thiserror 2.0.12", + "thiserror 2.0.18", "zerocopy", ] [[package]] name = "light-bloom-filter" -version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.5.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "bitvec", "num-bigint 0.4.6", "solana-nostd-keccak", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "light-bounded-vec" -version = "2.0.0" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233a69f003522990dadcf923b436094ffcb55326a2c3cef7f67acdbcb6e5b039" +checksum = "58cfa375d028164719e3ffef93d2e5c27855cc8a5bb5bf257b868d17c12a3e66" dependencies = [ "bytemuck", "memoffset", @@ -2972,24 +2527,26 @@ dependencies = [ [[package]] name = "light-client" -version = "0.13.1" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.17.2" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "async-trait", "base64 0.13.1", "borsh 0.10.4", "bs58", - "bytemuck", "lazy_static", "light-compressed-account", "light-concurrent-merkle-tree", + "light-event", "light-hasher", "light-indexed-merkle-tree", "light-merkle-tree-metadata", "light-prover-client", "light-sdk", + "light-token-interface", + "light-token-sdk", + "litesvm", "num-bigint 0.4.6", - "num-traits", "photon-api", "rand 0.8.5", "solana-account", @@ -2999,7 +2556,6 @@ dependencies = [ "solana-clock", "solana-commitment-config", "solana-compute-budget-interface", - "solana-epoch-info", "solana-hash", "solana-instruction", "solana-keypair", @@ -3012,202 +2568,139 @@ dependencies = [ "solana-transaction", "solana-transaction-error", "solana-transaction-status-client-types", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tracing", ] [[package]] name = "light-compressed-account" -version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.7.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "anchor-lang", "borsh 0.10.4", "bytemuck", "light-hasher", "light-macros", + "light-poseidon 0.3.0", + "light-program-profiler", "light-zero-copy", "solana-msg", "solana-program-error", "solana-pubkey", - "thiserror 2.0.12", + "thiserror 2.0.18", + "tinyvec", "zerocopy", ] [[package]] -name = "light-compressed-token" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +name = "light-compressible" +version = "0.2.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ - "account-compression", - "anchor-compressed-token", + "aligned-sized", "anchor-lang", - "arrayvec", "borsh 0.10.4", + "bytemuck", "light-account-checks", "light-compressed-account", - "light-ctoken-types", "light-hasher", - "light-heap", - "light-sdk", - "light-sdk-pinocchio", + "light-macros", + "light-program-profiler", "light-sdk-types", - "light-system-program-anchor", "light-zero-copy", - "pinocchio", - "solana-pubkey", - "solana-security-txt", - "spl-pod", - "spl-token", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-2022 7.0.0 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", - "zerocopy", -] - -[[package]] -name = "light-compressed-token-sdk" -version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "anchor-lang", - "arrayvec", - "borsh 0.10.4", - "light-account-checks", - "light-compressed-account", - "light-compressed-token-types", - "light-ctoken-types", - "light-macros", - "light-sdk", - "solana-account-info", - "solana-cpi", - "solana-instruction", + "pinocchio-pubkey", "solana-msg", "solana-program-error", "solana-pubkey", - "spl-pod", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 2.0.12", -] - -[[package]] -name = "light-compressed-token-types" -version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "anchor-lang", - "borsh 0.10.4", - "light-account-checks", - "light-compressed-account", - "light-macros", - "light-sdk-types", - "solana-msg", - "thiserror 2.0.12", + "solana-sysvar", + "thiserror 2.0.18", + "zerocopy", ] [[package]] name = "light-compressible-client" -version = "0.13.1" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.17.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "anchor-lang", + "async-trait", "borsh 0.10.4", + "futures", "light-client", + "light-compressed-account", + "light-compressible", "light-sdk", + "light-token-interface", + "light-token-sdk", + "smallvec", "solana-account", "solana-instruction", + "solana-program", + "solana-program-error", "solana-pubkey", - "thiserror 2.0.12", + "spl-token-2022 7.0.0", + "thiserror 2.0.18", ] [[package]] name = "light-concurrent-merkle-tree" -version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "5.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "borsh 0.10.4", "light-bounded-vec", "light-hasher", "memoffset", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] -name = "light-ctoken-types" -version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +name = "light-event" +version = "0.2.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ - "anchor-lang", - "arrayvec", "borsh 0.10.4", "light-compressed-account", "light-hasher", - "light-macros", "light-zero-copy", - "pinocchio", - "solana-msg", - "solana-pubkey", - "spl-pod", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "thiserror 2.0.12", - "zerocopy", -] - -[[package]] -name = "light-hash-set" -version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "light-hasher", - "num-bigint 0.4.6", - "num-traits", - "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "light-hasher" -version = "3.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "5.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", - "arrayvec", "borsh 0.10.4", "light-poseidon 0.3.0", "num-bigint 0.4.6", "sha2 0.10.9", "sha3", - "solana-nostd-keccak", "solana-program-error", - "solana-pubkey", - "thiserror 2.0.12", -] - -[[package]] -name = "light-heap" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "anchor-lang", + "thiserror 2.0.18", + "tinyvec", ] [[package]] name = "light-indexed-array" -version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.3.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "light-hasher", "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "light-indexed-merkle-tree" -version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "5.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "light-bounded-vec", "light-concurrent-merkle-tree", @@ -3216,24 +2709,25 @@ dependencies = [ "num-bigint 0.4.6", "num-traits", "solana-program-error", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "light-macros" -version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "2.2.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.104", + "solana-pubkey", + "syn 2.0.114", ] [[package]] name = "light-merkle-tree-metadata" -version = "0.3.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.7.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -3242,20 +2736,20 @@ dependencies = [ "solana-msg", "solana-program-error", "solana-sysvar", - "thiserror 2.0.12", + "thiserror 2.0.18", "zerocopy", ] [[package]] name = "light-merkle-tree-reference" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "4.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "light-hasher", "light-indexed-array", "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -3282,40 +2776,60 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "light-profiler-macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a8be18fe4de58a6f754caa74a3fbc6d8a758a26f1f3c24d5b0f5b55df5f5408" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "light-program-profiler" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1d345871581aebd8825868a3f08410290aa1cdddcb189ca7f7e588f61d79fcf" +dependencies = [ + "light-profiler-macro", +] + [[package]] name = "light-program-test" -version = "0.13.2" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.17.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ - "account-compression", "anchor-lang", "async-trait", + "base64 0.13.1", "borsh 0.10.4", "bs58", "bytemuck", "chrono", - "light-batched-merkle-tree", "light-client", "light-compressed-account", - "light-compressed-token", "light-compressible-client", - "light-concurrent-merkle-tree", + "light-event", "light-hasher", "light-indexed-array", "light-indexed-merkle-tree", "light-merkle-tree-metadata", "light-merkle-tree-reference", "light-prover-client", - "light-registry", "light-sdk", "light-sdk-types", + "light-token-interface", + "light-token-sdk", + "light-zero-copy", "litesvm", "log", "num-bigint 0.4.6", "num-traits", "photon-api", "rand 0.8.5", - "reqwest 0.12.22", + "reqwest 0.12.28", "serde", "serde_json", "solana-account", @@ -3328,18 +2842,20 @@ dependencies = [ "solana-transaction", "solana-transaction-status", "solana-transaction-status-client-types", + "spl-token-2022 7.0.0", "tabled", "tokio", ] [[package]] name = "light-prover-client" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "5.0.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "ark-bn254 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", + "light-compressed-account", "light-hasher", "light-indexed-array", "light-sparse-merkle-tree", @@ -3349,37 +2865,22 @@ dependencies = [ "serde", "serde_json", "solana-bn254", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tracing", ] -[[package]] -name = "light-registry" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "account-compression", - "aligned-sized", - "anchor-lang", - "light-batched-merkle-tree", - "light-merkle-tree-metadata", - "light-system-program-anchor", - "solana-sdk", - "solana-security-txt", -] - [[package]] name = "light-sdk" -version = "0.13.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.17.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "anchor-lang", - "arrayvec", "bincode", "borsh 0.10.4", "light-account-checks", "light-compressed-account", + "light-compressible", "light-hasher", "light-macros", "light-sdk-macros", @@ -3390,52 +2891,33 @@ dependencies = [ "solana-clock", "solana-cpi", "solana-instruction", + "solana-loader-v3-interface", "solana-msg", - "solana-program", "solana-program-error", "solana-pubkey", - "solana-rent", "solana-system-interface", "solana-sysvar", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "light-sdk-macros" -version = "0.13.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.17.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ - "heck 0.4.1", + "darling", "light-hasher", - "light-poseidon 0.3.0", + "light-sdk-types", "proc-macro2", "quote", "solana-pubkey", - "syn 2.0.104", -] - -[[package]] -name = "light-sdk-pinocchio" -version = "0.13.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" -dependencies = [ - "borsh 0.10.4", - "light-account-checks", - "light-compressed-account", - "light-hasher", - "light-macros", - "light-sdk-macros", - "light-sdk-types", - "light-zero-copy", - "pinocchio", - "solana-pubkey", - "thiserror 2.0.12", + "syn 2.0.114", ] [[package]] name = "light-sdk-types" -version = "0.13.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.17.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -3443,72 +2925,107 @@ dependencies = [ "light-compressed-account", "light-hasher", "light-macros", - "light-zero-copy", "solana-msg", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "light-sparse-merkle-tree" -version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.3.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "light-hasher", "light-indexed-array", "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] -name = "light-system-program-anchor" -version = "2.0.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +name = "light-token-interface" +version = "0.1.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ - "account-compression", "aligned-sized", "anchor-lang", + "borsh 0.10.4", + "bytemuck", + "light-array-map", "light-compressed-account", + "light-compressible", + "light-hasher", + "light-macros", + "light-program-profiler", "light-zero-copy", + "pinocchio", + "pinocchio-pubkey", + "solana-account-info", + "solana-pubkey", + "spl-pod", + "spl-token-2022 7.0.0", + "thiserror 2.0.18", + "tinyvec", "zerocopy", ] [[package]] -name = "light-token-client" -version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +name = "light-token-sdk" +version = "0.2.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ + "anchor-lang", + "arrayvec", "borsh 0.10.4", - "light-client", + "light-account-checks", + "light-batched-merkle-tree", "light-compressed-account", - "light-compressed-token-sdk", - "light-compressed-token-types", - "light-ctoken-types", + "light-compressible", + "light-macros", + "light-program-profiler", "light-sdk", + "light-sdk-types", + "light-token-interface", + "light-token-types", + "light-zero-copy", + "solana-account-info", + "solana-cpi", "solana-instruction", - "solana-keypair", "solana-msg", + "solana-program-error", "solana-pubkey", - "solana-signature", - "solana-signer", "spl-pod", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "thiserror 2.0.18", +] + +[[package]] +name = "light-token-types" +version = "0.2.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +dependencies = [ + "anchor-lang", + "borsh 0.10.4", + "light-account-checks", + "light-compressed-account", + "light-macros", + "light-sdk-types", + "solana-msg", + "thiserror 2.0.18", ] [[package]] name = "light-verifier" -version = "2.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "6.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "groth16-solana", "light-compressed-account", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "light-zero-copy" -version = "0.2.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.5.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "light-zero-copy-derive", "solana-program-error", @@ -3517,36 +3034,39 @@ dependencies = [ [[package]] name = "light-zero-copy-derive" -version = "0.1.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.5.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "linux-raw-sys" -version = "0.9.4" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" [[package]] name = "litemap" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "241eaef5fd12c88705a01fc1066c48c4b36e0dd4377dcdc7ec3942cea7a69956" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" [[package]] name = "litesvm" -version = "0.6.1" +version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb7e5f4462f34439adcfcab58099bc7a89c67a17f8240b84a993b8b705c1becb" +checksum = "23bca37ac374948b348e29c74b324dc36f18bbbd1ccf80e2046d967521cbd143" dependencies = [ + "agave-feature-set", + "agave-precompiles", + "agave-reserved-account-keys", "ansi_term", "bincode", - "indexmap 2.10.0", + "indexmap 2.13.0", "itertools 0.14.0", "log", "solana-account", @@ -3556,10 +3076,8 @@ dependencies = [ "solana-clock", "solana-compute-budget", "solana-compute-budget-instruction", - "solana-config-program", "solana-epoch-rewards", "solana-epoch-schedule", - "solana-feature-set", "solana-fee", "solana-fee-structure", "solana-hash", @@ -3570,17 +3088,15 @@ dependencies = [ "solana-loader-v3-interface", "solana-loader-v4-interface", "solana-log-collector", - "solana-measure", "solana-message", - "solana-native-token", + "solana-native-token 3.0.0", "solana-nonce", "solana-nonce-account", - "solana-precompiles", + "solana-precompile-error", "solana-program-error", "solana-program-runtime", "solana-pubkey", "solana-rent", - "solana-reserved-account-keys", "solana-sdk-ids", "solana-sha256-hasher", "solana-signature", @@ -3588,6 +3104,7 @@ dependencies = [ "solana-slot-hashes", "solana-slot-history", "solana-stake-interface", + "solana-svm-callback", "solana-svm-transaction", "solana-system-interface", "solana-system-program", @@ -3598,24 +3115,23 @@ dependencies = [ "solana-transaction-context", "solana-transaction-error", "solana-vote-program", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "lock_api" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.27" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru-slab" @@ -3625,9 +3141,9 @@ checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" [[package]] name = "memchr" -version = "2.7.5" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "memmap2" @@ -3675,12 +3191,6 @@ dependencies = [ "unicase", ] -[[package]] -name = "minimal-lexical" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" - [[package]] name = "miniz_oxide" version = "0.8.9" @@ -3688,30 +3198,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "1.0.4" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78bed444cc8a2160f01cbcf811ef18cac863ad68ae8ca62092e8db51d51c761c" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", - "windows-sys 0.59.0", -] - -[[package]] -name = "mpl-token-metadata" -version = "5.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "989e6a3000e761d3b2d685662a3a9ee99826f9369fb033bd1bc7011b1cf02ed9" -dependencies = [ - "borsh 0.10.4", - "num-derive 0.3.3", - "num-traits", - "solana-program", - "thiserror 1.0.69", + "windows-sys 0.61.2", ] [[package]] @@ -3726,46 +3224,11 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] -[[package]] -name = "nix" -version = "0.29.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" -dependencies = [ - "bitflags 2.9.1", - "cfg-if", - "cfg_aliases", - "libc", - "memoffset", -] - -[[package]] -name = "no-std-compat" -version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" - -[[package]] -name = "nom" -version = "7.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" -dependencies = [ - "memchr", - "minimal-lexical", -] - -[[package]] -name = "nonzero_ext" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" - [[package]] name = "num" version = "0.2.1" @@ -3818,17 +3281,6 @@ 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", - "quote", - "syn 1.0.109", -] - [[package]] name = "num-derive" version = "0.4.2" @@ -3837,7 +3289,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -3881,21 +3333,11 @@ dependencies = [ "autocfg", ] -[[package]] -name = "num_cpus" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" -dependencies = [ - "hermit-abi 0.5.2", - "libc", -] - [[package]] name = "num_enum" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a973b4e44ce6cad84ce69d797acf9a044532e4184c4f267913d1b546a0727b7a" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" dependencies = [ "num_enum_derive", "rustversion", @@ -3903,14 +3345,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.4" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77e878c846a8abae00dd069496dbe8751b16ac1c3d6bd2a7283a938e8228f90d" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" dependencies = [ - "proc-macro-crate 3.3.0", + "proc-macro-crate 3.4.0", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -3919,36 +3361,12 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" -[[package]] -name = "object" -version = "0.36.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62948e14d923ea95ea2c7c86c71013138b66525b86bdc08d2dcc262bdb497b87" -dependencies = [ - "memchr", -] - -[[package]] -name = "oid-registry" -version = "0.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" -dependencies = [ - "asn1-rs", -] - [[package]] name = "once_cell" version = "1.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" -[[package]] -name = "once_cell_polyfill" -version = "1.70.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" - [[package]] name = "opaque-debug" version = "0.3.1" @@ -3957,11 +3375,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.73" +version = "0.10.75" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8505734d46c8ab1e19a1dce3aef597ad87dcb4c37e7188231769bd6bd51cebf8" +checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "cfg-if", "foreign-types", "libc", @@ -3978,7 +3396,7 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -3987,14 +3405,24 @@ version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +[[package]] +name = "openssl-src" +version = "300.5.4+3.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a507b3792995dae9b0df8a1c1e3771e8418b7c2d9f0baeba32e6fe8b06c7cb72" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" -version = "0.9.109" +version = "0.9.111" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90096e2e47630d78b7d1c20952dc621f957103f8bc2c8359ec81290d75238571" +checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] @@ -4029,17 +3457,11 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "parking" -version = "2.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" - [[package]] name = "parking_lot" -version = "0.12.4" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -4047,15 +3469,15 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.11" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-targets 0.52.6", + "windows-link", ] [[package]] @@ -4073,20 +3495,11 @@ dependencies = [ "digest 0.10.7", ] -[[package]] -name = "pem" -version = "1.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8835c273a76a90455d7344889b0964598e3316e2a79ede8e36f16bdcf2228b8" -dependencies = [ - "base64 0.13.1", -] - [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "percentage" @@ -4099,10 +3512,10 @@ dependencies = [ [[package]] name = "photon-api" -version = "0.51.0" -source = "git+https://github.com/lightprotocol/light-protocol?tag=csdk-0.3.3#196374d85dce47cdc00b3042f5eaa07014f1e306" +version = "0.53.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" dependencies = [ - "reqwest 0.12.22", + "reqwest 0.12.28", "serde", "serde_derive", "serde_json", @@ -4128,7 +3541,7 @@ checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -4145,9 +3558,20 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinocchio" -version = "0.8.4" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b971851087bc3699b001954ad02389d50c41405ece3548cbcafc88b3e20017a" + +[[package]] +name = "pinocchio-pubkey" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c33b58567c11b07749cefbb8320ac023f3387c57807aeb8e3b1262501b6e9f0" +checksum = "cb0225638cadcbebae8932cb7f49cb5da7c15c21beb19f048f05a5ca7d93f065" +dependencies = [ + "five8_const", + "pinocchio", + "sha2-const-stable", +] [[package]] name = "pkg-config" @@ -4169,15 +3593,15 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" [[package]] name = "potential_utf" -version = "0.1.2" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5a7c30837279ca13e7c867e9e40053bc68740f988cb07f7ca6df43cc734b585" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" dependencies = [ "zerovec", ] @@ -4208,11 +3632,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" dependencies = [ - "toml_edit", + "toml_edit 0.23.10+spec-1.0.0", ] [[package]] @@ -4234,28 +3658,27 @@ dependencies = [ "proc-macro-error-attr2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] [[package]] name = "proptest" -version = "1.7.0" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fcdab19deb5195a31cf7726a210015ff1496ba1464fd42cb4f537b8b01b471f" +checksum = "bee689443a2bd0a16ab0348b52ee43e3b2d1b1f931c8aa5c9f8de4c86fbe8c40" dependencies = [ "bit-set", "bit-vec", - "bitflags 2.9.1", - "lazy_static", + "bitflags 2.10.0", "num-traits", "rand 0.9.2", "rand_chacha 0.9.0", @@ -4283,22 +3706,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", -] - -[[package]] -name = "quanta" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" -dependencies = [ - "crossbeam-utils", - "libc", - "once_cell", - "raw-cpuid", - "wasi 0.11.1+wasi-snapshot-preview1", - "web-sys", - "winapi", + "syn 2.0.114", ] [[package]] @@ -4320,9 +3728,9 @@ dependencies = [ [[package]] name = "quinn" -version = "0.11.8" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "626214629cda6781b6dc1d316ba307189c85ba657213ce642d9c77670f8202c8" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", "cfg_aliases", @@ -4330,9 +3738,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash", - "rustls 0.23.29", - "socket2 0.5.10", - "thiserror 2.0.12", + "rustls 0.23.36", + "socket2 0.6.1", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -4340,22 +3748,20 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.12" +version = "0.11.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49df843a9161c85bb8aae55f101bc0bac8bcafd637a620d9122fd7e0b2f7422e" +checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" dependencies = [ "bytes", - "fastbloom", - "getrandom 0.3.3", + "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring", "rustc-hash", - "rustls 0.23.29", + "rustls 0.23.36", "rustls-pki-types", - "rustls-platform-verifier", "slab", - "thiserror 2.0.12", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -4363,23 +3769,23 @@ dependencies = [ [[package]] name = "quinn-udp" -version = "0.5.13" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcebb1209ee276352ef14ff8732e24cc2b02bbac986cd74a4c81bcb2f9881970" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.5.10", + "socket2 0.6.1", "tracing", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] @@ -4427,7 +3833,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4457,7 +3863,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4475,16 +3881,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", ] [[package]] @@ -4502,16 +3908,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "513962919efc330f829edb2535844d1b912b0fbe2ca165d613e4e8788bb05a5a" dependencies = [ - "rand_core 0.9.3", -] - -[[package]] -name = "raw-cpuid" -version = "11.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6df7ab838ed27997ba19a4664507e6f82b41fe6e20be42929332156e5e85146" -dependencies = [ - "bitflags 2.9.1", + "rand_core 0.9.5", ] [[package]] @@ -4519,34 +3916,45 @@ name = "raydium-cp-swap" version = "0.2.0" dependencies = [ "anchor-lang", - "anchor-spl 0.31.1 (git+https://github.com/lightprotocol/anchor?rev=d8a2b3d9)", + "anchor-spl", "arrayref", "bytemuck", "light-client", "light-compressed-account", - "light-compressed-token-sdk", + "light-compressible", "light-compressible-client", - "light-ctoken-types", "light-hasher", - "light-macros", "light-program-test", "light-sdk", "light-sdk-macros", "light-sdk-types", + "light-token-sdk", "proptest", "quickcheck", "rand 0.9.2", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-keypair", + "solana-msg", + "solana-program", + "solana-program-error", + "solana-pubkey", + "solana-sdk", "solana-security-txt", + "solana-signer", "spl-math", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 7.0.0", + "spl-token-2022 7.0.0", + "tokio", "uint", ] [[package]] name = "rayon" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" +checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" dependencies = [ "either", "rayon-core", @@ -4554,9 +3962,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -4564,38 +3972,38 @@ dependencies = [ [[package]] name = "redox_syscall" -version = "0.5.17" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", ] [[package]] name = "ref-cast" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" dependencies = [ "ref-cast-impl", ] [[package]] name = "ref-cast-impl" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "regex" -version = "1.11.1" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -4605,9 +4013,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.9" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -4616,9 +4024,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.5" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "reqwest" @@ -4626,7 +4034,6 @@ version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ - "async-compression", "base64 0.21.7", "bytes", "encoding_rs", @@ -4642,7 +4049,6 @@ dependencies = [ "js-sys", "log", "mime", - "mime_guess", "native-tls", "once_cell", "percent-encoding", @@ -4657,7 +4063,6 @@ dependencies = [ "tokio", "tokio-native-tls", "tokio-rustls 0.24.1", - "tokio-util 0.7.15", "tower-service", "url", "wasm-bindgen", @@ -4669,20 +4074,21 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.22" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cbc931937e6ca3a06e3b6c0aa7841849b160a90351d6ab467a8b9b9959767531" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ "base64 0.22.1", "bytes", "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2 0.4.11", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "http-body-util", - "hyper 1.6.0", + "hyper 1.8.1", "hyper-rustls 0.27.7", "hyper-tls 0.6.0", "hyper-util", @@ -4693,6 +4099,8 @@ dependencies = [ "native-tls", "percent-encoding", "pin-project-lite", + "quinn", + "rustls 0.23.36", "rustls-pki-types", "serde", "serde_json", @@ -4700,6 +4108,7 @@ dependencies = [ "sync_wrapper 1.0.2", "tokio", "tokio-native-tls", + "tokio-rustls 0.26.4", "tower", "tower-http", "tower-service", @@ -4707,21 +4116,22 @@ dependencies = [ "wasm-bindgen", "wasm-bindgen-futures", "web-sys", + "webpki-roots 1.0.5", ] [[package]] name = "reqwest-middleware" -version = "0.2.5" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a735987236a8e238bf0296c7e351b999c188ccc11477f311b82b55c93984216" +checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" dependencies = [ "anyhow", "async-trait", - "http 0.2.12", - "reqwest 0.11.27", + "http 1.4.0", + "reqwest 0.12.28", "serde", - "task-local-extensions", "thiserror 1.0.69", + "tower-service", ] [[package]] @@ -4732,7 +4142,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted", "windows-sys 0.52.0", @@ -4740,9 +4150,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -4759,26 +4169,17 @@ dependencies = [ "semver", ] -[[package]] -name = "rusticata-macros" -version = "4.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "faf0c4a6ece9950b9abdb62b1cfcf2a68b3b67a10ba445b3bb85be2a293d0632" -dependencies = [ - "nom", -] - [[package]] name = "rustix" -version = "1.0.8" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11181fbabf243db407ef8df94a6ce0b2f9a733bd8be4ad02b4eda9602296cac8" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "errno", "libc", "linux-raw-sys", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -4795,30 +4196,18 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.29" +version = "0.23.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2491382039b29b9b11ff08b76ff6c97cf287671dbb74f0be44bda389fffe9bd1" +checksum = "c665f33d38cea657d9614f766881e4d510e0eda4239891eea56b4cadcf01801b" dependencies = [ "once_cell", "ring", "rustls-pki-types", - "rustls-webpki 0.103.4", + "rustls-webpki 0.103.9", "subtle", "zeroize", ] -[[package]] -name = "rustls-native-certs" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fcff2dd52b58a8d98a70243663a0d234c4e2b79235637849d15913394a247d3" -dependencies = [ - "openssl-probe", - "rustls-pki-types", - "schannel", - "security-framework 3.2.0", -] - [[package]] name = "rustls-pemfile" version = "1.0.4" @@ -4830,41 +4219,14 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.12.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "229a4a4c221013e7e1f1a043678c5cc39fe5171437c88fb47151a21e6f5b5c79" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", ] -[[package]] -name = "rustls-platform-verifier" -version = "0.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19787cda76408ec5404443dc8b31795c87cd8fec49762dc75fa727740d34acc1" -dependencies = [ - "core-foundation 0.10.1", - "core-foundation-sys", - "jni", - "log", - "once_cell", - "rustls 0.23.29", - "rustls-native-certs", - "rustls-platform-verifier-android", - "rustls-webpki 0.103.4", - "security-framework 3.2.0", - "security-framework-sys", - "webpki-root-certs 0.26.11", - "windows-sys 0.59.0", -] - -[[package]] -name = "rustls-platform-verifier-android" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" - [[package]] name = "rustls-webpki" version = "0.101.7" @@ -4877,9 +4239,9 @@ dependencies = [ [[package]] name = "rustls-webpki" -version = "0.103.4" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a17884ae0c1b773f1ccd2bd4a8c72f16da897310a98b0e84bf349ad5ead92fc" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring", "rustls-pki-types", @@ -4888,15 +4250,15 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.21" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a0d197bd2c9dc6e53b84da9556a69ba4cdfab8619eb41a8bd1cc2027a0f6b1d" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rusty-fork" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb3dcc6e454c328bb824492db107ab7c0ae8fcffe4ad210136ef014458c1bc4f" +checksum = "cc6bf79ff24e648f6da1f8d1f011e9cac26491b619e6b9280f2b47f1774e6ee2" dependencies = [ "fnv", "quick-error", @@ -4906,35 +4268,17 @@ dependencies = [ [[package]] name = "ryu" -version = "1.0.20" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" - -[[package]] -name = "safe_arch" -version = "0.7.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b02de82ddbe1b636e6170c21be622223aea188ef2e139be0a5b219ec215323" -dependencies = [ - "bytemuck", -] - -[[package]] -name = "same-file" -version = "1.0.6" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" -dependencies = [ - "winapi-util", -] +checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984" [[package]] name = "schannel" -version = "0.1.27" +version = "0.1.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1f29ebaa345f945cec9fbbc532eb307f0fdad8161f281b6369539c8d84876b3d" +checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -4951,9 +4295,9 @@ dependencies = [ [[package]] name = "schemars" -version = "1.0.4" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0" +checksum = "54e910108742c57a770f492731f99be216a52fadd361b06c8fb59d74ccc267d2" dependencies = [ "dyn-clone", "ref-cast", @@ -4983,21 +4327,8 @@ version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" dependencies = [ - "bitflags 2.9.1", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.2.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271720403f46ca04f7ba6f55d438f8bd878d6b8ca0a1046e8228c4145bcbb316" -dependencies = [ - "bitflags 2.9.1", - "core-foundation 0.10.1", + "bitflags 2.10.0", + "core-foundation", "core-foundation-sys", "libc", "security-framework-sys", @@ -5005,9 +4336,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.14.0" +version = "2.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49db231d56a190491cb4aeda9527f1ad45345af50b0851622a7adb8c03b01c32" +checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" dependencies = [ "core-foundation-sys", "libc", @@ -5015,16 +4346,17 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.26" +version = "1.0.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] @@ -5039,34 +4371,45 @@ dependencies = [ [[package]] name = "serde_bytes" -version = "0.11.17" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.219" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "serde_json" -version = "1.0.141" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30b9eff21ebe718216c6ec64e1d9ac57087aad11efc64e32002bce4a0d4c03d3" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", + "serde_core", + "zmij", ] [[package]] @@ -5092,19 +4435,18 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.14.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2c45cd61fefa9db6f254525d46e392b852e0e61d9a1fd36e5bd183450a556d5" +checksum = "4fa237f2807440d238e0364a218270b98f767a00d3dada77b1c53ae88940e2e7" dependencies = [ "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.10.0", + "indexmap 2.13.0", "schemars 0.9.0", - "schemars 1.0.4", - "serde", - "serde_derive", + "schemars 1.2.0", + "serde_core", "serde_json", "serde_with_macros", "time", @@ -5112,25 +4454,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.14.0" +version = "3.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de90945e6565ce0d9a25098082ed4ee4002e047cb59892c318d66821e14bb30f" +checksum = "52a8e3ca0ca629121f70ab50f95249e5a6f925cc0f6ffe8256c45b728875706c" dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.104", -] - -[[package]] -name = "sha1" -version = "0.10.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" -dependencies = [ - "cfg-if", - "cpufeatures", - "digest 0.10.7", + "syn 2.0.114", ] [[package]] @@ -5157,6 +4488,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + [[package]] name = "sha3" version = "0.10.8" @@ -5194,10 +4531,11 @@ dependencies = [ [[package]] name = "signal-hook-registry" -version = "1.4.5" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9203b8055f63a2a00e2f593bb0510367fe707d7ff1e5c872de2f537b339e5410" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -5208,22 +4546,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" [[package]] -name = "siphasher" -version = "0.3.11" +name = "simd-adler32" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "siphasher" -version = "1.0.1" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" [[package]] name = "slab" -version = "0.4.10" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04dc19736151f35336d325007ac991178d504a119863a2fcb3758cdb5e52c50d" +checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" [[package]] name = "smallvec" @@ -5243,12 +4581,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "233504af464074f9d066d7b5416c5f9b894a5862a6506e306f7b816cdd6f1807" +checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" dependencies = [ "libc", - "windows-sys 0.59.0", + "windows-sys 0.60.2", ] [[package]] @@ -5271,48 +4609,52 @@ dependencies = [ [[package]] name = "solana-account-decoder" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3a8e4aacc7c681419ae63c1de36349d2156d5a4f4ffaea8e507335013e57189" +checksum = "ba71c97fa4d85ce4a1e0e79044ad0406c419382be598c800202903a7688ce71a" dependencies = [ "Inflector", "base64 0.22.1", "bincode", "bs58", "bv", - "lazy_static", "serde", "serde_derive", "serde_json", "solana-account", "solana-account-decoder-client-types", + "solana-address-lookup-table-interface", "solana-clock", - "solana-config-program", + "solana-config-program-client", "solana-epoch-schedule", "solana-fee-calculator", "solana-instruction", + "solana-loader-v3-interface", "solana-nonce", - "solana-program", + "solana-program-option", "solana-program-pack", "solana-pubkey", "solana-rent", "solana-sdk-ids", "solana-slot-hashes", "solana-slot-history", + "solana-stake-interface", "solana-sysvar", - "spl-token", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-group-interface", - "spl-token-metadata-interface", - "thiserror 2.0.12", + "solana-vote-interface", + "spl-generic-token", + "spl-token 8.0.0", + "spl-token-2022 8.0.1", + "spl-token-group-interface 0.6.0", + "spl-token-metadata-interface 0.7.0", + "thiserror 2.0.18", "zstd", ] [[package]] name = "solana-account-decoder-client-types" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6329c4f360f5173dd6f65022708486cdd24d302841058e2310945a2502284105" +checksum = "5519e8343325b707f17fbed54fcefb325131b692506d0af9e08a539d15e4f8cf" dependencies = [ "base64 0.22.1", "bs58", @@ -5326,9 +4668,9 @@ dependencies = [ [[package]] name = "solana-account-info" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0c17d606a298a205fae325489fbed88ee6dc4463c111672172327e741c8905d" +checksum = "c8f5152a288ef1912300fc6efa6c2d1f9bb55d9398eb6c72326360b8063987da" dependencies = [ "bincode", "serde", @@ -5354,31 +4696,6 @@ dependencies = [ "solana-slot-hashes", ] -[[package]] -name = "solana-address-lookup-table-program" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b87ae97f2d1b91a9790c1e35dba3f90a4d595d105097ad93fa685cbc034ad0f1" -dependencies = [ - "bincode", - "bytemuck", - "log", - "num-derive 0.4.2", - "num-traits", - "solana-address-lookup-table-interface", - "solana-bincode", - "solana-clock", - "solana-feature-set", - "solana-instruction", - "solana-log-collector", - "solana-packet", - "solana-program-runtime", - "solana-pubkey", - "solana-system-interface", - "solana-transaction-context", - "thiserror 2.0.12", -] - [[package]] name = "solana-atomic-u64" version = "2.2.1" @@ -5390,30 +4707,50 @@ dependencies = [ [[package]] name = "solana-banks-client" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71e8b93a73f583fb03c9a43be9185c2e04c8a5df84e3c20fd813f0ff79a12142" +checksum = "68548570c38a021c724b5aa0112f45a54bdf7ff1b041a042848e034a95a96994" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.0", "futures", + "solana-account", "solana-banks-interface", - "solana-program", - "solana-sdk", + "solana-clock", + "solana-commitment-config", + "solana-hash", + "solana-message", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-signature", + "solana-sysvar", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", "tarpc", - "thiserror 2.0.12", + "thiserror 2.0.18", "tokio", "tokio-serde", ] [[package]] name = "solana-banks-interface" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54bdc2f951d900289a3de58f8fc835fcea67fdaaea390b447e16a8a403a2399" +checksum = "a6d90edc435bf488ef7abed4dcb1f94fa1970102cbabb25688f58417fd948286" dependencies = [ "serde", "serde_derive", - "solana-sdk", + "solana-account", + "solana-clock", + "solana-commitment-config", + "solana-hash", + "solana-message", + "solana-pubkey", + "solana-signature", + "solana-transaction", + "solana-transaction-context", + "solana-transaction-error", "tarpc", ] @@ -5453,9 +4790,9 @@ dependencies = [ [[package]] name = "solana-bn254" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9abc69625158faaab02347370b91c0d8e0fe347bf9287239f0fbe8f5864d91da" +checksum = "4420f125118732833f36facf96a27e7b78314b2d642ba07fa9ffdacd8d79e243" dependencies = [ "ark-bn254 0.4.0", "ark-ec 0.4.2", @@ -5463,7 +4800,7 @@ dependencies = [ "ark-serialize 0.4.2", "bytemuck", "solana-define-syscall", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -5473,17 +4810,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" dependencies = [ "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.0", ] [[package]] name = "solana-bpf-loader-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6931e8893b48e3a1c8124938f580fff857d84895582578cc7dbf100dd08d2c8f" +checksum = "b5aec57dcd80d0f6879956cad28854a6eebaed6b346ce56908ea01a9f36ab259" dependencies = [ "bincode", "libsecp256k1", + "num-traits", "qualifier_attr", "scopeguard", "solana-account", @@ -5493,10 +4831,8 @@ dependencies = [ "solana-blake3-hasher", "solana-bn254", "solana-clock", - "solana-compute-budget", "solana-cpi", "solana-curve25519", - "solana-feature-set", "solana-hash", "solana-instruction", "solana-keccak-hasher", @@ -5506,9 +4842,7 @@ dependencies = [ "solana-measure", "solana-packet", "solana-poseidon", - "solana-precompiles", "solana-program-entrypoint", - "solana-program-memory", "solana-program-runtime", "solana-pubkey", "solana-sbpf", @@ -5516,26 +4850,26 @@ dependencies = [ "solana-secp256k1-recover", "solana-sha256-hasher", "solana-stable-layout", + "solana-svm-feature-set", "solana-system-interface", "solana-sysvar", "solana-sysvar-id", "solana-timings", "solana-transaction-context", "solana-type-overrides", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "solana-builtins" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9240641f944ece59e097c9981bdc33b2f519cbd91b9764ff5f62c307d986a3d" +checksum = "6d61a31b63b52b0d268cbcd56c76f50314867d7f8e07a0f2c62ee7c9886e07b2" dependencies = [ - "solana-address-lookup-table-program", + "agave-feature-set", "solana-bpf-loader-program", "solana-compute-budget-program", - "solana-config-program", - "solana-feature-set", + "solana-hash", "solana-loader-v4-program", "solana-program-runtime", "solana-pubkey", @@ -5549,19 +4883,15 @@ dependencies = [ [[package]] name = "solana-builtins-default-costs" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fb6728141dc45bdde9d68b67bb914013be28f94a2aea8bb7131ea8c6161c30e" +checksum = "2ca69a299a6c969b18ea381a02b40c9e4dda04b2af0d15a007c1184c82163bbb" dependencies = [ + "agave-feature-set", "ahash", - "lazy_static", "log", - "qualifier_attr", - "solana-address-lookup-table-program", "solana-bpf-loader-program", "solana-compute-budget-program", - "solana-config-program", - "solana-feature-set", "solana-loader-v4-program", "solana-pubkey", "solana-sdk-ids", @@ -5570,52 +4900,6 @@ dependencies = [ "solana-vote-program", ] -[[package]] -name = "solana-client" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e827416867d988cbba327b6e448ad0bfb85ba44f080c6a02a00aa498c2249c4" -dependencies = [ - "async-trait", - "bincode", - "dashmap", - "futures", - "futures-util", - "indexmap 2.10.0", - "indicatif", - "log", - "quinn", - "rayon", - "solana-account", - "solana-client-traits", - "solana-commitment-config", - "solana-connection-cache", - "solana-epoch-info", - "solana-hash", - "solana-instruction", - "solana-keypair", - "solana-measure", - "solana-message", - "solana-pubkey", - "solana-pubsub-client", - "solana-quic-client", - "solana-quic-definitions", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-rpc-client-nonce-utils", - "solana-signature", - "solana-signer", - "solana-streamer", - "solana-thin-client", - "solana-time-utils", - "solana-tpu-client", - "solana-transaction", - "solana-transaction-error", - "solana-udp-client", - "thiserror 2.0.12", - "tokio", -] - [[package]] name = "solana-client-traits" version = "2.2.1" @@ -5639,9 +4923,9 @@ dependencies = [ [[package]] name = "solana-clock" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c2177a1b9fe8326004f1151a5acd124420b737811080b1035df31349e4d892" +checksum = "1bb482ab70fced82ad3d7d3d87be33d466a3498eb8aa856434ff3c0dfc2e2e31" dependencies = [ "serde", "serde_derive", @@ -5673,42 +4957,42 @@ dependencies = [ [[package]] name = "solana-compute-budget" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e593ce26764fa3366b6d125b9f2455f6cd8d557f86b4f3c7b7c517db6d8f5f" +checksum = "9f4fc63bc2276a1618ca0bfc609da7448534ecb43a1cb387cdf9eaa2dc7bc272" dependencies = [ "solana-fee-structure", - "solana-program-entrypoint", + "solana-program-runtime", ] [[package]] name = "solana-compute-budget-instruction" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "240e28cf764d1468f2388fb0d10b70278a64d47277ff552379116ba45d609cd1" +checksum = "503d94430f6d3c5ac1e1fa6a342c1c714d5b03c800999e7b6cf235298f0b5341" dependencies = [ + "agave-feature-set", "log", "solana-borsh", "solana-builtins-default-costs", "solana-compute-budget", "solana-compute-budget-interface", - "solana-feature-set", "solana-instruction", "solana-packet", "solana-pubkey", "solana-sdk-ids", "solana-svm-transaction", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "solana-compute-budget-interface" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a5df17b195d312b66dccdde9beec6709766d8230cb4718c4c08854f780d0309" +checksum = "8432d2c4c22d0499aa06d62e4f7e333f81777b3d7c96050ae9e5cb71a8c3aee4" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.0", "serde", "serde_derive", "solana-instruction", @@ -5717,60 +5001,24 @@ dependencies = [ [[package]] name = "solana-compute-budget-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfc6b8ea70ed5123412655ed15e7e0e29f06a7d5b82eb2572bee608d7755afb7" +checksum = "072b02beed1862c6b7b7a8a699379594c4470a9371c711856a0a3c266dcf57e5" dependencies = [ - "qualifier_attr", "solana-program-runtime", ] [[package]] -name = "solana-config-program" -version = "2.2.4" +name = "solana-config-program-client" +version = "0.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2417094a8c5c2d60812a5bd6f0bd31bdefc49479826c10347a85d217e088c964" +checksum = "53aceac36f105fd4922e29b4f0c1f785b69d7b3e7e387e384b8985c8e0c3595e" dependencies = [ "bincode", - "chrono", + "borsh 0.10.4", + "kaigan", "serde", - "serde_derive", - "solana-account", - "solana-bincode", - "solana-instruction", - "solana-log-collector", - "solana-packet", - "solana-program-runtime", - "solana-pubkey", - "solana-sdk-ids", - "solana-short-vec", - "solana-stake-interface", - "solana-system-interface", - "solana-transaction-context", -] - -[[package]] -name = "solana-connection-cache" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55ad0b507b4044e2690915c9aa69eacfd51b1fa55e4deeca662ee5cff7d7d1f4" -dependencies = [ - "async-trait", - "bincode", - "crossbeam-channel", - "futures-util", - "indexmap 2.10.0", - "log", - "rand 0.8.5", - "rayon", - "solana-keypair", - "solana-measure", - "solana-metrics", - "solana-net-utils", - "solana-time-utils", - "solana-transaction-error", - "thiserror 2.0.12", - "tokio", + "solana-program", ] [[package]] @@ -5789,16 +5037,16 @@ dependencies = [ [[package]] name = "solana-curve25519" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b3d15f1a893ced38529d44d7fe0d4348dc38c28fea13b6d6be5d13d438a441f" +checksum = "eae4261b9a8613d10e77ac831a8fa60b6fa52b9b103df46d641deff9f9812a23" dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", "solana-define-syscall", "subtle", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -5812,9 +5060,9 @@ dependencies = [ [[package]] name = "solana-define-syscall" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf784bb2cb3e02cac9801813c30187344228d2ae952534902108f6150573a33d" +checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" [[package]] name = "solana-derivation-path" @@ -5872,7 +5120,7 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "96c5fd2662ae7574810904585fd443545ed2b568dbd304b25a31e79ccc76e81b" dependencies = [ - "siphasher 0.3.11", + "siphasher", "solana-hash", "solana-pubkey", ] @@ -5908,14 +5156,14 @@ dependencies = [ "solana-pubkey", "solana-sdk-ids", "solana-system-interface", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "solana-feature-gate-interface" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f9c7fbf3e58b64a667c5f35e90af580538a95daea7001ff7806c0662d301bdf" +checksum = "43f5c5382b449e8e4e3016fb05e418c53d57782d8b5c30aa372fc265654b956d" dependencies = [ "bincode", "serde", @@ -5932,9 +5180,9 @@ dependencies = [ [[package]] name = "solana-feature-set" -version = "2.2.1" +version = "2.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89e1d3b52b4a014efeaaab67f14e40af3972a4be61c523d612860db8e3145529" +checksum = "93b93971e289d6425f88e6e3cb6668c4b05df78b3c518c249be55ced8efd6b6d" dependencies = [ "ahash", "lazy_static", @@ -5946,11 +5194,11 @@ dependencies = [ [[package]] name = "solana-fee" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c14eaaa9d099e4510c9105522d97778cd66c3d401f0d68eebcf43179a1bf094" +checksum = "16beda37597046b1edd1cea6fa7caaed033c091f99ec783fe59c82828bc2adb8" dependencies = [ - "solana-feature-set", + "agave-feature-set", "solana-fee-structure", "solana-svm-transaction", ] @@ -5968,21 +5216,21 @@ dependencies = [ [[package]] name = "solana-fee-structure" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f45f94a88efdb512805563181dfa1c85c60a21b6e6d602bf24a2ea88f9399d6e" +checksum = "33adf673581c38e810bf618f745bf31b683a0a4a4377682e6aaac5d9a058dd4e" dependencies = [ "serde", "serde_derive", "solana-message", - "solana-native-token", + "solana-native-token 2.3.0", ] [[package]] name = "solana-genesis-config" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "968dabd2b92d57131473eddbd475339da530e14f54397386abf303de3a2595a2" +checksum = "b3725085d47b96d37fef07a29d78d2787fc89a0b9004c66eed7753d1e554989f" dependencies = [ "bincode", "chrono", @@ -5998,7 +5246,6 @@ dependencies = [ "solana-inflation", "solana-keypair", "solana-logger", - "solana-native-token", "solana-poh-config", "solana-pubkey", "solana-rent", @@ -6021,14 +5268,14 @@ dependencies = [ [[package]] name = "solana-hash" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf7bcb14392900fe02e4e34e90234fbf0c673d4e327888410ba99fa2ba0f4e99" +checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" dependencies = [ - "borsh 1.5.7", - "bs58", + "borsh 1.6.0", "bytemuck", "bytemuck_derive", + "five8", "js-sys", "serde", "serde_derive", @@ -6047,29 +5294,20 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "solana-inline-spl" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed78e6709851bb3fa8a0acb1ee40fbffa888049d042ca132d6ccb8e0b313ac72" -dependencies = [ - "bytemuck", - "solana-pubkey", -] - [[package]] name = "solana-instruction" -version = "2.2.1" +version = "2.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce496a475e5062ba5de97215ab39d9c358f9c9df4bb7f3a45a1f1a8bd9065ed" +checksum = "bab5682934bd1f65f8d2c16f21cb532526fcc1a09f796e2cacdb091eee5774ad" dependencies = [ "bincode", - "borsh 1.5.7", - "getrandom 0.2.16", + "borsh 1.6.0", + "getrandom 0.2.17", "js-sys", "num-traits", "serde", "serde_derive", + "serde_json", "solana-define-syscall", "solana-pubkey", "wasm-bindgen", @@ -6081,7 +5319,7 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" dependencies = [ - "bitflags 2.9.1", + "bitflags 2.10.0", "solana-account-info", "solana-instruction", "solana-program-error", @@ -6106,13 +5344,13 @@ dependencies = [ [[package]] name = "solana-keypair" -version = "2.2.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3dbb7042c2e0c561afa07242b2099d55c57bd1b1da3b6476932197d84e15e3e4" +checksum = "bd3f04aa1a05c535e93e121a95f66e7dcccf57e007282e8255535d24bf1e98bb" dependencies = [ - "bs58", "ed25519-dalek", "ed25519-dalek-bip32", + "five8", "rand 0.7.3", "solana-derivation-path", "solana-pubkey", @@ -6152,9 +5390,9 @@ dependencies = [ [[package]] name = "solana-loader-v3-interface" -version = "3.0.0" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" +checksum = "6f7162a05b8b0773156b443bccd674ea78bb9aa406325b467ea78c06c99a63a2" dependencies = [ "serde", "serde_bytes", @@ -6182,16 +5420,15 @@ dependencies = [ [[package]] name = "solana-loader-v4-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b0298bf161e18b146230b15e8fa57bd170a05342ab9c1fd996b0241c0f016c2" +checksum = "a6ab01855d851fa2fb6034b0d48de33d77d5c5f5fb4b0353d8e4a934cc03d48a" dependencies = [ "log", "qualifier_attr", "solana-account", "solana-bincode", "solana-bpf-loader-program", - "solana-compute-budget", "solana-instruction", "solana-loader-v3-interface", "solana-loader-v4-interface", @@ -6208,9 +5445,9 @@ dependencies = [ [[package]] name = "solana-log-collector" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d03bf4c676117575be755296e8f21233d74cd28dca227c42e97e86219a27193" +checksum = "9d945b1cf5bf7cbd6f5b78795beda7376370c827640df43bb2a1c17b492dc106" dependencies = [ "log", ] @@ -6230,15 +5467,15 @@ dependencies = [ [[package]] name = "solana-measure" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b17ee553110d2bfc454b8784840a4b75867e123d3816e13046989463fed2c6b" +checksum = "11dcd67cd2ae6065e494b64e861e0498d046d95a61cbbf1ae3d58be1ea0f42ed" [[package]] name = "solana-message" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "268486ba8a294ed22a4d7c1ec05f540c3dbe71cfa7c6c54b6d4d13668d895678" +checksum = "1796aabce376ff74bf89b78d268fa5e683d7d7a96a0a4e4813ec34de49d5314b" dependencies = [ "bincode", "blake3", @@ -6259,20 +5496,18 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98b79bd642efa8388791fef7a900bfeb48865669148d523fba041fa7e407312f" +checksum = "0375159d8460f423d39e5103dcff6e07796a5ec1850ee1fcfacfd2482a8f34b5" dependencies = [ "crossbeam-channel", "gethostname", - "lazy_static", "log", - "reqwest 0.11.27", - "solana-clock", + "reqwest 0.12.28", "solana-cluster-type", "solana-sha256-hasher", "solana-time-utils", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -6286,31 +5521,15 @@ dependencies = [ [[package]] name = "solana-native-token" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e9de00960197412e4be3902a6cd35e60817c511137aca6c34c66cd5d4017ec" +checksum = "61515b880c36974053dd499c0510066783f0cc6ac17def0c7ef2a244874cf4a9" [[package]] -name = "solana-net-utils" -version = "2.2.4" +name = "solana-native-token" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef9db57e121ca1577fb5578d916bed549632be0e54a2098e8325980ac724d283" -dependencies = [ - "anyhow", - "bincode", - "bytes", - "crossbeam-channel", - "itertools 0.12.1", - "log", - "nix", - "rand 0.8.5", - "serde", - "serde_derive", - "socket2 0.5.10", - "solana-serde", - "tokio", - "url", -] +checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" [[package]] name = "solana-nonce" @@ -6370,45 +5589,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "004f2d2daf407b3ec1a1ca5ec34b3ccdfd6866dd2d3c7d0715004a96e4b6d127" dependencies = [ "bincode", - "bitflags 2.9.1", + "bitflags 2.10.0", "cfg_eval", "serde", "serde_derive", "serde_with", ] -[[package]] -name = "solana-perf" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b87939c18937f8bfad6028779a02fa123b27e986fb2c55fbbf683952a0e4932" -dependencies = [ - "ahash", - "bincode", - "bv", - "caps", - "curve25519-dalek 4.1.3", - "dlopen2", - "fnv", - "lazy_static", - "libc", - "log", - "nix", - "rand 0.8.5", - "rayon", - "serde", - "solana-hash", - "solana-message", - "solana-metrics", - "solana-packet", - "solana-pubkey", - "solana-rayon-threadlimit", - "solana-sdk-ids", - "solana-short-vec", - "solana-signature", - "solana-time-utils", -] - [[package]] name = "solana-poh-config" version = "2.2.1" @@ -6421,14 +5608,14 @@ dependencies = [ [[package]] name = "solana-poseidon" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d2908b48b3828bc04b752d1ff36122f5a06de043258da88df5f8ce64791d208" +checksum = "cbac4eb90016eeb1d37fa36e592d3a64421510c49666f81020736611c319faff" dependencies = [ "ark-bn254 0.4.0", "light-poseidon 0.2.0", "solana-define-syscall", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -6443,9 +5630,9 @@ dependencies = [ [[package]] name = "solana-precompiles" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a460ab805ec063802105b463ecb5eb02c3ffe469e67a967eea8a6e778e0bc06" +checksum = "36e92768a57c652edb0f5d1b30a7d0bc64192139c517967c18600debe9ae3832" dependencies = [ "lazy_static", "solana-ed25519-program", @@ -6471,24 +5658,24 @@ dependencies = [ [[package]] name = "solana-program" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "586469467e93ceb79048f8d8e3a619bf61d05396ee7de95cb40280301a589d05" +checksum = "98eca145bd3545e2fbb07166e895370576e47a00a7d824e325390d33bf467210" dependencies = [ "bincode", "blake3", "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.0", "bs58", "bytemuck", "console_error_panic_hook", "console_log", - "getrandom 0.2.16", + "getrandom 0.2.17", "lazy_static", "log", "memoffset", "num-bigint 0.4.6", - "num-derive 0.4.2", + "num-derive", "num-traits", "rand 0.8.5", "serde", @@ -6520,7 +5707,7 @@ dependencies = [ "solana-loader-v4-interface", "solana-message", "solana-msg", - "solana-native-token", + "solana-native-token 2.3.0", "solana-nonce", "solana-program-entrypoint", "solana-program-error", @@ -6545,15 +5732,15 @@ dependencies = [ "solana-sysvar", "solana-sysvar-id", "solana-vote-interface", - "thiserror 2.0.12", + "thiserror 2.0.18", "wasm-bindgen", ] [[package]] name = "solana-program-entrypoint" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473ffe73c68d93e9f2aa726ad2985fe52760052709aaab188100a42c618060ec" +checksum = "32ce041b1a0ed275290a5008ee1a4a6c48f5054c8a3d78d313c08958a06aedbd" dependencies = [ "solana-account-info", "solana-msg", @@ -6567,7 +5754,7 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.0", "num-traits", "serde", "serde_derive", @@ -6579,11 +5766,10 @@ dependencies = [ [[package]] name = "solana-program-memory" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b0268f6c89825fb634a34bd0c3b8fdaeaecfc3728be1d622a8ee6dd577b60d4" +checksum = "3a5426090c6f3fd6cfdc10685322fede9ca8e5af43cd6a59e98bfe4e91671712" dependencies = [ - "num-traits", "solana-define-syscall", ] @@ -6604,9 +5790,9 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce0a9acc6049c2ae8a2a2dd0b63269ab1a6d8fab4dead1aae75a9bcdd4aa6f05" +checksum = "5653001e07b657c9de6f0417cf9add1cf4325903732c480d415655e10cc86704" dependencies = [ "base64 0.22.1", "bincode", @@ -6618,45 +5804,47 @@ dependencies = [ "serde", "solana-account", "solana-clock", - "solana-compute-budget", "solana-epoch-rewards", "solana-epoch-schedule", - "solana-feature-set", + "solana-fee-structure", "solana-hash", "solana-instruction", "solana-last-restart-slot", "solana-log-collector", "solana-measure", "solana-metrics", - "solana-precompiles", + "solana-program-entrypoint", "solana-pubkey", "solana-rent", "solana-sbpf", "solana-sdk-ids", "solana-slot-hashes", "solana-stable-layout", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-system-interface", "solana-sysvar", "solana-sysvar-id", "solana-timings", "solana-transaction-context", "solana-type-overrides", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "solana-pubkey" -version = "2.2.1" +version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40db1ff5a0f8aea2c158d78ab5f2cf897848964251d1df42fef78efd3c85b863" +checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" dependencies = [ "borsh 0.10.4", - "borsh 1.5.7", - "bs58", + "borsh 1.6.0", "bytemuck", "bytemuck_derive", "curve25519-dalek 4.1.3", + "five8", "five8_const", - "getrandom 0.2.16", + "getrandom 0.2.17", "js-sys", "num-traits", "rand 0.8.5", @@ -6670,83 +5858,15 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "solana-pubsub-client" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52d219147fd3a6753dc4819578fb6830c082a7c26b1559fab0f240fcf11f4e39" -dependencies = [ - "crossbeam-channel", - "futures-util", - "log", - "reqwest 0.11.27", - "semver", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder-client-types", - "solana-clock", - "solana-pubkey", - "solana-rpc-client-api", - "solana-signature", - "thiserror 2.0.12", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tungstenite", - "url", -] - -[[package]] -name = "solana-quic-client" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "769d66df4ab445ab689ab2c4f10135dfe80576859b4fea1cae7d9bdd7985e4e2" -dependencies = [ - "async-lock", - "async-trait", - "futures", - "itertools 0.12.1", - "lazy_static", - "log", - "quinn", - "quinn-proto", - "rustls 0.23.29", - "solana-connection-cache", - "solana-keypair", - "solana-measure", - "solana-metrics", - "solana-net-utils", - "solana-pubkey", - "solana-quic-definitions", - "solana-rpc-client-api", - "solana-signer", - "solana-streamer", - "solana-tls-utils", - "solana-transaction-error", - "thiserror 2.0.12", - "tokio", -] - [[package]] name = "solana-quic-definitions" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e606feac5110eb5d8afaa43ccaeea3ec49ccec36773387930b5ba545e745aea2" +checksum = "fbf0d4d5b049eb1d0c35f7b18f305a27c8986fc5c0c9b383e97adaa35334379e" dependencies = [ "solana-keypair", ] -[[package]] -name = "solana-rayon-threadlimit" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bf3ad7091b26c9bd0ebabff6ac4d825c88ecf2eafdb83de30dffda80ffc2f17" -dependencies = [ - "lazy_static", - "num_cpus", -] - [[package]] name = "solana-rent" version = "2.2.1" @@ -6762,9 +5882,9 @@ dependencies = [ [[package]] name = "solana-rent-collector" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c1e19f5d5108b0d824244425e43bc78bbb9476e2199e979b0230c9f632d3bf4" +checksum = "127e6dfa51e8c8ae3aa646d8b2672bc4ac901972a338a9e1cd249e030564fb9d" dependencies = [ "serde", "serde_derive", @@ -6789,9 +5909,9 @@ dependencies = [ [[package]] name = "solana-reserved-account-keys" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b293f4246626c0e0a991531f08848a713ada965612e99dc510963f04d12cae7" +checksum = "e4b22ea19ca2a3f28af7cd047c914abf833486bf7a7c4a10fc652fff09b385b1" dependencies = [ "lazy_static", "solana-feature-set", @@ -6811,17 +5931,18 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44f1809a424bb8d90aa40990451593cde7e734a060fb52b35e475db585450578" +checksum = "b8d3161ac0918178e674c1f7f1bfac40de3e7ed0383bd65747d63113c156eaeb" dependencies = [ "async-trait", "base64 0.22.1", "bincode", "bs58", + "futures", "indicatif", "log", - "reqwest 0.11.27", + "reqwest 0.12.28", "reqwest-middleware", "semver", "serde", @@ -6844,55 +5965,56 @@ dependencies = [ "solana-transaction-error", "solana-transaction-status-client-types", "solana-version", + "solana-vote-interface", "tokio", ] [[package]] name = "solana-rpc-client-api" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2eb4fe573cd2d59d8672f0d8ac65f64e70c948b36cf97218b9aeb80dca3329" +checksum = "2dbc138685c79d88a766a8fd825057a74ea7a21e1dd7f8de275ada899540fff7" dependencies = [ "anyhow", - "base64 0.22.1", - "bs58", "jsonrpc-core", - "reqwest 0.11.27", + "reqwest 0.12.28", "reqwest-middleware", - "semver", "serde", "serde_derive", "serde_json", - "solana-account", "solana-account-decoder-client-types", "solana-clock", - "solana-commitment-config", - "solana-fee-calculator", - "solana-inflation", - "solana-inline-spl", - "solana-pubkey", + "solana-rpc-client-types", "solana-signer", "solana-transaction-error", "solana-transaction-status-client-types", - "solana-version", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] -name = "solana-rpc-client-nonce-utils" -version = "2.2.4" +name = "solana-rpc-client-types" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2712d22c58616762ad8e02fc18556eaf7be4104d5e56b11a2b8aa892c7de2a08" +checksum = "8ea428a81729255d895ea47fba9b30fd4dacbfe571a080448121bd0592751676" dependencies = [ + "base64 0.22.1", + "bs58", + "semver", + "serde", + "serde_derive", + "serde_json", "solana-account", + "solana-account-decoder-client-types", + "solana-clock", "solana-commitment-config", - "solana-hash", - "solana-message", - "solana-nonce", + "solana-fee-calculator", + "solana-inflation", "solana-pubkey", - "solana-rpc-client", - "solana-sdk-ids", - "thiserror 2.0.12", + "solana-transaction-error", + "solana-transaction-status-client-types", + "solana-version", + "spl-generic-token", + "thiserror 2.0.18", ] [[package]] @@ -6903,26 +6025,26 @@ checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" [[package]] name = "solana-sbpf" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a3ce7a0f4d6830124ceb2c263c36d1ee39444ec70146eb49b939e557e72b96" +checksum = "474a2d95dc819898ded08d24f29642d02189d3e1497bbb442a92a3997b7eb55f" dependencies = [ "byteorder", - "combine 3.8.1", + "combine", "hash32", "libc", "log", "rand 0.8.5", "rustc-demangle", - "thiserror 1.0.69", + "thiserror 2.0.18", "winapi", ] [[package]] name = "solana-sdk" -version = "2.2.1" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4808e8d7f3c931657e615042d4176b423e66f64dc99e3dc3c735a197e512029b" +checksum = "8cc0e4a7635b902791c44b6581bfb82f3ada32c5bc0929a64f39fe4bb384c86a" dependencies = [ "bincode", "bs58", @@ -6949,7 +6071,7 @@ dependencies = [ "solana-instruction", "solana-keypair", "solana-message", - "solana-native-token", + "solana-native-token 2.3.0", "solana-nonce-account", "solana-offchain-message", "solana-packet", @@ -6985,7 +6107,7 @@ dependencies = [ "solana-transaction-context", "solana-transaction-error", "solana-validator-exit", - "thiserror 2.0.12", + "thiserror 2.0.18", "wasm-bindgen", ] @@ -7007,14 +6129,14 @@ dependencies = [ "bs58", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "solana-secp256k1-program" -version = "2.2.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0a1caa972414cc78122c32bdae65ac5fe89df7db598585a5cde19d16a20280a" +checksum = "f19833e4bc21558fe9ec61f239553abe7d05224347b57d65c2218aeeb82d6149" dependencies = [ "bincode", "digest 0.10.7", @@ -7026,6 +6148,7 @@ dependencies = [ "solana-instruction", "solana-precompile-error", "solana-sdk-ids", + "solana-signature", ] [[package]] @@ -7034,17 +6157,17 @@ version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.0", "libsecp256k1", "solana-define-syscall", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "solana-secp256r1-program" -version = "2.2.3" +version = "2.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf903cbdc36a161533812f90acfccdb434ed48982bd5dd71f3217930572c4a80" +checksum = "ce0ae46da3071a900f02d367d99b2f3058fe2e90c5062ac50c4f20cfedad8f0f" dependencies = [ "bytemuck", "openssl", @@ -7056,9 +6179,12 @@ dependencies = [ [[package]] name = "solana-security-txt" -version = "1.1.1" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" +checksum = "156bb61a96c605fa124e052d630dba2f6fb57e08c7d15b757e1e958b3ed7b3fe" +dependencies = [ + "hashbrown 0.15.2", +] [[package]] name = "solana-seed-derivable" @@ -7091,9 +6217,9 @@ dependencies = [ [[package]] name = "solana-serde-varint" -version = "2.2.1" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bcc07d00200d82e6def2f7f7a45738e3406b17fe54a18adcf0defa16a97ccadb" +checksum = "2a7e155eba458ecfb0107b98236088c3764a09ddf0201ec29e52a0be40857113" dependencies = [ "serde", ] @@ -7111,9 +6237,9 @@ dependencies = [ [[package]] name = "solana-sha256-hasher" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0037386961c0d633421f53560ad7c80675c0447cba4d1bb66d60974dd486c7ea" +checksum = "5aa3feb32c28765f6aa1ce8f3feac30936f16c5c3f7eb73d63a5b8f6f8ecdc44" dependencies = [ "sha2 0.10.9", "solana-define-syscall", @@ -7142,12 +6268,12 @@ dependencies = [ [[package]] name = "solana-signature" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "47d251c8f3dc015f320b4161daac7f108156c837428e5a8cc61136d25beb11d6" +checksum = "64c8ec8e657aecfc187522fc67495142c12f35e55ddeca8698edbb738b8dbd8c" dependencies = [ - "bs58", "ed25519-dalek", + "five8", "rand 0.8.5", "serde", "serde-big-array", @@ -7209,7 +6335,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" dependencies = [ "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.0", "num-traits", "serde", "serde_derive", @@ -7225,21 +6351,21 @@ dependencies = [ [[package]] name = "solana-stake-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b140dad8a60e40c381a0a359a350d37d51827d02ceb623acf8b942c04f3f3e6" +checksum = "500e9b9d11573f12de91e94f9c4459882cd5ffc692776af49b610d6fcc0b167f" dependencies = [ + "agave-feature-set", "bincode", "log", "solana-account", "solana-bincode", "solana-clock", - "solana-config-program", - "solana-feature-set", + "solana-config-program-client", "solana-genesis-config", "solana-instruction", "solana-log-collector", - "solana-native-token", + "solana-native-token 2.3.0", "solana-packet", "solana-program-runtime", "solana-pubkey", @@ -7253,57 +6379,27 @@ dependencies = [ ] [[package]] -name = "solana-streamer" -version = "2.2.4" +name = "solana-svm-callback" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8251a832b9f849e32266e2ebc14dba374c6c58d64e8b1ea9e9d95e836a53fe6" +checksum = "7cef9f7d5cfb5d375081a6c8ad712a6f0e055a15890081f845acf55d8254a7a2" dependencies = [ - "async-channel", - "bytes", - "crossbeam-channel", - "dashmap", - "futures", - "futures-util", - "governor", - "histogram", - "indexmap 2.10.0", - "itertools 0.12.1", - "libc", - "log", - "nix", - "pem", - "percentage", - "quinn", - "quinn-proto", - "rand 0.8.5", - "rustls 0.23.29", - "smallvec", - "socket2 0.5.10", - "solana-keypair", - "solana-measure", - "solana-metrics", - "solana-net-utils", - "solana-packet", - "solana-perf", + "solana-account", + "solana-precompile-error", "solana-pubkey", - "solana-quic-definitions", - "solana-signature", - "solana-signer", - "solana-time-utils", - "solana-tls-utils", - "solana-transaction-error", - "solana-transaction-metrics-tracker", - "thiserror 2.0.12", - "tokio", - "tokio-util 0.7.15", - "x509-parser", ] +[[package]] +name = "solana-svm-feature-set" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f24b836eb4d74ec255217bdbe0f24f64a07adeac31aca61f334f91cd4a3b1d5" + [[package]] name = "solana-svm-transaction" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1da9eb37e6ced0215a5e44df4ed1f3b885cf349156cbbf99197680cb7eaccf5f" +checksum = "ab717b9539375ebb088872c6c87d1d8832d19f30f154ecc530154d23f60a6f0c" dependencies = [ "solana-hash", "solana-message", @@ -7331,9 +6427,9 @@ dependencies = [ [[package]] name = "solana-system-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6321fd5380961387ef4633a98c109ac7f978667ceab2a38d0a699d6ddb2fc57a" +checksum = "23ca36cef39aea7761be58d4108a56a2e27042fb1e913355fdb142a05fc7eab7" dependencies = [ "bincode", "log", @@ -7341,6 +6437,7 @@ dependencies = [ "serde_derive", "solana-account", "solana-bincode", + "solana-fee-calculator", "solana-instruction", "solana-log-collector", "solana-nonce", @@ -7372,9 +6469,9 @@ dependencies = [ [[package]] name = "solana-sysvar" -version = "2.2.1" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf6b44740d7f0c9f375d045c165bc0aab4a90658f92d6835aeb0649afaeaff9a" +checksum = "b8c3595f95069f3d90f275bb9bd235a1973c4d059028b0a7f81baca2703815db" dependencies = [ "base64 0.22.1", "bincode", @@ -7417,35 +6514,6 @@ dependencies = [ "solana-sdk-ids", ] -[[package]] -name = "solana-thin-client" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61f6e417c23af670d7861ef74feae3c556d47ea9e5f64c664cfcf6d254f43e1a" -dependencies = [ - "bincode", - "log", - "rayon", - "solana-account", - "solana-client-traits", - "solana-clock", - "solana-commitment-config", - "solana-connection-cache", - "solana-epoch-info", - "solana-hash", - "solana-instruction", - "solana-keypair", - "solana-message", - "solana-pubkey", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-signature", - "solana-signer", - "solana-system-interface", - "solana-transaction", - "solana-transaction-error", -] - [[package]] name = "solana-time-utils" version = "2.2.1" @@ -7454,67 +6522,20 @@ checksum = "6af261afb0e8c39252a04d026e3ea9c405342b08c871a2ad8aa5448e068c784c" [[package]] name = "solana-timings" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "224f93327d9d3178a30cd6c057e1ac6ca85e95287dd7355064dfa6b9c49f5671" +checksum = "7c49b842dfc53c1bf9007eaa6730296dea93b4fce73f457ce1080af43375c0d6" dependencies = [ "eager", "enum-iterator", "solana-pubkey", ] -[[package]] -name = "solana-tls-utils" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec21c6c242ee93642aa50b829f5727470cdbdf6b461fb7323fe4bc31d1b54c08" -dependencies = [ - "rustls 0.23.29", - "solana-keypair", - "solana-pubkey", - "solana-signer", - "x509-parser", -] - -[[package]] -name = "solana-tpu-client" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "637e3ff3c8ece22043d96758f980d95558d50792d827d1457c2e06d9daaa7ff5" -dependencies = [ - "async-trait", - "bincode", - "futures-util", - "indexmap 2.10.0", - "indicatif", - "log", - "rayon", - "solana-client-traits", - "solana-clock", - "solana-commitment-config", - "solana-connection-cache", - "solana-epoch-info", - "solana-measure", - "solana-message", - "solana-net-utils", - "solana-pubkey", - "solana-pubsub-client", - "solana-quic-definitions", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-signature", - "solana-signer", - "solana-transaction", - "solana-transaction-error", - "thiserror 2.0.12", - "tokio", -] - [[package]] name = "solana-transaction" -version = "2.2.1" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "753b3e9afed170e4cfc0ea1e87b5dfdc6d4a50270869414edd24c6ea1f529b29" +checksum = "80657d6088f721148f5d889c828ca60c7daeedac9a8679f9ec215e0c42bcbf41" dependencies = [ "bincode", "serde", @@ -7527,7 +6548,6 @@ dependencies = [ "solana-message", "solana-precompiles", "solana-pubkey", - "solana-reserved-account-keys", "solana-sanitize", "solana-sdk-ids", "solana-short-vec", @@ -7540,18 +6560,19 @@ dependencies = [ [[package]] name = "solana-transaction-context" -version = "2.2.1" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5022de04cbba05377f68bf848c8c1322ead733f88a657bf792bb40f3257b8218" +checksum = "54a312304361987a85b2ef2293920558e6612876a639dd1309daf6d0d59ef2fe" dependencies = [ "bincode", "serde", "serde_derive", "solana-account", "solana-instruction", + "solana-instructions-sysvar", "solana-pubkey", "solana-rent", - "solana-signature", + "solana-sdk-ids", ] [[package]] @@ -7566,69 +6587,55 @@ dependencies = [ "solana-sanitize", ] -[[package]] -name = "solana-transaction-metrics-tracker" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58e40670c0780af24e73551be1fadf2306f61ed13f538ff3933846dab813b06d" -dependencies = [ - "base64 0.22.1", - "bincode", - "lazy_static", - "log", - "rand 0.8.5", - "solana-packet", - "solana-perf", - "solana-short-vec", - "solana-signature", -] - [[package]] name = "solana-transaction-status" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e05fc20dd8feb089562b113a80115dab32b22fc64d63ca45c14d7b71e5e98d67" +checksum = "135f92f4192cc68900c665becf97fc0a6500ae5a67ff347bf2cbc20ecfefa821" dependencies = [ "Inflector", + "agave-reserved-account-keys", "base64 0.22.1", "bincode", - "borsh 1.5.7", + "borsh 1.6.0", "bs58", - "lazy_static", "log", "serde", "serde_derive", "serde_json", "solana-account-decoder", + "solana-address-lookup-table-interface", "solana-clock", "solana-hash", "solana-instruction", "solana-loader-v2-interface", + "solana-loader-v3-interface", "solana-message", - "solana-program", + "solana-program-option", "solana-pubkey", - "solana-reserved-account-keys", "solana-reward-info", "solana-sdk-ids", "solana-signature", + "solana-stake-interface", "solana-system-interface", "solana-transaction", "solana-transaction-error", "solana-transaction-status-client-types", - "spl-associated-token-account", + "solana-vote-interface", + "spl-associated-token-account 7.0.0", "spl-memo", - "spl-token", - "spl-token-2022 7.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-group-interface", - "spl-token-metadata-interface", - "thiserror 2.0.12", + "spl-token 8.0.0", + "spl-token-2022 8.0.1", + "spl-token-group-interface 0.6.0", + "spl-token-metadata-interface 0.7.0", + "thiserror 2.0.18", ] [[package]] name = "solana-transaction-status-client-types" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1458fc750d0df4439bb4c1b418a4fe61afbd2e83963e452256eca99dc0c1cf76" +checksum = "51f1d7c2387c35850848212244d2b225847666cb52d3bd59a5c409d2c300303d" dependencies = [ "base64 0.22.1", "bincode", @@ -7644,35 +6651,18 @@ dependencies = [ "solana-transaction", "solana-transaction-context", "solana-transaction-error", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "solana-type-overrides" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d26d927bf3ed2f2b6b06a0f409dd8d6b1ad1af73cbba337e9471d05d42f026c9" +checksum = "41d80c44761eb398a157d809a04840865c347e1831ae3859b6100c0ee457bc1a" dependencies = [ - "lazy_static", "rand 0.8.5", ] -[[package]] -name = "solana-udp-client" -version = "2.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c37955cc627be2745e29ce326fd1b51739e499445b5e2b5fec687ed8ec581e34" -dependencies = [ - "async-trait", - "solana-connection-cache", - "solana-keypair", - "solana-net-utils", - "solana-streamer", - "solana-transaction-error", - "thiserror 2.0.12", - "tokio", -] - [[package]] name = "solana-validator-exit" version = "2.2.1" @@ -7681,26 +6671,27 @@ checksum = "7bbf6d7a3c0b28dd5335c52c0e9eae49d0ae489a8f324917faf0ded65a812c1d" [[package]] name = "solana-version" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374dea09855d46655c776256dda9cc3c854cc70fd923ef22ba0805bc83ca7bfd" +checksum = "3324d46c7f7b7f5d34bf7dc71a2883bdc072c7b28ca81d0b2167ecec4cf8da9f" dependencies = [ + "agave-feature-set", + "rand 0.8.5", "semver", "serde", "serde_derive", - "solana-feature-set", "solana-sanitize", "solana-serde-varint", ] [[package]] name = "solana-vote-interface" -version = "2.2.1" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4507bb9d071fb81cfcf676f12fba3db4098f764524ef0b5567d671a81d41f3e" +checksum = "b80d57478d6599d30acc31cc5ae7f93ec2361a06aefe8ea79bc81739a08af4c3" dependencies = [ "bincode", - "num-derive 0.4.2", + "num-derive", "num-traits", "serde", "serde_derive", @@ -7719,13 +6710,14 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0289c18977992907d361ca94c86cf45fd24cb41169fa03eb84947779e22933f" +checksum = "908d0e72c8b83e48762eb3e8c9114497cf4b1d66e506e360c46aba9308e71299" dependencies = [ + "agave-feature-set", "bincode", "log", - "num-derive 0.4.2", + "num-derive", "num-traits", "serde", "serde_derive", @@ -7733,7 +6725,6 @@ dependencies = [ "solana-bincode", "solana-clock", "solana-epoch-schedule", - "solana-feature-set", "solana-hash", "solana-instruction", "solana-keypair", @@ -7748,17 +6739,18 @@ dependencies = [ "solana-transaction", "solana-transaction-context", "solana-vote-interface", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "solana-zk-elgamal-proof-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a96b0ad864cc4d2156dbf0c4d7cadac4140ae13ebf7e856241500f74eca46f4" +checksum = "70cea14481d8efede6b115a2581f27bc7c6fdfba0752c20398456c3ac1245fc4" dependencies = [ + "agave-feature-set", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "solana-instruction", "solana-log-collector", @@ -7769,9 +6761,9 @@ dependencies = [ [[package]] name = "solana-zk-sdk" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "71db02a2e496c58840077c96dd4ede61894a4e6053853cca6dcddbb73200fb77" +checksum = "97b9fc6ec37d16d0dccff708ed1dd6ea9ba61796700c3bb7c3b401973f10f63b" dependencies = [ "aes-gcm-siv", "base64 0.22.1", @@ -7781,9 +6773,8 @@ dependencies = [ "curve25519-dalek 4.1.3", "itertools 0.12.1", "js-sys", - "lazy_static", "merlin", - "num-derive 0.4.2", + "num-derive", "num-traits", "rand 0.8.5", "serde", @@ -7799,21 +6790,21 @@ dependencies = [ "solana-signature", "solana-signer", "subtle", - "thiserror 2.0.12", + "thiserror 2.0.18", "wasm-bindgen", "zeroize", ] [[package]] name = "solana-zk-token-proof-program" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c540a4f7df1300dc6087f0cbb271b620dd55e131ea26075bb52ba999be3105f0" +checksum = "579752ad6ea2a671995f13c763bf28288c3c895cb857a518cc4ebab93c9a8dde" dependencies = [ + "agave-feature-set", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", - "solana-feature-set", "solana-instruction", "solana-log-collector", "solana-program-runtime", @@ -7823,9 +6814,9 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "2.2.4" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c4debebedfebfd4a188a7ac3dd0a56e86368417c35891d6f3c35550b46bfbc0" +checksum = "5055e5df94abd5badf4f947681c893375bdb6f8f543c05d2a7ab9647a6a9d205" dependencies = [ "aes-gcm-siv", "base64 0.22.1", @@ -7834,9 +6825,8 @@ dependencies = [ "bytemuck_derive", "curve25519-dalek 4.1.3", "itertools 0.12.1", - "lazy_static", "merlin", - "num-derive 0.4.2", + "num-derive", "num-traits", "rand 0.8.5", "serde", @@ -7853,33 +6843,40 @@ dependencies = [ "solana-signature", "solana-signer", "subtle", - "thiserror 2.0.12", + "thiserror 2.0.18", "zeroize", ] [[package]] -name = "spinning_top" -version = "0.3.0" +name = "spl-associated-token-account" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" +checksum = "76fee7d65013667032d499adc3c895e286197a35a0d3a4643c80e7fd3e9969e3" dependencies = [ - "lock_api", + "borsh 1.6.0", + "num-derive", + "num-traits", + "solana-program", + "spl-associated-token-account-client", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "thiserror 1.0.69", ] [[package]] name = "spl-associated-token-account" -version = "6.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76fee7d65013667032d499adc3c895e286197a35a0d3a4643c80e7fd3e9969e3" +checksum = "ae179d4a26b3c7a20c839898e6aed84cb4477adf108a366c95532f058aea041b" dependencies = [ - "borsh 1.5.7", - "num-derive 0.4.2", + "borsh 1.6.0", + "num-derive", "num-traits", "solana-program", "spl-associated-token-account-client", - "spl-token", - "spl-token-2022 6.0.0", - "thiserror 1.0.69", + "spl-token 8.0.0", + "spl-token-2022 8.0.1", + "thiserror 2.0.18", ] [[package]] @@ -7912,19 +6909,19 @@ checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "spl-discriminator-syn" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.104", + "syn 2.0.114", "thiserror 1.0.69", ] @@ -7938,19 +6935,40 @@ dependencies = [ "solana-program", "solana-zk-sdk", "spl-pod", - "spl-token-confidential-transfer-proof-extraction 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token-confidential-transfer-proof-extraction 0.2.1", ] [[package]] name = "spl-elgamal-registry" -version = "0.1.1" -source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65edfeed09cd4231e595616aa96022214f9c9d2be02dea62c2b30d5695a6833a" dependencies = [ "bytemuck", - "solana-program", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", + "solana-sysvar", "solana-zk-sdk", "spl-pod", - "spl-token-confidential-transfer-proof-extraction 0.2.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", + "spl-token-confidential-transfer-proof-extraction 0.3.0", +] + +[[package]] +name = "spl-generic-token" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "741a62a566d97c58d33f9ed32337ceedd4e35109a686e31b1866c5dfa56abddc" +dependencies = [ + "bytemuck", + "solana-pubkey", ] [[package]] @@ -7959,8 +6977,8 @@ version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5cc5a6cc7a4f0cf7813ce44153bba73280909f697d7f6baf7b9f223a255e7887" dependencies = [ - "borsh 1.5.7", - "num-derive 0.4.2", + "borsh 1.6.0", + "num-derive", "num-traits", "solana-program", "thiserror 1.0.69", @@ -7987,10 +7005,10 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.0", "bytemuck", "bytemuck_derive", - "num-derive 0.4.2", + "num-derive", "num-traits", "solana-decode-error", "solana-msg", @@ -7998,7 +7016,7 @@ dependencies = [ "solana-program-option", "solana-pubkey", "solana-zk-sdk", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -8007,13 +7025,28 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" dependencies = [ - "num-derive 0.4.2", + "num-derive", "num-traits", "solana-program", - "spl-program-error-derive", + "spl-program-error-derive 0.4.1", "thiserror 1.0.69", ] +[[package]] +name = "spl-program-error" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdebc8b42553070b75aa5106f071fef2eb798c64a7ec63375da4b1f058688c6" +dependencies = [ + "num-derive", + "num-traits", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-program-error-derive 0.5.0", + "thiserror 2.0.18", +] + [[package]] name = "spl-program-error-derive" version = "0.4.1" @@ -8023,7 +7056,19 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.104", + "syn 2.0.114", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a2539e259c66910d78593475540e8072f0b10f0f61d7607bbf7593899ed52d0" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.9", + "syn 2.0.114", ] [[package]] @@ -8033,7 +7078,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" dependencies = [ "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "solana-account-info", "solana-decode-error", @@ -8043,11 +7088,33 @@ dependencies = [ "solana-pubkey", "spl-discriminator", "spl-pod", - "spl-program-error", - "spl-type-length-value", + "spl-program-error 0.6.0", + "spl-type-length-value 0.7.0", "thiserror 1.0.69", ] +[[package]] +name = "spl-tlv-account-resolution" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1408e961215688715d5a1063cbdcf982de225c45f99c82b4f7d7e1dd22b998d7" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error 0.7.0", + "spl-type-length-value 0.8.0", + "thiserror 2.0.18", +] + [[package]] name = "spl-token" version = "7.0.0" @@ -8056,13 +7123,41 @@ checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "num_enum", "solana-program", "thiserror 1.0.69", ] +[[package]] +name = "spl-token" +version = "8.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053067c6a82c705004f91dae058b11b4780407e9ccd6799dc9e7d0fab5f242da" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-sysvar", + "thiserror 2.0.18", +] + [[package]] name = "spl-token-2022" version = "6.0.0" @@ -8071,23 +7166,23 @@ checksum = "5b27f7405010ef816587c944536b0eafbcc35206ab6ba0f2ca79f1d28e488f4f" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "num_enum", "solana-program", "solana-security-txt", "solana-zk-sdk", - "spl-elgamal-registry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-elgamal-registry 0.1.1", "spl-memo", "spl-pod", - "spl-token", - "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-confidential-transfer-proof-extraction 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-token 7.0.0", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1", + "spl-token-confidential-transfer-proof-extraction 0.2.1", "spl-token-confidential-transfer-proof-generation 0.2.0", - "spl-token-group-interface", - "spl-token-metadata-interface", - "spl-transfer-hook-interface", - "spl-type-length-value", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", + "spl-transfer-hook-interface 0.9.0", + "spl-type-length-value 0.7.0", "thiserror 1.0.69", ] @@ -8099,51 +7194,68 @@ checksum = "9048b26b0df0290f929ff91317c83db28b3ef99af2b3493dd35baa146774924c" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "num_enum", "solana-program", "solana-security-txt", "solana-zk-sdk", - "spl-elgamal-registry 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "spl-elgamal-registry 0.1.1", "spl-memo", "spl-pod", - "spl-token", - "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-confidential-transfer-proof-extraction 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-confidential-transfer-proof-generation 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "spl-token-group-interface", - "spl-token-metadata-interface", - "spl-transfer-hook-interface", - "spl-type-length-value", - "thiserror 2.0.12", + "spl-token 7.0.0", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1", + "spl-token-confidential-transfer-proof-extraction 0.2.1", + "spl-token-confidential-transfer-proof-generation 0.3.0", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", + "spl-transfer-hook-interface 0.9.0", + "spl-type-length-value 0.7.0", + "thiserror 2.0.18", ] [[package]] name = "spl-token-2022" -version = "7.0.0" -source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +version = "8.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31f0dfbb079eebaee55e793e92ca5f433744f4b71ee04880bfd6beefba5973e5" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "num_enum", - "solana-program", + "solana-account-info", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-native-token 2.3.0", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", "solana-security-txt", + "solana-system-interface", + "solana-sysvar", "solana-zk-sdk", - "spl-elgamal-registry 0.1.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", + "spl-elgamal-registry 0.2.0", "spl-memo", "spl-pod", - "spl-token", - "spl-token-confidential-transfer-ciphertext-arithmetic 0.2.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", - "spl-token-confidential-transfer-proof-extraction 0.2.1 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", - "spl-token-confidential-transfer-proof-generation 0.3.0 (git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf)", - "spl-token-group-interface", - "spl-token-metadata-interface", - "spl-transfer-hook-interface", - "spl-type-length-value", - "thiserror 2.0.12", + "spl-token 8.0.0", + "spl-token-confidential-transfer-ciphertext-arithmetic 0.3.1", + "spl-token-confidential-transfer-proof-extraction 0.3.0", + "spl-token-confidential-transfer-proof-generation 0.4.1", + "spl-token-group-interface 0.6.0", + "spl-token-metadata-interface 0.7.0", + "spl-transfer-hook-interface 0.10.0", + "spl-type-length-value 0.8.0", + "thiserror 2.0.18", ] [[package]] @@ -8160,8 +7272,9 @@ dependencies = [ [[package]] name = "spl-token-confidential-transfer-ciphertext-arithmetic" -version = "0.2.1" -source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cddd52bfc0f1c677b41493dafa3f2dbbb4b47cf0990f08905429e19dc8289b35" dependencies = [ "base64 0.22.1", "bytemuck", @@ -8180,20 +7293,27 @@ dependencies = [ "solana-program", "solana-zk-sdk", "spl-pod", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "spl-token-confidential-transfer-proof-extraction" -version = "0.2.1" -source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe2629860ff04c17bafa9ba4bed8850a404ecac81074113e1f840dbd0ebb7bd6" dependencies = [ "bytemuck", + "solana-account-info", "solana-curve25519", - "solana-program", + "solana-instruction", + "solana-instructions-sysvar", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "solana-sdk-ids", "solana-zk-sdk", "spl-pod", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -8215,17 +7335,18 @@ checksum = "0e3597628b0d2fe94e7900fd17cdb4cfbb31ee35c66f82809d27d86e44b2848b" dependencies = [ "curve25519-dalek 4.1.3", "solana-zk-sdk", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] name = "spl-token-confidential-transfer-proof-generation" -version = "0.3.0" -source = "git+https://github.com/Lightprotocol/token-2022?rev=06d12f50a06db25d73857d253b9a82857d6f4cdf#06d12f50a06db25d73857d253b9a82857d6f4cdf" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa27b9174bea869a7ebf31e0be6890bce90b1a4288bc2bbf24bd413f80ae3fde" dependencies = [ "curve25519-dalek 4.1.3", "solana-zk-sdk", - "thiserror 2.0.12", + "thiserror 2.0.18", ] [[package]] @@ -8235,8 +7356,91 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" dependencies = [ "bytemuck", - "num-derive 0.4.2", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5597b4cd76f85ce7cd206045b7dc22da8c25516573d42d267c8d1fd128db5129" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +dependencies = [ + "borsh 1.6.0", + "num-derive", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "304d6e06f0de0c13a621464b1fd5d4b1bebf60d15ca71a44d3839958e0da16ee" +dependencies = [ + "borsh 1.6.0", + "num-derive", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value 0.8.0", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", "num-traits", + "solana-account-info", + "solana-cpi", "solana-decode-error", "solana-instruction", "solana-msg", @@ -8244,19 +7448,24 @@ dependencies = [ "solana-pubkey", "spl-discriminator", "spl-pod", + "spl-program-error 0.6.0", + "spl-tlv-account-resolution 0.9.0", + "spl-type-length-value 0.7.0", "thiserror 1.0.69", ] [[package]] -name = "spl-token-metadata-interface" -version = "0.6.0" +name = "spl-transfer-hook-interface" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +checksum = "a7e905b849b6aba63bde8c4badac944ebb6c8e6e14817029cbe1bc16829133bd" dependencies = [ - "borsh 1.5.7", - "num-derive 0.4.2", + "arrayref", + "bytemuck", + "num-derive", "num-traits", - "solana-borsh", + "solana-account-info", + "solana-cpi", "solana-decode-error", "solana-instruction", "solana-msg", @@ -8264,43 +7473,38 @@ dependencies = [ "solana-pubkey", "spl-discriminator", "spl-pod", - "spl-type-length-value", - "thiserror 1.0.69", + "spl-program-error 0.7.0", + "spl-tlv-account-resolution 0.10.0", + "spl-type-length-value 0.8.0", + "thiserror 2.0.18", ] [[package]] -name = "spl-transfer-hook-interface" -version = "0.9.0" +name = "spl-type-length-value" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" dependencies = [ - "arrayref", "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "solana-account-info", - "solana-cpi", "solana-decode-error", - "solana-instruction", "solana-msg", "solana-program-error", - "solana-pubkey", "spl-discriminator", "spl-pod", - "spl-program-error", - "spl-tlv-account-resolution", - "spl-type-length-value", "thiserror 1.0.69", ] [[package]] name = "spl-type-length-value" -version = "0.7.0" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" +checksum = "d417eb548214fa822d93f84444024b4e57c13ed6719d4dcc68eec24fb481e9f5" dependencies = [ "bytemuck", - "num-derive 0.4.2", + "num-derive", "num-traits", "solana-account-info", "solana-decode-error", @@ -8308,14 +7512,14 @@ dependencies = [ "solana-program-error", "spl-discriminator", "spl-pod", - "thiserror 1.0.69", + "thiserror 2.0.18", ] [[package]] name = "stable_deref_trait" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] name = "static_assertions" @@ -8348,9 +7552,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.104" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -8372,18 +7576,6 @@ dependencies = [ "futures-core", ] -[[package]] -name = "synstructure" -version = "0.12.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f36bdaa60a83aca3921b5259d5400cbf5e90fc51931376a9bd4a0eb79aa7210f" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.109", - "unicode-xid", -] - [[package]] name = "synstructure" version = "0.13.2" @@ -8392,7 +7584,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -8402,7 +7594,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" dependencies = [ "bitflags 1.3.2", - "core-foundation 0.9.4", + "core-foundation", "system-configuration-sys 0.5.0", ] @@ -8412,8 +7604,8 @@ version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" dependencies = [ - "bitflags 2.9.1", - "core-foundation 0.9.4", + "bitflags 2.10.0", + "core-foundation", "system-configuration-sys 0.6.0", ] @@ -8458,7 +7650,7 @@ dependencies = [ "proc-macro-error2", "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -8502,26 +7694,17 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "task-local-extensions" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba323866e5d033818e3240feeb9f7db2c4296674e4d9e16b97b7bf8f490434e8" -dependencies = [ - "pin-utils", -] - [[package]] name = "tempfile" -version = "3.20.0" +version = "3.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a64e3985349f2441a1a9ef0b853f869006c3855f2cda6862a94d26ebb9d6a1" +checksum = "655da9c7eb6305c55742045d5a8d2037996d61d8de95806335c7c86ce0f82e9c" dependencies = [ "fastrand", - "getrandom 0.3.3", + "getrandom 0.3.4", "once_cell", "rustix", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -8553,11 +7736,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "567b8a2dae586314f7be2a752ec7474332959c6460e02bde30d702a66d488708" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.12", + "thiserror-impl 2.0.18", ] [[package]] @@ -8568,18 +7751,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "thiserror-impl" -version = "2.0.12" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f7cf42b4507d8ea322120659672cf1b9dbb93f8f2d4ecfd6e51350ff5b17a1d" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -8593,30 +7776,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.41" +version = "0.3.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a7619e19bc266e0f9c5e6686659d394bc57973859340060a69221e57dbc0c40" +checksum = "f9e442fc33d7fdb45aa9bfeb312c095964abdf596f7567261062b2a7107aaabd" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.4" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e9a38711f559d9e3ce1cdb06dd7c5b8ea546bc90052da6d06bb76da74bb07c" +checksum = "8b36ee98fd31ec7426d599183e8fe26932a8dc1fb76ddb6214d05493377d34ca" [[package]] name = "time-macros" -version = "0.2.22" +version = "0.2.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3526739392ec93fd8b359c8e98514cb3e8e021beb4e5f597b00a0221f8ed8a49" +checksum = "71e552d1249bf61ac2a52db88179fd0673def1e1ad8243a00d9ec9ed71fee3dd" dependencies = [ "num-conv", "time-core", @@ -8624,9 +7807,9 @@ dependencies = [ [[package]] name = "tinystr" -version = "0.8.1" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d4f6d1145dcb577acf783d4e601bc1d76a13337bb54e6233add580b07344c8b" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" dependencies = [ "displaydoc", "zerovec", @@ -8634,9 +7817,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.9.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09b3661f17e86524eccd4371ab0429194e0d7c008abb45f7a7495b1719463c71" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" dependencies = [ "tinyvec_macros", ] @@ -8649,33 +7832,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.47.0" +version = "1.49.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43864ed400b6043a4757a25c7a64a8efde741aed79a056a2fb348a406701bb35" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" dependencies = [ - "backtrace", "bytes", - "io-uring", "libc", "mio", "parking_lot", "pin-project-lite", "signal-hook-registry", - "slab", - "socket2 0.6.0", + "socket2 0.6.1", "tokio-macros", - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.5.0" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e06d43f1345a3bcd39f6a56dbb7dcab2ba47e68e8ac134855e7e2bdbaf8cab8" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -8700,11 +7880,11 @@ dependencies = [ [[package]] name = "tokio-rustls" -version = "0.26.2" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e727b36a1a0e8b74c376ac2211e40c2c8af09fb4013c60d910495810f008e9b" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.29", + "rustls 0.23.36", "tokio", ] @@ -8724,32 +7904,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "tokio-stream" -version = "0.1.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" -dependencies = [ - "futures-core", - "pin-project-lite", - "tokio", -] - -[[package]] -name = "tokio-tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" -dependencies = [ - "futures-util", - "log", - "rustls 0.21.12", - "tokio", - "tokio-rustls 0.24.1", - "tungstenite", - "webpki-roots 0.25.4", -] - [[package]] name = "tokio-util" version = "0.6.10" @@ -8767,9 +7921,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.15" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66a539a9ad6d5d281510d5bd368c973d636c02dbf8a67300bfb6b950696ad7df" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -8795,8 +7949,8 @@ checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" dependencies = [ "serde", "serde_spanned", - "toml_datetime", - "toml_edit", + "toml_datetime 0.6.11", + "toml_edit 0.22.27", ] [[package]] @@ -8808,20 +7962,50 @@ dependencies = [ "serde", ] +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + [[package]] name = "toml_edit" version = "0.22.27" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" dependencies = [ - "indexmap 2.10.0", + "indexmap 2.13.0", "serde", "serde_spanned", - "toml_datetime", + "toml_datetime 0.6.11", "toml_write", "winnow", ] +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap 2.13.0", + "toml_datetime 0.7.5+spec-1.1.0", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.6+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3198b4b0a8e11f09dd03e133c0280504d0801269e9afa46362ffde1cbeebf44" +dependencies = [ + "winnow", +] + [[package]] name = "toml_write" version = "0.1.2" @@ -8830,9 +8014,9 @@ checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", @@ -8845,17 +8029,22 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.9.1", + "async-compression", + "bitflags 2.10.0", "bytes", + "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", + "http-body-util", "iri-string", "pin-project-lite", + "tokio", + "tokio-util 0.7.18", "tower", "tower-layer", "tower-service", @@ -8875,9 +8064,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -8887,20 +8076,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -8921,9 +8110,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.19" +version = "0.3.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008" +checksum = "2f30143827ddab0d256fd843b7a66d164e9f271cfa0dde49142c5ca0ca291f1e" dependencies = [ "sharded-slab", "thread_local", @@ -8936,32 +8125,11 @@ version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b" -[[package]] -name = "tungstenite" -version = "0.20.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e3dac10fd62eaf6617d3a904ae222845979aec67c615d1c842b4002c7666fb9" -dependencies = [ - "byteorder", - "bytes", - "data-encoding", - "http 0.2.12", - "httparse", - "log", - "rand 0.8.5", - "rustls 0.21.12", - "sha1", - "thiserror 1.0.69", - "url", - "utf-8", - "webpki-roots 0.24.0", -] - [[package]] name = "typenum" -version = "1.18.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "uint" @@ -8983,15 +8151,15 @@ checksum = "eaea85b334db583fe3274d12b4cd1880032beab409c0d774be044d4480ab9a94" [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-ident" -version = "1.0.18" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" [[package]] name = "unicode-segmentation" @@ -9001,15 +8169,9 @@ checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" [[package]] name = "unicode-width" -version = "0.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a1a07cc7db3810833284e8d372ccdc6da29741639ecc70c9ec107df0fa6154c" - -[[package]] -name = "unicode-xid" -version = "0.2.6" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "universal-hash" @@ -9048,42 +8210,31 @@ dependencies = [ [[package]] name = "url" -version = "2.5.4" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32f8b686cadd1473f4bd0117a5d28d36b1ade384ea9b5069a1c40aefed7fda60" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] -[[package]] -name = "utf-8" -version = "0.7.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" - [[package]] name = "utf8_iter" version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" -[[package]] -name = "utf8parse" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" - [[package]] name = "uuid" -version = "1.17.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cf4199d1e5d15ddd86a694e4d0dffa9c323ce759fea589f00fef9d81cc1931d" +checksum = "e2e054861b4bd027cd373e18e8d8d8e6548085000e41290d95ce0c373a654b4a" dependencies = [ - "getrandom 0.3.3", + "getrandom 0.3.4", "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -9120,16 +8271,6 @@ dependencies = [ "libc", ] -[[package]] -name = "walkdir" -version = "2.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" -dependencies = [ - "same-file", - "winapi-util", -] - [[package]] name = "want" version = "0.3.1" @@ -9152,47 +8293,35 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasi" -version = "0.14.2+wasi-0.2.4" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "wit-bindgen-rt", + "wit-bindgen", ] [[package]] name = "wasm-bindgen" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" dependencies = [ "cfg-if", "once_cell", "rustversion", "wasm-bindgen-macro", -] - -[[package]] -name = "wasm-bindgen-backend" -version = "0.2.100" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" -dependencies = [ - "bumpalo", - "log", - "proc-macro2", - "quote", - "syn 2.0.104", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.50" +version = "0.4.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "555d470ec0bc3bb57890405e5d4322cc9ea83cebb085523ced7be4144dac1e61" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -9201,9 +8330,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -9211,31 +8340,31 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.104", - "wasm-bindgen-backend", + "syn 2.0.114", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.100" +version = "0.2.108" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" dependencies = [ "unicode-ident", ] [[package]] name = "web-sys" -version = "0.3.77" +version = "0.3.85" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33b6dd2ef9186f1f2072e409e99cd22a975331a6b3591b12c764e0e55c60d5d2" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" dependencies = [ "js-sys", "wasm-bindgen", @@ -9251,33 +8380,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-root-certs" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75c7f0ef91146ebfb530314f5f1d24528d7f0767efbfd31dce919275413e393e" -dependencies = [ - "webpki-root-certs 1.0.2", -] - -[[package]] -name = "webpki-root-certs" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e4ffd8df1c57e87c325000a3d6ef93db75279dc3a231125aac571650f22b12a" -dependencies = [ - "rustls-pki-types", -] - -[[package]] -name = "webpki-roots" -version = "0.24.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" -dependencies = [ - "rustls-webpki 0.101.7", -] - [[package]] name = "webpki-roots" version = "0.25.4" @@ -9285,13 +8387,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" [[package]] -name = "wide" -version = "0.7.33" +name = "webpki-roots" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ce5da8ecb62bcd8ec8b7ea19f69a51275e91299be594ea5cc6ef7819e16cd03" +checksum = "12bed680863276c63889429bfd6cab3b99943659923822de1c8a39c49e4d722c" dependencies = [ - "bytemuck", - "safe_arch", + "rustls-pki-types", ] [[package]] @@ -9312,11 +8413,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.9" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf221c93e13a30d793f7645a0e7762c55d169dbb0a49671918a2319d289b10bb" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] @@ -9327,9 +8428,9 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "windows-core" -version = "0.61.2" +version = "0.62.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0fdd3ddb90610c7638aa2b3a3ab2904fb9e5cdbecc643ddb3647212781c4ae3" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" dependencies = [ "windows-implement", "windows-interface", @@ -9340,37 +8441,37 @@ dependencies = [ [[package]] name = "windows-implement" -version = "0.60.0" +version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "windows-interface" -version = "0.59.1" +version = "0.59.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "windows-link" -version = "0.1.3" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" [[package]] name = "windows-registry" -version = "0.5.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a9ed28765efc97bbc954883f4e6796c33a06546ebafacbabee9696967499e" +checksum = "02752bf7fbdcce7f2a27a742f798510f3e5ad88dbe84871e5168e2120c3d5720" dependencies = [ "windows-link", "windows-result", @@ -9379,31 +8480,22 @@ dependencies = [ [[package]] name = "windows-result" -version = "0.3.4" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f42bd332cc6c8eac5af113fc0c1fd6a8fd2aa08a0119358686e5160d0586c6" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" dependencies = [ "windows-link", ] [[package]] name = "windows-strings" -version = "0.4.2" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e6c93f3a0c3b36176cb1327a4958a0353d5d166c2a35cb268ace15e91d3b57" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ "windows-link", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -9437,22 +8529,16 @@ version = "0.60.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" dependencies = [ - "windows-targets 0.53.3", + "windows-targets 0.53.5", ] [[package]] -name = "windows-targets" -version = "0.42.2" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" 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-link", ] [[package]] @@ -9488,27 +8574,21 @@ dependencies = [ [[package]] name = "windows-targets" -version = "0.53.3" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ "windows-link", - "windows_aarch64_gnullvm 0.53.0", - "windows_aarch64_msvc 0.53.0", - "windows_i686_gnu 0.53.0", - "windows_i686_gnullvm 0.53.0", - "windows_i686_msvc 0.53.0", - "windows_x86_64_gnu 0.53.0", - "windows_x86_64_gnullvm 0.53.0", - "windows_x86_64_msvc 0.53.0", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.48.5" @@ -9523,15 +8603,9 @@ checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" - -[[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" @@ -9547,15 +8621,9 @@ checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_aarch64_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" - -[[package]] -name = "windows_i686_gnu" -version = "0.42.2" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" @@ -9571,9 +8639,9 @@ checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" [[package]] name = "windows_i686_gnu" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" [[package]] name = "windows_i686_gnullvm" @@ -9583,15 +8651,9 @@ checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" - -[[package]] -name = "windows_i686_msvc" -version = "0.42.2" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" @@ -9607,15 +8669,9 @@ checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_i686_msvc" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" - -[[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" @@ -9631,15 +8687,9 @@ checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnu" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" - -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" @@ -9655,15 +8705,9 @@ checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_gnullvm" -version = "0.53.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" - -[[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" @@ -9679,15 +8723,15 @@ checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] name = "windows_x86_64_msvc" -version = "0.53.0" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.7.12" +version = "0.7.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3edebf492c8125044983378ecb5766203ad3b4c2f7a922bd7dd207f6d443e95" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" dependencies = [ "memchr", ] @@ -9703,19 +8747,16 @@ dependencies = [ ] [[package]] -name = "wit-bindgen-rt" -version = "0.39.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" -dependencies = [ - "bitflags 2.9.1", -] +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" [[package]] name = "writeable" -version = "0.6.1" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea2f10b9bb0928dfb1b42b65e1f9e36f7f54dbdf08457afefb38afcdec4fa2bb" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" [[package]] name = "wyz" @@ -9726,31 +8767,12 @@ dependencies = [ "tap", ] -[[package]] -name = "x509-parser" -version = "0.14.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e0ecbeb7b67ce215e40e3cc7f2ff902f94a223acf44995934763467e7b1febc8" -dependencies = [ - "asn1-rs", - "base64 0.13.1", - "data-encoding", - "der-parser", - "lazy_static", - "nom", - "oid-registry", - "rusticata-macros", - "thiserror 1.0.69", - "time", -] - [[package]] name = "yoke" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f41bb01b8226ef4bfd589436a297c53d118f65921786300e427be8d487695cc" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" dependencies = [ - "serde", "stable_deref_trait", "yoke-derive", "zerofrom", @@ -9758,34 +8780,34 @@ dependencies = [ [[package]] name = "yoke-derive" -version = "0.8.0" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38da3c9736e16c5d3c8c597a9aaa5d1fa565d0532ae05e27c24aa62fb32c0ab6" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", - "synstructure 0.13.2", + "syn 2.0.114", + "synstructure", ] [[package]] name = "zerocopy" -version = "0.8.26" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "668f5168d10b9ee831de31933dc111a459c97ec93225beb307aed970d1372dfd" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.26" +version = "0.8.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "2c7962b26b0a8685668b671ee4b54d007a67d4eaf05fda79ac0ecf41e32270f1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] @@ -9805,35 +8827,35 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", - "synstructure 0.13.2", + "syn 2.0.114", + "synstructure", ] [[package]] name = "zeroize" -version = "1.8.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] [[package]] name = "zerotrie" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "36f0bbd478583f79edad978b407914f61b2972f5af6fa089686016be8f9af595" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" dependencies = [ "displaydoc", "yoke", @@ -9842,9 +8864,9 @@ dependencies = [ [[package]] name = "zerovec" -version = "0.11.2" +version = "0.11.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a05eb080e015ba39cc9e23bbe5e7fb04d5fb040350f99f34e338d5fdd294428" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" dependencies = [ "yoke", "zerofrom", @@ -9853,15 +8875,21 @@ dependencies = [ [[package]] name = "zerovec-derive" -version = "0.11.1" +version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b96237efa0c878c64bd89c436f661be4e46b2f3eff1ebb976f7ef2321d2f58f" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.104", + "syn 2.0.114", ] +[[package]] +name = "zmij" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2" + [[package]] name = "zstd" version = "0.13.3" @@ -9882,9 +8910,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.15+zstd.1.5.7" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb81183ddd97d0c74cedf1d50d85c8d08c1b8b68ee863bdee9e706eedba1a237" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", diff --git a/Cargo.toml b/Cargo.toml index 29273e1..172ad47 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [workspace] resolver = "2" -members = ["programs/*", "client"] +members = ["programs/*"] -# Force newer proc-macro2 version compatible with Rust 1.87 [workspace.dependencies] proc-macro2 = "1.0.95" @@ -13,4 +12,4 @@ codegen-units = 1 [profile.release.build-override] opt-level = 3 incremental = false -codegen-units = 1 \ No newline at end of file +codegen-units = 1 diff --git a/SECURITY.md b/SECURITY.md deleted file mode 100644 index 0d46f87..0000000 --- a/SECURITY.md +++ /dev/null @@ -1,82 +0,0 @@ -# Raydium CP-Swap (CPMM) Bug Bounty Program - -Raydium's full bug bounty program with ImmuneFi can be found at: https://immunefi.com/bounty/raydium/ - -## Rewards by Threat Level - -Rewards are distributed according to the impact of the vulnerability based on the Immunefi Vulnerability Severity Classification System V2.3. This is a simplified 5-level scale, focusing on the impact of the vulnerability reported. - -### Smart Contracts - -| Severity | Bounty | -| -------- | ------------------------- | -| Critical | USD 50,000 to USD 505,000 | -| High | USD 40,000 | -| Medium | USD 5,000 | - -All bug reports must include a Proof of Concept (PoC) demonstrating how the vulnerability can be exploited to impact an asset-in-scope to be eligible for a reward. Critical and High severity bug reports should also include a suggestion for a fix. Explanations and statements are not accepted as PoC and code is required. - -Rewards for critical smart contract bug reports will be further capped at 10% of direct funds at risk if the bug discovered is exploited. However, there is a minimum reward of USD 50,000. - -Bugs in `raydium-sdk` and other code outside of the smart contract will be assessed on a case-by-case basis. - -## Report Submission - -Please email security@reactorlabs.io with a detailed description of the attack vector. For high- and critical-severity reports, please include a proof of concept. We will reach back out within 24 hours with additional questions or next steps on the bug bounty. - -## Payout Information - -Payouts are handled by the Raydium team directly and are denominated in USD. Payouts can be done in RAY, SOL, or USDC. - -## Out of Scope & Rules - -The following vulnerabilities are excluded from the rewards for this bug bounty program: - -- Attacks that the reporter has already exploited themselves, leading to damage -- Attacks requiring access to leaked keys/credentials -- Attacks requiring access to privileged addresses (governance, strategist) -- Incorrect data supplied by third party oracles (not excluding oracle manipulation/flash loan attacks) -- Basic economic governance attacks (e.g. 51% attack) -- Lack of liquidity -- Best practice critiques -- Sybil attacks -- Centralization risks -- Any UI bugs -- Bugs in the core Solana runtime (please submit these to [Solana's bug bounty program](https://github.com/solana-labs/solana/security/policy)) -- Vulnerabilities that require a validator to execute them -- Vulnerabilities requiring access to privileged keys/credentials -- MEV vectors the team is already aware of - -## AMM Assets in Scope - -| Target | Type | -| ------------------------------------------------------------------------------------------------------------------------- | ------------------------------------- | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/lib.rs | Smart Contract - lib | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/error.rs | Smart Contract - error | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs | Smart Contract - collect_fund_fee | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs | Smart Contract - collect_protocol_fee | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/admin/create_config.rs | Smart Contract - create_config | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/admin/mod.rs | Smart Contract - admin mod | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/admin/update_config.rs | Smart Contract - update_config | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/admin/update_pool_status.rs | Smart Contract - update_pool_status | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/deposit.rs | Smart Contract - deposit | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/initialize.rs | Smart Contract - initialize | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/mod.rs | Smart Contract - instructions mod | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/swap_base_input.rs | Smart Contract - swap_base_input | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/swap_base_output.rs | Smart Contract - swap_base_output | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/instructions/withdraw.rs | Smart Contract - withdraw | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/states/config.rs | Smart Contract - config | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/states/events.rs | Smart Contract - events | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/states/mod.rs | Smart Contract - states mod | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/states/pool.rs | Smart Contract - pool | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/utils/math.rs | Smart Contract - math | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/utils/mod.rs | Smart Contract - utils mod | -| https://github.com/raydium-io/raydium-cp-swap/blob/master/programs/cp-swap/src/utils/token.rs | Smart Contract - utils token | - -## Additional Information - -A public testnet of Raydium's CPMM can be found at A public testnet of Raydium’s AMM can be found at https://explorer.solana.com/address/CPMDWBwJDtYax9qW7AyRuVC19Cc4L4Vcy4n2BHAbHkCW?cluster=devnet - -A public testnet of OpenBook's Central Limit Order Book can be found at https://explorer.solana.com/address/EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj - -If a Critical Impact can be caused to any other asset managed by Raydium that isn't on this table but for which the impact is in the Impacts in Scope section below, you are encouraged to submit it for consideration by the project. This only applies to Critical impacts. diff --git a/client/Cargo.toml b/client/Cargo.toml deleted file mode 100644 index 3308da6..0000000 --- a/client/Cargo.toml +++ /dev/null @@ -1,50 +0,0 @@ -[package] -name = "client" -version = "0.1.0" -edition = "2021" - -[features] -devnet = ["raydium-cp-swap/devnet"] -test-sbf = ["raydium-cp-swap/test-sbf"] - -[dependencies] -anchor-client = { version = "=0.31.1", features = ["async"] } -anchor-lang = { version = "=0.31.1" } -anchor-spl = { version = "=0.31.1", git = "https://github.com/lightprotocol/anchor", rev = "d8a2b3d9", features = ["memo", "metadata", "idl-build"] } - -raydium-cp-swap = { path = "../programs/cp-swap", features = [ - "no-entrypoint", - "client", - "idl-build", -] } -solana-sdk = "2.2" -solana-client = "2.2" -solana-message = "2.2" -solana-account-decoder = "2.2" -solana-transaction-status = "2.2" -clap = { version = "4.1.8", features = ["derive"] } -anyhow = "1.0.32" -rand = "0.9.0" -hex = "0.4.3" -configparser = "3.0.0" -serde_json = { version = "1.0.78" } -serde = { version = "1.0", features = ["derive"] } -arrayref = "0.3.7" -bs58 = { version = "0.5.0" } -bincode = { version = "1.3.3" } -borsh = { version = "1.5.7" } -regex = "1" -colorful = "0.3.2" -base64 = "0.21.0" -bytemuck = { version = "1.23.0", features = ["derive"] } -tokio = { version = "1.0", features = ["full"] } -futures = "0.3" - -light-program-test = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } -light-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } -light-compressible-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } -light-sdk = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor", "anchor-discriminator-compat", "v2"] } -light-compressed-account = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } -light-token-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3" } - - diff --git a/client/src/instructions/amm_instructions.rs b/client/src/instructions/amm_instructions.rs deleted file mode 100644 index 62080a4..0000000 --- a/client/src/instructions/amm_instructions.rs +++ /dev/null @@ -1,494 +0,0 @@ -use anchor_client::{Client, Cluster}; -use anchor_spl::{ - associated_token::spl_associated_token_account, memo::spl_memo, token::spl_token, - token_2022::spl_token_2022, -}; -use anyhow::Result; -use light_client::{ - indexer::{AddressWithTree, Indexer}, - rpc::{LightClient, Rpc}, -}; -use light_compressed_account::address::derive_address; -use light_sdk::{ - compressible::CompressibleConfig, - instruction::{PackedAccounts, SystemAccountMetaConfig}, -}; -use light_token_client::compressed_token::{self, derive_compressed_mint_address}; -use solana_sdk::{instruction::Instruction, pubkey::Pubkey, system_program, sysvar}; -use std::rc::Rc; - -use raydium_cp_swap::{accounts as raydium_cp_accounts, utils::POOL_STATE_CREATION_INDEX}; -use raydium_cp_swap::{ - instruction as raydium_cp_instructions, - utils::{LP_MINT_CREATION_INDEX, OBSERVATION_STATE_CREATION_INDEX}, -}; -use raydium_cp_swap::{ - states::{AMM_CONFIG_SEED, OBSERVATION_SEED, POOL_LP_MINT_SEED, POOL_SEED, POOL_VAULT_SEED}, - AUTH_SEED, -}; - -use super::super::{read_keypair_file, ClientConfig}; - -pub async fn initialize_pool_instr( - light_client: &mut LightClient, - config: &ClientConfig, - token_0_mint: Pubkey, - token_1_mint: Pubkey, - token_0_program: Pubkey, - token_1_program: Pubkey, - user_token_0_account: Pubkey, - user_token_1_account: Pubkey, - create_pool_fee: Pubkey, - random_pool_id: Option, - init_amount_0: u64, - init_amount_1: u64, - open_time: u64, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - - let client = Client::new(url, Rc::new(payer)); - let program = client.program(config.raydium_cp_program)?; - - let amm_config_index = 0u16; - let (amm_config_key, __bump) = Pubkey::find_program_address( - &[AMM_CONFIG_SEED.as_bytes(), &amm_config_index.to_be_bytes()], - &program.id(), - ); - - let pool_account_key = if random_pool_id.is_some() { - random_pool_id.unwrap() - } else { - Pubkey::find_program_address( - &[ - POOL_SEED.as_bytes(), - amm_config_key.to_bytes().as_ref(), - token_0_mint.to_bytes().as_ref(), - token_1_mint.to_bytes().as_ref(), - ], - &program.id(), - ) - .0 - }; - - let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); - - let (token_0_vault, __bump) = Pubkey::find_program_address( - &[ - POOL_VAULT_SEED.as_bytes(), - pool_account_key.to_bytes().as_ref(), - token_0_mint.to_bytes().as_ref(), - ], - &program.id(), - ); - let (token_1_vault, __bump) = Pubkey::find_program_address( - &[ - POOL_VAULT_SEED.as_bytes(), - pool_account_key.to_bytes().as_ref(), - token_1_mint.to_bytes().as_ref(), - ], - &program.id(), - ); - - let (lp_mint_signer, _lp_mint_signer_bump) = Pubkey::find_program_address( - &[ - POOL_LP_MINT_SEED.as_bytes(), - pool_account_key.to_bytes().as_ref(), - ], - &program.id(), - ); - - let (lp_mint_key, lp_mint_bump) = compressed_token::find_mint_address(lp_mint_signer); - - let (lp_vault, __bump) = Pubkey::find_program_address( - &[POOL_VAULT_SEED.as_bytes(), lp_mint_key.to_bytes().as_ref()], - &program.id(), - ); - let (observation_key, __bump) = Pubkey::find_program_address( - &[ - OBSERVATION_SEED.as_bytes(), - pool_account_key.to_bytes().as_ref(), - ], - &program.id(), - ); - - let compression_config_key = CompressibleConfig::derive_default_pda(&program.id()).0; - let mut remaining_accounts = PackedAccounts::default(); - let address_tree_info = light_client.get_address_tree_v2(); - let state_tree_info = light_client.get_state_tree_infos()[0]; - remaining_accounts.add_system_accounts_small(SystemAccountMetaConfig::new_with_cpi_context( - program.id(), - state_tree_info.cpi_context.unwrap(), - ))?; - - // Derive compressed addresses of all to-be-initialized compressible accounts. - let pool_compressed_address = derive_address( - &pool_account_key.to_bytes(), - &address_tree_info.tree.to_bytes(), - &program.id().to_bytes(), - ); - let observation_compressed_address = derive_address( - &observation_key.to_bytes(), - &address_tree_info.tree.to_bytes(), - &program.id().to_bytes(), - ); - let lp_mint_compressed_address = - derive_compressed_mint_address(lp_mint_key, &address_tree_info.tree); - - // Fetch validity proof for all new compressed addresses. Proves that the - // accounts don't exist yet. Must match the ordering used by the program - // when invoking the cpi. - let rpc_result = light_client - .get_validity_proof( - vec![], - vec![ - AddressWithTree { - address: pool_compressed_address, - tree: address_tree_info.tree, - }, - AddressWithTree { - address: observation_compressed_address, - tree: address_tree_info.tree, - }, - AddressWithTree { - address: lp_mint_compressed_address, - tree: address_tree_info.tree, - }, - ], - None, - ) - .await - .unwrap() - .value; - - let output_state_tree_index = remaining_accounts.insert_or_get(state_tree_info.queue); - let packed_tree_infos = rpc_result.pack_tree_infos(&mut remaining_accounts); - let pool_address_tree_info = - packed_tree_infos.address_trees[POOL_STATE_CREATION_INDEX as usize]; - let observation_address_tree_info = - packed_tree_infos.address_trees[OBSERVATION_STATE_CREATION_INDEX as usize]; - let lp_mint_address_tree_info = - packed_tree_infos.address_trees[LP_MINT_CREATION_INDEX as usize]; - - let (system_accounts, _, _) = remaining_accounts.to_account_metas(); - - let (creator_lp_token, creator_lp_token_bump) = - compressed_token::get_associated_ctoken_address_and_bump(&program.payer(), &lp_mint_key); - - let compression_params = - raydium_cp_swap::instructions::initialize::InitializeCompressionParams { - pool_address_tree_info, - observation_address_tree_info, - lp_mint_address_tree_info, - lp_mint_bump, - proof: rpc_result.proof.into(), - output_state_tree_index, - creator_lp_token_bump, - }; - - let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&token_0_mint); - let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&token_1_mint); - - let mut instructions = program - .request() - .accounts(raydium_cp_accounts::Initialize { - creator: program.payer(), - amm_config: amm_config_key, - authority, - pool_state: pool_account_key, - token_0_mint, - token_1_mint, - lp_mint: lp_mint_key, - lp_vault, - creator_token_0: user_token_0_account, - creator_token_1: user_token_1_account, - creator_lp_token, - token_0_vault, - token_1_vault, - create_pool_fee, - observation_state: observation_key, - token_program: spl_token::id(), - token_0_program, - token_1_program, - associated_token_program: spl_associated_token_account::id(), - system_program: system_program::id(), - rent: sysvar::rent::id(), - compression_config: compression_config_key, - rent_recipient: program.payer(), - lp_mint_signer, - compressed_token_program_cpi_authority: compressed_token::cpi_authority(), - compressed_token_program: compressed_token::id(), - compressed_token_0_pool_pda, - compressed_token_1_pool_pda, - }) - .accounts(system_accounts) - .args(raydium_cp_instructions::Initialize { - init_amount_0, - init_amount_1, - open_time, - compression_params, - }) - .instructions()?; - - if random_pool_id.is_some() { - // update account signer as true for random pool - for account in instructions[0].accounts.iter_mut() { - if account.pubkey == random_pool_id.unwrap() { - account.is_signer = true; - break; - } - } - } - - Ok(instructions) -} - -pub fn deposit_instr( - config: &ClientConfig, - pool_id: Pubkey, - token_0_mint: Pubkey, - token_1_mint: Pubkey, - token_lp_mint: Pubkey, - token_0_vault: Pubkey, - token_1_vault: Pubkey, - user_token_0_account: Pubkey, - user_token_1_account: Pubkey, - user_token_lp_account: Pubkey, - lp_token_amount: u64, - maximum_token_0_amount: u64, - maximum_token_1_amount: u64, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. - let client = Client::new(url, Rc::new(payer)); - let program = client.program(config.raydium_cp_program)?; - - let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); - - let (lp_vault, __bump) = Pubkey::find_program_address( - &[ - POOL_VAULT_SEED.as_bytes(), - token_lp_mint.to_bytes().as_ref(), - ], - &program.id(), - ); - - let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&token_0_mint); - let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&token_1_mint); - - let instructions = program - .request() - .accounts(raydium_cp_accounts::Deposit { - owner: program.payer(), - authority, - pool_state: pool_id, - owner_lp_token: user_token_lp_account, - token_0_account: user_token_0_account, - token_1_account: user_token_1_account, - token_0_vault, - token_1_vault, - token_program: spl_token::id(), - token_program_2022: spl_token_2022::id(), - vault_0_mint: token_0_mint, - vault_1_mint: token_1_mint, - lp_vault, - compressed_token_program: compressed_token::id(), - compressed_token_program_cpi_authority: compressed_token::cpi_authority(), - compressed_token_0_pool_pda, - compressed_token_1_pool_pda, - }) - .args(raydium_cp_instructions::Deposit { - lp_token_amount, - maximum_token_0_amount, - maximum_token_1_amount, - }) - .instructions()?; - Ok(instructions) -} - -pub fn withdraw_instr( - config: &ClientConfig, - pool_id: Pubkey, - token_0_mint: Pubkey, - token_1_mint: Pubkey, - token_lp_mint: Pubkey, - token_0_vault: Pubkey, - token_1_vault: Pubkey, - user_token_0_account: Pubkey, - user_token_1_account: Pubkey, - user_token_lp_account: Pubkey, - lp_token_amount: u64, - minimum_token_0_amount: u64, - minimum_token_1_amount: u64, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. - let client = Client::new(url, Rc::new(payer)); - let program = client.program(config.raydium_cp_program)?; - - let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); - - let (lp_vault, __bump) = Pubkey::find_program_address( - &[ - POOL_VAULT_SEED.as_bytes(), - token_lp_mint.to_bytes().as_ref(), - ], - &program.id(), - ); - let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&token_0_mint); - let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&token_1_mint); - - let instructions = program - .request() - .accounts(raydium_cp_accounts::Withdraw { - owner: program.payer(), - authority, - pool_state: pool_id, - owner_lp_token: user_token_lp_account, - token_0_account: user_token_0_account, - token_1_account: user_token_1_account, - token_0_vault, - token_1_vault, - token_program: spl_token::id(), - token_program_2022: spl_token_2022::id(), - vault_0_mint: token_0_mint, - vault_1_mint: token_1_mint, - lp_vault, - compressed_token_program: compressed_token::id(), - memo_program: spl_memo::id(), - compressed_token_program_cpi_authority: compressed_token::cpi_authority(), - compressed_token_0_pool_pda, - compressed_token_1_pool_pda, - }) - .args(raydium_cp_instructions::Withdraw { - lp_token_amount, - minimum_token_0_amount, - minimum_token_1_amount, - }) - .instructions()?; - Ok(instructions) -} - -pub fn swap_base_input_instr( - config: &ClientConfig, - pool_id: Pubkey, - amm_config: Pubkey, - observation_account: Pubkey, - input_token_account: Pubkey, - output_token_account: Pubkey, - input_vault: Pubkey, - output_vault: Pubkey, - input_token_mint: Pubkey, - output_token_mint: Pubkey, - input_token_program: Pubkey, - output_token_program: Pubkey, - amount_in: u64, - minimum_amount_out: u64, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. - let client = Client::new(url, Rc::new(payer)); - let program = client.program(config.raydium_cp_program)?; - - let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); - - let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&input_token_mint); - let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&output_token_mint); - - let instructions = program - .request() - .accounts(raydium_cp_accounts::Swap { - payer: program.payer(), - authority, - amm_config, - pool_state: pool_id, - input_token_account, - output_token_account, - input_vault, - output_vault, - input_token_program, - output_token_program, - input_token_mint, - output_token_mint, - observation_state: observation_account, - compressed_token_program_cpi_authority: compressed_token::cpi_authority(), - compressed_token_program: compressed_token::id(), - compressed_token_0_pool_pda, - compressed_token_1_pool_pda, - }) - .args(raydium_cp_instructions::SwapBaseInput { - amount_in, - minimum_amount_out, - }) - .instructions()?; - Ok(instructions) -} - -pub fn swap_base_output_instr( - config: &ClientConfig, - pool_id: Pubkey, - amm_config: Pubkey, - observation_account: Pubkey, - input_token_account: Pubkey, - output_token_account: Pubkey, - input_vault: Pubkey, - output_vault: Pubkey, - input_token_mint: Pubkey, - output_token_mint: Pubkey, - input_token_program: Pubkey, - output_token_program: Pubkey, - max_amount_in: u64, - amount_out: u64, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - // Client. - let client = Client::new(url, Rc::new(payer)); - let program = client.program(config.raydium_cp_program)?; - - let (authority, __bump) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &program.id()); - - let (compressed_token_0_pool_pda, token_0_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&input_token_mint); - let (compressed_token_1_pool_pda, token_1_pool_pda_bump) = - compressed_token::get_token_pool_address_and_bump(&output_token_mint); - - let instructions = program - .request() - .accounts(raydium_cp_accounts::Swap { - payer: program.payer(), - authority, - amm_config, - pool_state: pool_id, - input_token_account, - output_token_account, - input_vault, - output_vault, - input_token_program, - output_token_program, - input_token_mint, - output_token_mint, - observation_state: observation_account, - compressed_token_program_cpi_authority: compressed_token::cpi_authority(), - compressed_token_program: compressed_token::id(), - compressed_token_0_pool_pda, - compressed_token_1_pool_pda, - }) - .args(raydium_cp_instructions::SwapBaseOutput { - max_amount_in, - amount_out, - }) - .instructions()?; - Ok(instructions) -} diff --git a/client/src/instructions/compression_instructions.rs b/client/src/instructions/compression_instructions.rs deleted file mode 100644 index ae4018c..0000000 --- a/client/src/instructions/compression_instructions.rs +++ /dev/null @@ -1,235 +0,0 @@ -use anchor_lang::AnchorDeserialize; -use anyhow::Result; -use light_client::{ - indexer::Indexer, - rpc::{LightClient, Rpc}, -}; -use light_compressible_client::CompressibleInstruction; -use light_sdk::compressible::CompressibleConfig; -use solana_client::rpc_client::RpcClient; -use solana_sdk::{ - pubkey::Pubkey, - signature::{Keypair, Signer}, -}; -use std::str::FromStr; - -use super::super::{read_keypair_file, ClientConfig}; -use super::rpc::send_versioned_txn; -use light_client::rpc::load_lookup_table; - -pub const COMPRESSION_DELAY: u32 = 100; -pub const ADDRESS_SPACE: [Pubkey; 1] = [solana_sdk::pubkey!( - "EzKE84aVTkCUhDHLELqyJaq1Y7UVVmqxXqZjVHwHY3rK" -)]; - -pub async fn initialize_compression_config( - rpc_client: &RpcClient, - config: &ClientConfig, - authority: &Keypair, -) -> Result<()> { - let payer = read_keypair_file(&config.payer_path)?; - let program_id = config.raydium_cp_program; - - let (config_pda, _) = CompressibleConfig::derive_default_pda(&program_id); - if rpc_client.get_account(&config_pda).is_ok() { - return Ok(()); - } - - let instruction = CompressibleInstruction::initialize_compression_config( - &program_id, - &CompressibleInstruction::INITIALIZE_COMPRESSION_CONFIG_DISCRIMINATOR, - &payer.pubkey(), - &authority.pubkey(), - COMPRESSION_DELAY, - payer.pubkey(), // rent_recipient - ADDRESS_SPACE.to_vec(), - None, - ); - - let lookup_table_address = Pubkey::from_str("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ")?; - let lookup_table = load_lookup_table(&rpc_client, &lookup_table_address)?; - let lookup_tables = vec![lookup_table]; - - let signers = vec![&payer, authority]; - let _signature = send_versioned_txn( - &rpc_client, - &[instruction], - &signers, - &payer.pubkey(), - &lookup_tables, - true, - )?; - - Ok(()) -} - -pub async fn decompress_pool_and_observation_idempotent( - light_client: &mut LightClient, - rpc_client: &RpcClient, - config: &ClientConfig, - pool_address: Pubkey, - observation_address: Pubkey, - amm_config: Pubkey, - token_0_mint: Pubkey, - token_1_mint: Pubkey, -) -> Result<()> { - let payer = read_keypair_file(&config.payer_path)?; - let program_id = config.raydium_cp_program; - - let pool_exists = rpc_client.get_account(&pool_address).is_ok(); - let observation_exists = rpc_client.get_account(&observation_address).is_ok(); - - if pool_exists && observation_exists { - return Ok(()); - } - - let address_tree_info = light_client.get_address_tree_v2(); - - let pool_compressed_address = light_compressed_account::address::derive_address( - &pool_address.to_bytes(), - &address_tree_info.tree.to_bytes(), - &program_id.to_bytes(), - ); - - let observation_compressed_address = light_compressed_account::address::derive_address( - &observation_address.to_bytes(), - &address_tree_info.tree.to_bytes(), - &program_id.to_bytes(), - ); - - let pool_compressed_accounts = light_client - .get_compressed_accounts_by_owner(&program_id, None, None) - .await?; - - let pool_compressed = pool_compressed_accounts - .value - .items - .iter() - .find(|acc| acc.address == Some(pool_compressed_address)) - .cloned(); - - let observation_compressed = pool_compressed_accounts - .value - .items - .iter() - .find(|acc| acc.address == Some(observation_compressed_address)) - .cloned(); - - if pool_compressed.is_none() && observation_compressed.is_none() { - if rpc_client.get_account(&pool_address).is_err() { - return Err(anyhow::anyhow!("Onchain pool account does not exist")); - } - if rpc_client.get_account(&observation_address).is_err() { - return Err(anyhow::anyhow!( - "Onchain observation account does not exist" - )); - } - - return Ok(()); - } - - let pool_compressed = - pool_compressed.ok_or_else(|| anyhow::anyhow!("Pool compressed account not found"))?; - let observation_compressed = observation_compressed - .ok_or_else(|| anyhow::anyhow!("Observation compressed account not found"))?; - - let validity_proof_result = light_client - .get_validity_proof( - vec![ - pool_compressed.hash.clone(), - observation_compressed.hash.clone(), - ], - vec![], - None, - ) - .await? - .value; - - let (_, pool_bump) = Pubkey::find_program_address( - &[ - raydium_cp_swap::states::POOL_SEED.as_bytes(), - amm_config.as_ref(), - token_0_mint.as_ref(), - token_1_mint.as_ref(), - ], - &program_id, - ); - - let (_, observation_bump) = Pubkey::find_program_address( - &[ - raydium_cp_swap::states::OBSERVATION_SEED.as_bytes(), - pool_address.as_ref(), - ], - &program_id, - ); - - let state_tree_info = light_client.get_state_tree_infos()[0]; - - let pool_data = pool_compressed - .data - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Pool compressed account has no data"))?; - let pool_state = raydium_cp_swap::states::PoolState::deserialize(&mut &pool_data.data[..])?; - - let observation_data = observation_compressed - .data - .as_ref() - .ok_or_else(|| anyhow::anyhow!("Observation compressed account has no data"))?; - let observation_state = - raydium_cp_swap::states::ObservationState::deserialize(&mut &observation_data.data[..])?; - - let decompress_instr = - light_compressible_client::CompressibleInstruction::decompress_accounts_idempotent( - &program_id, - &CompressibleInstruction::DECOMPRESS_ACCOUNTS_IDEMPOTENT_DISCRIMINATOR, - &payer.pubkey(), - &payer.pubkey(), - &[pool_address, observation_address], - &[ - ( - pool_compressed.clone(), - raydium_cp_swap::raydium_cp_swap::CompressedAccountVariant::PoolState( - pool_state, - ), - vec![ - raydium_cp_swap::states::POOL_SEED.as_bytes().to_vec(), - amm_config.to_bytes().to_vec(), - token_0_mint.to_bytes().to_vec(), - token_1_mint.to_bytes().to_vec(), - ], - ), - ( - observation_compressed.clone(), - raydium_cp_swap::raydium_cp_swap::CompressedAccountVariant::ObservationState( - observation_state, - ), - vec![ - raydium_cp_swap::states::OBSERVATION_SEED - .as_bytes() - .to_vec(), - pool_address.to_bytes().to_vec(), - ], - ), - ], - &[pool_bump, observation_bump], - validity_proof_result, - state_tree_info, - ) - .map_err(|e| anyhow::anyhow!("Failed to build decompress instruction: {}", e))?; - - let lookup_table_address = Pubkey::from_str("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ")?; - let lookup_table = load_lookup_table(&rpc_client, &lookup_table_address)?; - let lookup_tables = vec![lookup_table]; - - let signers = vec![&payer]; - send_versioned_txn( - &rpc_client, - &[decompress_instr], - &signers, - &payer.pubkey(), - &lookup_tables, - true, - )?; - - Ok(()) -} diff --git a/client/src/instructions/events_instructions_parse.rs b/client/src/instructions/events_instructions_parse.rs deleted file mode 100644 index b04103a..0000000 --- a/client/src/instructions/events_instructions_parse.rs +++ /dev/null @@ -1,507 +0,0 @@ -use anchor_client::ClientError; -use anchor_lang::Discriminator; -use anyhow::Result; -use colorful::Color; -use colorful::Colorful; -use raydium_cp_swap::instruction; -use raydium_cp_swap::states::*; -use regex::Regex; -use solana_transaction_status::{ - option_serializer::OptionSerializer, EncodedTransaction, UiTransactionStatusMeta, -}; - -const PROGRAM_LOG: &str = "Program log: "; -const PROGRAM_DATA: &str = "Program data: "; -const DISCRIMINATOR_LEN: usize = 8; -pub enum InstructionDecodeType { - BaseHex, - Base64, - Base58, -} - -pub fn parse_program_event( - self_program_str: &str, - meta: Option, -) -> Result<(), ClientError> { - let logs: Vec = if let Some(meta_data) = meta { - let log_messages = if let OptionSerializer::Some(log_messages) = meta_data.log_messages { - log_messages - } else { - Vec::new() - }; - log_messages - } else { - Vec::new() - }; - let mut logs = &logs[..]; - if !logs.is_empty() { - if let Ok(mut execution) = Execution::new(&mut logs) { - for l in logs { - let (new_program, did_pop) = - if !execution.is_empty() && self_program_str == execution.program() { - handle_program_log(self_program_str, &l, true).unwrap_or_else(|e| { - println!("Unable to parse log: {e}"); - std::process::exit(1); - }) - } else { - let (program, did_pop) = handle_system_log(self_program_str, l); - (program, did_pop) - }; - // Switch program context on CPI. - if let Some(new_program) = new_program { - execution.push(new_program); - } - // Program returned. - if did_pop { - execution.pop(); - } - } - } - } else { - println!("log is empty"); - } - Ok(()) -} - -struct Execution { - stack: Vec, -} - -impl Execution { - pub fn new(logs: &mut &[String]) -> Result { - let l = &logs[0]; - *logs = &logs[1..]; - - let re = Regex::new(r"^Program (.*) invoke.*$").unwrap(); - let c = re - .captures(l) - .ok_or_else(|| ClientError::LogParseError(l.to_string()))?; - let program = c - .get(1) - .ok_or_else(|| ClientError::LogParseError(l.to_string()))? - .as_str() - .to_string(); - Ok(Self { - stack: vec![program], - }) - } - - pub fn program(&self) -> String { - assert!(!self.stack.is_empty()); - self.stack[self.stack.len() - 1].clone() - } - - pub fn is_empty(&self) -> bool { - self.stack.is_empty() - } - - pub fn push(&mut self, new_program: String) { - self.stack.push(new_program); - } - - pub fn pop(&mut self) { - assert!(!self.stack.is_empty()); - self.stack.pop().unwrap(); - } -} - -pub fn handle_program_log( - self_program_str: &str, - l: &str, - with_prefix: bool, -) -> Result<(Option, bool), ClientError> { - // Log emitted from the current program. - if let Some(log) = if with_prefix { - l.strip_prefix(PROGRAM_LOG) - .or_else(|| l.strip_prefix(PROGRAM_DATA)) - } else { - Some(l) - } { - if l.starts_with(&format!("Program log:")) { - // not log event - return Ok((None, false)); - } - let borsh_bytes = - match base64::Engine::decode(&base64::engine::general_purpose::STANDARD, log) { - Ok(borsh_bytes) => borsh_bytes, - _ => { - println!("Could not base64 decode log: {}", log); - return Ok((None, false)); - } - }; - - if borsh_bytes.len() < DISCRIMINATOR_LEN { - return Err(ClientError::LogParseError( - format!("log data is too short: {}", log).to_string(), - )); - } - let disc = &borsh_bytes[..DISCRIMINATOR_LEN]; - let mut slice: &[u8] = &borsh_bytes[DISCRIMINATOR_LEN..]; - - match disc { - SwapEvent::DISCRIMINATOR => { - println!("{:#?}", decode_event::(&mut slice)?); - } - LpChangeEvent::DISCRIMINATOR => { - println!("{:#?}", decode_event::(&mut slice)?); - } - _ => { - println!("unknow event: {}", l); - } - } - return Ok((None, false)); - } else { - let (program, did_pop) = handle_system_log(self_program_str, l); - return Ok((program, did_pop)); - } -} - -fn handle_system_log(this_program_str: &str, log: &str) -> (Option, bool) { - if log.starts_with(&format!("Program {this_program_str} invoke")) { - (Some(this_program_str.to_string()), false) - } else if log.contains("invoke") { - (Some("cpi".to_string()), false) // Any string will do. - } else { - let re = Regex::new(r"^Program (.*) success*$").unwrap(); - if re.is_match(log) { - (None, true) - } else { - (None, false) - } - } -} - -fn decode_event( - slice: &mut &[u8], -) -> Result { - let event: T = anchor_lang::AnchorDeserialize::deserialize(slice) - .map_err(|e| ClientError::LogParseError(e.to_string()))?; - Ok(event) -} - -pub fn parse_program_instruction( - self_program_str: &str, - encoded_transaction: EncodedTransaction, - meta: Option, -) -> Result<(), ClientError> { - let ui_raw_msg = match encoded_transaction { - solana_transaction_status::EncodedTransaction::Json(ui_tx) => { - let ui_message = ui_tx.message; - // println!("{:#?}", ui_message); - match ui_message { - solana_transaction_status::UiMessage::Raw(ui_raw_msg) => ui_raw_msg, - _ => solana_transaction_status::UiRawMessage { - header: solana_sdk::message::MessageHeader::default(), - account_keys: Vec::new(), - recent_blockhash: "".to_string(), - instructions: Vec::new(), - address_table_lookups: None, - }, - } - } - _ => solana_transaction_status::UiRawMessage { - header: solana_sdk::message::MessageHeader::default(), - account_keys: Vec::new(), - recent_blockhash: "".to_string(), - instructions: Vec::new(), - address_table_lookups: None, - }, - }; - // append lookup table keys if necessary - if meta.is_some() { - let mut account_keys = ui_raw_msg.account_keys; - let meta = meta.clone().unwrap(); - match meta.loaded_addresses { - OptionSerializer::Some(addresses) => { - let mut writeable_address = addresses.writable; - let mut readonly_address = addresses.readonly; - account_keys.append(&mut writeable_address); - account_keys.append(&mut readonly_address); - } - _ => {} - } - let program_index = account_keys - .iter() - .position(|r| r == self_program_str) - .unwrap(); - // println!("{}", program_index); - // println!("{:#?}", account_keys); - for (i, ui_compiled_instruction) in ui_raw_msg.instructions.iter().enumerate() { - if (ui_compiled_instruction.program_id_index as usize) == program_index { - let out_put = format!("instruction #{}", i + 1); - println!("{}", out_put.gradient(Color::Green)); - handle_program_instruction( - &ui_compiled_instruction.data, - InstructionDecodeType::Base58, - )?; - } - } - - match meta.inner_instructions { - OptionSerializer::Some(inner_instructions) => { - for inner in inner_instructions { - for (i, instruction) in inner.instructions.iter().enumerate() { - match instruction { - solana_transaction_status::UiInstruction::Compiled( - ui_compiled_instruction, - ) => { - if (ui_compiled_instruction.program_id_index as usize) - == program_index - { - let out_put = - format!("inner_instruction #{}.{}", inner.index + 1, i + 1); - println!("{}", out_put.gradient(Color::Green)); - handle_program_instruction( - &ui_compiled_instruction.data, - InstructionDecodeType::Base58, - )?; - } - } - _ => {} - } - } - } - } - _ => {} - } - } - Ok(()) -} - -pub fn handle_program_instruction( - instr_data: &str, - decode_type: InstructionDecodeType, -) -> Result<(), ClientError> { - let data; - match decode_type { - InstructionDecodeType::BaseHex => { - data = hex::decode(instr_data).unwrap(); - } - InstructionDecodeType::Base64 => { - let borsh_bytes = match base64::Engine::decode( - &base64::engine::general_purpose::STANDARD, - instr_data, - ) { - Ok(borsh_bytes) => borsh_bytes, - _ => { - println!("Could not base64 decode instruction: {}", instr_data); - return Ok(()); - } - }; - data = borsh_bytes; - } - InstructionDecodeType::Base58 => { - let borsh_bytes = match bs58::decode(instr_data).into_vec() { - Ok(borsh_bytes) => borsh_bytes, - _ => { - println!("Could not base58 decode instruction: {}", instr_data); - return Ok(()); - } - }; - data = borsh_bytes; - } - } - - if data.len() < DISCRIMINATOR_LEN { - return Err(ClientError::LogParseError( - format!("instruction data is too short: {}", instr_data).to_string(), - )); - } - let disc = &data[..DISCRIMINATOR_LEN]; - let mut ix_data: &[u8] = &data[DISCRIMINATOR_LEN..]; - - match disc { - instruction::CreateAmmConfig::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct CreateAmmConfig { - pub index: u16, - pub trade_fee_rate: u64, - pub protocol_fee_rate: u64, - pub fund_fee_rate: u64, - pub create_pool_fee: u64, - } - impl From for CreateAmmConfig { - fn from(instr: instruction::CreateAmmConfig) -> CreateAmmConfig { - CreateAmmConfig { - index: instr.index, - trade_fee_rate: instr.trade_fee_rate, - protocol_fee_rate: instr.protocol_fee_rate, - fund_fee_rate: instr.fund_fee_rate, - create_pool_fee: instr.create_pool_fee, - } - } - } - println!("{:#?}", CreateAmmConfig::from(ix)); - } - instruction::UpdateAmmConfig::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct UpdateAmmConfig { - pub param: u8, - pub value: u64, - } - impl From for UpdateAmmConfig { - fn from(instr: instruction::UpdateAmmConfig) -> UpdateAmmConfig { - UpdateAmmConfig { - param: instr.param, - value: instr.value, - } - } - } - println!("{:#?}", UpdateAmmConfig::from(ix)); - } - instruction::Initialize::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct Initialize { - pub init_amount_0: u64, - pub init_amount_1: u64, - pub open_time: u64, - } - impl From for Initialize { - fn from(instr: instruction::Initialize) -> Initialize { - Initialize { - init_amount_0: instr.init_amount_0, - init_amount_1: instr.init_amount_1, - open_time: instr.open_time, - } - } - } - println!("{:#?}", Initialize::from(ix)); - } - instruction::UpdatePoolStatus::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct UpdatePoolStatus { - pub status: u8, - } - impl From for UpdatePoolStatus { - fn from(instr: instruction::UpdatePoolStatus) -> UpdatePoolStatus { - UpdatePoolStatus { - status: instr.status, - } - } - } - println!("{:#?}", UpdatePoolStatus::from(ix)); - } - instruction::CollectProtocolFee::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct CollectProtocolFee { - pub amount_0_requested: u64, - pub amount_1_requested: u64, - } - impl From for CollectProtocolFee { - fn from(instr: instruction::CollectProtocolFee) -> CollectProtocolFee { - CollectProtocolFee { - amount_0_requested: instr.amount_0_requested, - amount_1_requested: instr.amount_1_requested, - } - } - } - println!("{:#?}", CollectProtocolFee::from(ix)); - } - instruction::CollectFundFee::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct CollectFundFee { - pub amount_0_requested: u64, - pub amount_1_requested: u64, - } - impl From for CollectFundFee { - fn from(instr: instruction::CollectFundFee) -> CollectFundFee { - CollectFundFee { - amount_0_requested: instr.amount_0_requested, - amount_1_requested: instr.amount_1_requested, - } - } - } - println!("{:#?}", CollectFundFee::from(ix)); - } - instruction::Deposit::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct Deposit { - pub lp_token_amount: u64, - pub maximum_token_0_amount: u64, - pub maximum_token_1_amount: u64, - } - impl From for Deposit { - fn from(instr: instruction::Deposit) -> Deposit { - Deposit { - lp_token_amount: instr.lp_token_amount, - maximum_token_0_amount: instr.maximum_token_0_amount, - maximum_token_1_amount: instr.maximum_token_1_amount, - } - } - } - println!("{:#?}", Deposit::from(ix)); - } - instruction::Withdraw::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct Withdraw { - pub lp_token_amount: u64, - pub minimum_token_0_amount: u64, - pub minimum_token_1_amount: u64, - } - impl From for Withdraw { - fn from(instr: instruction::Withdraw) -> Withdraw { - Withdraw { - lp_token_amount: instr.lp_token_amount, - minimum_token_0_amount: instr.minimum_token_0_amount, - minimum_token_1_amount: instr.minimum_token_1_amount, - } - } - } - println!("{:#?}", Withdraw::from(ix)); - } - instruction::SwapBaseInput::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct SwapBaseInput { - pub amount_in: u64, - pub minimum_amount_out: u64, - } - impl From for SwapBaseInput { - fn from(instr: instruction::SwapBaseInput) -> SwapBaseInput { - SwapBaseInput { - amount_in: instr.amount_in, - minimum_amount_out: instr.minimum_amount_out, - } - } - } - println!("{:#?}", SwapBaseInput::from(ix)); - } - instruction::SwapBaseOutput::DISCRIMINATOR => { - let ix = decode_instruction::(&mut ix_data).unwrap(); - #[derive(Debug)] - pub struct SwapBaseOutput { - pub max_amount_in: u64, - pub amount_out: u64, - } - impl From for SwapBaseOutput { - fn from(instr: instruction::SwapBaseOutput) -> SwapBaseOutput { - SwapBaseOutput { - max_amount_in: instr.max_amount_in, - amount_out: instr.amount_out, - } - } - } - println!("{:#?}", SwapBaseOutput::from(ix)); - } - _ => { - println!("unknow instruction: {}", instr_data); - } - } - Ok(()) -} - -fn decode_instruction( - slice: &mut &[u8], -) -> Result { - let instruction: T = anchor_lang::AnchorDeserialize::deserialize(slice) - .map_err(|_| anchor_lang::error::ErrorCode::InstructionDidNotDeserialize)?; - Ok(instruction) -} diff --git a/client/src/instructions/mod.rs b/client/src/instructions/mod.rs deleted file mode 100644 index 041e32b..0000000 --- a/client/src/instructions/mod.rs +++ /dev/null @@ -1,6 +0,0 @@ -pub mod amm_instructions; -pub mod compression_instructions; -pub mod events_instructions_parse; -pub mod rpc; -pub mod token_instructions; -pub mod utils; diff --git a/client/src/instructions/rpc.rs b/client/src/instructions/rpc.rs deleted file mode 100644 index 7a9b04b..0000000 --- a/client/src/instructions/rpc.rs +++ /dev/null @@ -1,85 +0,0 @@ -use anyhow::Result; -use solana_client::{ - rpc_client::RpcClient, - rpc_config::RpcSendTransactionConfig, - rpc_request::RpcRequest, - rpc_response::{RpcResult, RpcSimulateTransactionResult}, -}; -use solana_message::AddressLookupTableAccount; -use solana_sdk::{ - commitment_config::CommitmentConfig, - instruction::Instruction, - message::{v0, VersionedMessage}, - pubkey::Pubkey, - signature::{Signature, Signer}, - transaction::{Transaction, VersionedTransaction}, -}; -use std::convert::Into; - -pub fn simulate_transaction( - client: &RpcClient, - transaction: &Transaction, - sig_verify: bool, - cfg: CommitmentConfig, -) -> RpcResult { - let serialized_encoded = bs58::encode(bincode::serialize(transaction).unwrap()).into_string(); - client.send( - RpcRequest::SimulateTransaction, - serde_json::json!([serialized_encoded, { - "sigVerify": sig_verify, "commitment": cfg.commitment - }]), - ) -} -pub fn send_versioned_txn( - client: &RpcClient, - instructions: &[Instruction], - signers: &[&T], - payer: &Pubkey, - lookup_tables: &[AddressLookupTableAccount], - wait_confirm: bool, -) -> Result { - let mut instructions_with_cu = vec![ - solana_sdk::compute_budget::ComputeBudgetInstruction::set_compute_unit_limit(1_000_000), - ]; - instructions_with_cu.extend_from_slice(instructions); - let instructions = &instructions_with_cu; - let blockhash = client.get_latest_blockhash()?; - let tx = VersionedTransaction::try_new( - VersionedMessage::V0(v0::Message::try_compile( - payer, - instructions, - lookup_tables, - blockhash, - )?), - signers, - )?; - - client.send_and_confirm_transaction_with_spinner_and_config( - &tx, - if wait_confirm { - CommitmentConfig::confirmed() - } else { - CommitmentConfig::processed() - }, - RpcSendTransactionConfig { - skip_preflight: true, - ..RpcSendTransactionConfig::default() - }, - )?; - Ok(tx.signatures[0]) -} - -pub fn send_txn(client: &RpcClient, txn: &Transaction, wait_confirm: bool) -> Result { - Ok(client.send_and_confirm_transaction_with_spinner_and_config( - txn, - if wait_confirm { - CommitmentConfig::confirmed() - } else { - CommitmentConfig::processed() - }, - RpcSendTransactionConfig { - skip_preflight: true, - ..RpcSendTransactionConfig::default() - }, - )?) -} diff --git a/client/src/instructions/token_instructions.rs b/client/src/instructions/token_instructions.rs deleted file mode 100644 index e2f1d41..0000000 --- a/client/src/instructions/token_instructions.rs +++ /dev/null @@ -1,310 +0,0 @@ -use super::super::{read_keypair_file, ClientConfig}; -use anchor_client::{Client, Cluster}; -use anchor_spl::{ - associated_token::spl_associated_token_account, - token::spl_token, - token_2022::spl_token_2022::{ - self, - extension::{BaseStateWithExtensions, ExtensionType, StateWithExtensionsMut}, - state::{Account, Mint}, - }, -}; -use anyhow::Result; -use solana_client::nonblocking::rpc_client::RpcClient; -use solana_sdk::{ - account::WritableAccount, - instruction::Instruction, - program_pack::Pack, - pubkey::Pubkey, - signature::{Keypair, Signer}, - system_instruction, -}; -use std::{rc::Rc, str::FromStr}; - -pub async fn create_and_init_mint_instr( - config: &ClientConfig, - token_program: Pubkey, - mint_key: &Pubkey, - mint_authority: &Pubkey, - freeze_authority: Option<&Pubkey>, - decimals: u8, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - - let client = Client::new(url, Rc::new(payer)); - let program = if token_program == spl_token::id() { - client.program(spl_token::id())? - } else { - client.program(spl_token_2022::id())? - }; - - let space = if token_program == spl_token::id() { - spl_token::state::Mint::LEN - } else { - spl_token_2022::extension::ExtensionType::try_calculate_account_len::< - spl_token_2022::state::Mint, - >(&[])? - }; - - let mut instructions = vec![system_instruction::create_account( - &program.payer(), - mint_key, - program - .rpc() - .get_minimum_balance_for_rent_exemption(space) - .await?, - space as u64, - &program.id(), - )]; - - if token_program == spl_token::id() { - instructions.push(spl_token::instruction::initialize_mint( - &program.id(), - mint_key, - mint_authority, - freeze_authority, - decimals, - )?); - } else { - instructions.push(spl_token_2022::instruction::initialize_mint( - &program.id(), - mint_key, - mint_authority, - freeze_authority, - decimals, - )?); - } - Ok(instructions) -} - -pub async fn create_account_rent_exmpt_instr( - config: &ClientConfig, - new_account_key: &Pubkey, - owner: Pubkey, - data_size: usize, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - - let client = Client::new(url, Rc::new(payer)); - let program = client.program(owner)?; - let instructions = program - .request() - .instruction(system_instruction::create_account( - &program.payer(), - &new_account_key, - program - .rpc() - .get_minimum_balance_for_rent_exemption(data_size) - .await?, - data_size as u64, - &program.id(), - )) - .instructions()?; - Ok(instructions) -} - -pub fn create_ata_token_account_instr( - config: &ClientConfig, - token_program: Pubkey, - mint: &Pubkey, - owner: &Pubkey, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - - let client = Client::new(url, Rc::new(payer)); - let program = client.program(token_program)?; - let instructions = program - .request() - .instruction( - spl_associated_token_account::instruction::create_associated_token_account_idempotent( - &program.payer(), - owner, - mint, - &token_program, - ), - ) - .instructions()?; - Ok(instructions) -} - -pub async fn create_and_init_auxiliary_token( - config: &ClientConfig, - new_account_key: &Pubkey, - mint: &Pubkey, - owner: &Pubkey, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - let mint_account = &mut RpcClient::new(config.http_url.to_string()) - .get_account(&mint) - .await?; - - let client = Client::new(url, Rc::new(payer)); - let (program, space) = if mint_account.owner == spl_token::id() { - ( - client.program(spl_token::id())?, - spl_token::state::Account::LEN, - ) - } else { - let mut extensions = vec![]; - extensions.push(ExtensionType::ImmutableOwner); - let mint_state = StateWithExtensionsMut::::unpack(mint_account.data_as_mut_slice())?; - let mint_extension_types = mint_state.get_extension_types()?; - let mut required_extensions = - ExtensionType::get_required_init_account_extensions(&mint_extension_types); - for extension_type in extensions.into_iter() { - if !required_extensions.contains(&extension_type) { - required_extensions.push(extension_type); - } - } - let space = ExtensionType::try_calculate_account_len::(&required_extensions)?; - - (client.program(spl_token_2022::id())?, space) - }; - - let instructions = program - .request() - .instruction(system_instruction::create_account( - &program.payer(), - &mint, - program - .rpc() - .get_minimum_balance_for_rent_exemption(space) - .await?, - space as u64, - &program.id(), - )) - .instruction(spl_token_2022::instruction::initialize_immutable_owner( - &program.id(), - new_account_key, - )?) - .instruction(spl_token_2022::instruction::initialize_account( - &program.id(), - new_account_key, - mint, - owner, - )?) - .instructions()?; - Ok(instructions) -} - -pub async fn close_token_account( - config: &ClientConfig, - close_account: &Pubkey, - destination: &Pubkey, - owner: &Keypair, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - - let client = Client::new(url, Rc::new(payer)); - let program = client.program(spl_token::id())?; - let instructions = program - .request() - .instruction(spl_token::instruction::close_account( - &program.id(), - close_account, - destination, - &owner.pubkey(), - &[], - )?) - .signer(owner.insecure_clone()) - .instructions()?; - Ok(instructions) -} - -pub fn spl_token_transfer_instr( - config: &ClientConfig, - from: &Pubkey, - to: &Pubkey, - amount: u64, - from_authority: &Keypair, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - - let client = Client::new(url, Rc::new(payer)); - let program = client.program(spl_token::id())?; - let instructions = program - .request() - .instruction(spl_token::instruction::transfer( - &program.id(), - from, - to, - &from_authority.pubkey(), - &[], - amount, - )?) - .signer(from_authority.insecure_clone()) - .instructions()?; - Ok(instructions) -} - -pub fn spl_token_mint_to_instr( - config: &ClientConfig, - token_program: Pubkey, - mint: &Pubkey, - to: &Pubkey, - amount: u64, - mint_authority: &Keypair, -) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - - let client = Client::new(url, Rc::new(payer)); - let program = if token_program == spl_token::id() { - client.program(spl_token::id())? - } else { - client.program(spl_token_2022::id())? - }; - let instructions = program - .request() - .instruction(spl_token_2022::instruction::mint_to( - &program.id(), - mint, - to, - &mint_authority.pubkey(), - &[], - amount, - )?) - .signer(mint_authority.insecure_clone()) - .instructions()?; - Ok(instructions) -} - -pub fn wrap_sol_instr(config: &ClientConfig, amount: u64) -> Result> { - let payer = read_keypair_file(&config.payer_path)?; - let wallet_key = payer.pubkey(); - let url = Cluster::Custom(config.http_url.clone(), config.ws_url.clone()); - let wsol_mint = Pubkey::from_str("So11111111111111111111111111111111111111112")?; - let wsol_ata_account = - spl_associated_token_account::get_associated_token_address(&wallet_key, &wsol_mint); - - let client = Client::new(url, Rc::new(payer)); - let program = client.program(spl_token::id())?; - - let instructions = program - .request() - .instruction( - spl_associated_token_account::instruction::create_associated_token_account_idempotent( - &program.payer(), - &wallet_key, - &wsol_mint, - &program.id(), - ), - ) - .instruction(system_instruction::transfer( - &wallet_key, - &wsol_ata_account, - amount, - )) - .instruction(spl_token::instruction::sync_native( - &program.id(), - &wsol_ata_account, - )?) - .instructions()?; - Ok(instructions) -} diff --git a/client/src/instructions/utils.rs b/client/src/instructions/utils.rs deleted file mode 100644 index ff3f57a..0000000 --- a/client/src/instructions/utils.rs +++ /dev/null @@ -1,136 +0,0 @@ -use anchor_lang::AccountDeserialize; -use anchor_spl::token_2022::spl_token_2022::{ - extension::{ - transfer_fee::{TransferFeeConfig, MAX_FEE_BASIS_POINTS}, - BaseState, BaseStateWithExtensions, PodStateWithExtensions, - }, - pod::{PodAccount, PodMint}, -}; -use anyhow::Result; -use bytemuck::Pod; -use solana_client::rpc_client::RpcClient; -use solana_sdk::{account::Account as CliAccount, pubkey::Pubkey}; -use std::ops::Mul; - -pub fn deserialize_anchor_account(account: &CliAccount) -> Result { - let mut data: &[u8] = &account.data; - T::try_deserialize(&mut data).map_err(Into::into) -} - -pub fn unpack_token(token_data: &[u8]) -> Result> { - let token = PodStateWithExtensions::::unpack(&token_data)?; - Ok(token) -} - -pub fn unpack_mint(token_data: &[u8]) -> Result> { - let mint = PodStateWithExtensions::::unpack(&token_data)?; - Ok(mint) -} - -#[derive(Debug)] -pub struct TransferFeeInfo { - pub mint: Pubkey, - pub owner: Pubkey, - pub transfer_fee: u64, -} - -pub fn amount_with_slippage(amount: u64, slippage: f64, round_up: bool) -> u64 { - if round_up { - (amount as f64).mul(1_f64 + slippage).ceil() as u64 - } else { - (amount as f64).mul(1_f64 - slippage).floor() as u64 - } -} - -pub fn get_pool_mints_inverse_fee( - rpc_client: &RpcClient, - token_mint_0: Pubkey, - token_mint_1: Pubkey, - post_fee_amount_0: u64, - post_fee_amount_1: u64, -) -> (TransferFeeInfo, TransferFeeInfo) { - let load_accounts = vec![token_mint_0, token_mint_1]; - let rsps = rpc_client.get_multiple_accounts(&load_accounts).unwrap(); - let epoch = rpc_client.get_epoch_info().unwrap().epoch; - let mint0_account = rsps[0].clone().ok_or("load mint0 rps error!").unwrap(); - let mint1_account = rsps[1].clone().ok_or("load mint0 rps error!").unwrap(); - let mint0_state = unpack_mint(&mint0_account.data).unwrap(); - let mint1_state = unpack_mint(&mint1_account.data).unwrap(); - ( - TransferFeeInfo { - mint: token_mint_0, - owner: mint0_account.owner, - transfer_fee: get_transfer_inverse_fee(&mint0_state, post_fee_amount_0, epoch), - }, - TransferFeeInfo { - mint: token_mint_1, - owner: mint1_account.owner, - transfer_fee: get_transfer_inverse_fee(&mint1_state, post_fee_amount_1, epoch), - }, - ) -} - -pub fn get_pool_mints_transfer_fee( - rpc_client: &RpcClient, - token_mint_0: Pubkey, - token_mint_1: Pubkey, - pre_fee_amount_0: u64, - pre_fee_amount_1: u64, -) -> (TransferFeeInfo, TransferFeeInfo) { - let load_accounts = vec![token_mint_0, token_mint_1]; - let rsps = rpc_client.get_multiple_accounts(&load_accounts).unwrap(); - let epoch = rpc_client.get_epoch_info().unwrap().epoch; - let mint0_account = rsps[0].clone().ok_or("load mint0 rps error!").unwrap(); - let mint1_account = rsps[1].clone().ok_or("load mint0 rps error!").unwrap(); - let mint0_state = unpack_mint(&mint0_account.data).unwrap(); - let mint1_state = unpack_mint(&mint1_account.data).unwrap(); - ( - TransferFeeInfo { - mint: token_mint_0, - owner: mint0_account.owner, - transfer_fee: get_transfer_fee(&mint0_state, pre_fee_amount_0, epoch), - }, - TransferFeeInfo { - mint: token_mint_1, - owner: mint1_account.owner, - transfer_fee: get_transfer_fee(&mint1_state, pre_fee_amount_1, epoch), - }, - ) -} - -/// Calculate the fee for output amount -pub fn get_transfer_inverse_fee<'data, S: BaseState + Pod>( - account_state: &PodStateWithExtensions<'data, S>, - epoch: u64, - post_fee_amount: u64, -) -> u64 { - let fee = if let Ok(transfer_fee_config) = account_state.get_extension::() { - let transfer_fee = transfer_fee_config.get_epoch_fee(epoch); - if u16::from(transfer_fee.transfer_fee_basis_points) == MAX_FEE_BASIS_POINTS { - u64::from(transfer_fee.maximum_fee) - } else { - transfer_fee_config - .calculate_inverse_epoch_fee(epoch, post_fee_amount) - .unwrap() - } - } else { - 0 - }; - fee -} - -/// Calculate the fee for input amount -pub fn get_transfer_fee<'data, S: BaseState + Pod>( - account_state: &PodStateWithExtensions<'data, S>, - epoch: u64, - pre_fee_amount: u64, -) -> u64 { - let fee = if let Ok(transfer_fee_config) = account_state.get_extension::() { - transfer_fee_config - .calculate_epoch_fee(epoch, pre_fee_amount) - .unwrap() - } else { - 0 - }; - fee -} diff --git a/client/src/main.rs b/client/src/main.rs deleted file mode 100644 index 8a47f88..0000000 --- a/client/src/main.rs +++ /dev/null @@ -1,928 +0,0 @@ -use anchor_spl::{associated_token::spl_associated_token_account, token::spl_token}; -use anyhow::{format_err, Result}; -use arrayref::array_ref; -use clap::Parser; -use configparser::ini::Ini; -use light_client::constants::LOOKUP_TABLE_ADDRESS; -use light_client::rpc::{load_lookup_table, LightClient, LightClientConfig, Rpc}; -use light_compressible_client::account_fetcher::get_compressible_account; -use light_token_client::actions::create_token_pool; -use light_token_client::compressed_token; -use solana_client::{rpc_client::RpcClient, rpc_config::RpcTransactionConfig}; -use solana_sdk::{ - commitment_config::CommitmentConfig, - pubkey::Pubkey, - signature::{Keypair, Signature, Signer}, -}; -use solana_transaction_status::UiTransactionEncoding; -use std::str::FromStr; - -mod instructions; -use instructions::amm_instructions::*; -use instructions::compression_instructions::*; -use instructions::events_instructions_parse::*; -use instructions::rpc::*; -use instructions::token_instructions::*; -use instructions::utils::*; - -#[derive(Clone, Debug, PartialEq)] -pub struct ClientConfig { - http_url: String, - ws_url: String, - payer_path: String, - admin_path: String, - raydium_cp_program: Pubkey, - slippage: f64, -} - -fn load_cfg(client_config: &String) -> Result { - let mut config = Ini::new(); - let _map = config.load(client_config).unwrap(); - let http_url = config.get("Global", "http_url").unwrap(); - if http_url.is_empty() { - panic!("http_url must not be empty"); - } - let ws_url = config.get("Global", "ws_url").unwrap(); - if ws_url.is_empty() { - panic!("ws_url must not be empty"); - } - let payer_path = config.get("Global", "payer_path").unwrap(); - if payer_path.is_empty() { - panic!("payer_path must not be empty"); - } - let admin_path = config.get("Global", "admin_path").unwrap(); - if admin_path.is_empty() { - panic!("admin_path must not be empty"); - } - - let raydium_cp_program_str = config.get("Global", "raydium_cp_program").unwrap(); - if raydium_cp_program_str.is_empty() { - panic!("raydium_cp_program must not be empty"); - } - let raydium_cp_program = Pubkey::from_str(&raydium_cp_program_str).unwrap(); - let slippage = config.getfloat("Global", "slippage").unwrap().unwrap(); - - Ok(ClientConfig { - http_url, - ws_url, - payer_path, - admin_path, - raydium_cp_program, - slippage, - }) -} - -fn read_keypair_file(s: &str) -> Result { - solana_sdk::signature::read_keypair_file(s) - .map_err(|_| format_err!("failed to read keypair from {}", s)) -} - -#[derive(Debug, Parser)] -pub struct Opts { - #[clap(subcommand)] - pub command: RaydiumCpCommands, -} - -#[derive(Debug, Parser)] -pub enum RaydiumCpCommands { - InitializePool { - mint0: Pubkey, - mint1: Pubkey, - init_amount_0: u64, - init_amount_1: u64, - #[arg(short, long, default_value_t = 0)] - open_time: u64, - #[clap(short, long, action)] - random_pool: bool, - }, - Deposit { - pool_id: Pubkey, - user_token_0: Pubkey, - user_token_1: Pubkey, - lp_token_amount: u64, - }, - Withdraw { - pool_id: Pubkey, - lp_token_amount: u64, - }, - SwapBaseIn { - pool_id: Pubkey, - user_input_token: Pubkey, - user_input_amount: u64, - }, - SwapBaseOut { - pool_id: Pubkey, - user_input_token: Pubkey, - amount_out_less_fee: u64, - }, - DecodeInstruction { - instr_hex_data: String, - }, - DecodeEvent { - log_event: String, - }, - DecodeTxLog { - tx_id: String, - }, - InitCompressionConfig {}, - CreateMint { - #[clap(help = "Number of decimal places for the token")] - decimals: u8, - #[clap(short, long, help = "Path to save the mint keypair (optional)")] - save_keypair: Option, - }, -} - -#[tokio::main] -async fn main() -> Result<()> { - let client_config = "client_config.ini"; - let pool_config = load_cfg(&client_config.to_string()).unwrap(); - let payer = read_keypair_file(&pool_config.payer_path)?; - let rpc_client = RpcClient::new(pool_config.http_url.to_string()); - - // 1. Extend RpcClient with ZK Compression RPC endpoints. - let mut light_client = LightClient::new(LightClientConfig::local()).await?; - - let opts = Opts::parse(); - match opts.command { - RaydiumCpCommands::InitializePool { - mint0, - mint1, - init_amount_0, - init_amount_1, - open_time, - random_pool, - } => { - let admin = read_keypair_file(&pool_config.admin_path)?; - - // Initialize compression config once globally. - initialize_compression_config(&rpc_client, &pool_config, &admin).await?; - - let (mint0, mint1, init_amount_0, init_amount_1) = if mint0 > mint1 { - (mint1, mint0, init_amount_1, init_amount_0) - } else { - (mint0, mint1, init_amount_0, init_amount_1) - }; - - let load_pubkeys = vec![mint0, mint1]; - let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; - let token_0_program = rsps[0].clone().unwrap().owner; - let token_1_program = rsps[1].clone().unwrap().owner; - - let mut signers = vec![&payer]; - - let random_pool_keypair = Keypair::new(); - let random_pool_id = if random_pool { - let random_pool_id = random_pool_keypair.pubkey(); - signers.push(&random_pool_keypair); - Some(random_pool_id) - } else { - None - }; - - let initialize_pool_instr = initialize_pool_instr( - &mut light_client, - &pool_config, - mint0, - mint1, - token_0_program, - token_1_program, - spl_associated_token_account::get_associated_token_address_with_program_id( - &payer.pubkey(), - &mint0, - &token_0_program, - ), - spl_associated_token_account::get_associated_token_address_with_program_id( - &payer.pubkey(), - &mint1, - &token_1_program, - ), - raydium_cp_swap::create_pool_fee_receiver::ID, - random_pool_id, - init_amount_0, - init_amount_1, - open_time, - ) - .await?; - - let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; - - send_versioned_txn( - &rpc_client, - &initialize_pool_instr, - &signers, - &payer.pubkey(), - &[lookup_table], - true, - )?; - } - RaydiumCpCommands::Deposit { - pool_id, - user_token_0, - user_token_1, - lp_token_amount, - } => { - let pool_state = - get_compressible_account::( - &pool_id, - &pool_config.raydium_cp_program, - &light_client.get_address_tree_v2(), - &mut light_client, - ) - .await?; - - decompress_pool_and_observation_idempotent( - &mut light_client, - &rpc_client, - &pool_config, - pool_id, - pool_state.observation_key, - pool_state.amm_config, - pool_state.token_0_mint, - pool_state.token_1_mint, - ) - .await?; - - let load_pubkeys = vec![pool_state.token_0_vault, pool_state.token_1_vault]; - let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; - let [token_0_vault_account, token_1_vault_account] = array_ref![rsps, 0, 2]; - let token_0_vault_info = unpack_token(&token_0_vault_account.as_ref().unwrap().data)?; - let token_1_vault_info = unpack_token(&token_1_vault_account.as_ref().unwrap().data)?; - - let (total_token_0_amount, total_token_1_amount) = pool_state.vault_amount_without_fee( - u64::from(token_0_vault_info.base.amount), - u64::from(token_1_vault_info.base.amount), - ); - - let results = raydium_cp_swap::curve::CurveCalculator::lp_tokens_to_trading_tokens( - u128::from(lp_token_amount), - u128::from(pool_state.lp_supply), - u128::from(total_token_0_amount), - u128::from(total_token_1_amount), - raydium_cp_swap::curve::RoundDirection::Ceiling, - ) - .ok_or(raydium_cp_swap::error::ErrorCode::ZeroTradingTokens) - .unwrap(); - - let amount_0_with_slippage = - amount_with_slippage(results.token_0_amount as u64, pool_config.slippage, true); - let amount_1_with_slippage = - amount_with_slippage(results.token_1_amount as u64, pool_config.slippage, true); - // calc with transfer_fee - let transfer_fee = get_pool_mints_inverse_fee( - &rpc_client, - pool_state.token_0_mint, - pool_state.token_1_mint, - amount_0_with_slippage, - amount_1_with_slippage, - ); - - let amount_0_max = (amount_0_with_slippage as u64) - .checked_add(transfer_fee.0.transfer_fee) - .unwrap(); - let amount_1_max = (amount_1_with_slippage as u64) - .checked_add(transfer_fee.1.transfer_fee) - .unwrap(); - - let mut instructions = Vec::new(); - let owner_lp_token = compressed_token::get_associated_ctoken_address( - &payer.pubkey(), - &pool_state.lp_mint, - ); - - let deposit_instr = deposit_instr( - &pool_config, - pool_id, - pool_state.token_0_mint, - pool_state.token_1_mint, - pool_state.lp_mint, - pool_state.token_0_vault, - pool_state.token_1_vault, - user_token_0, - user_token_1, - owner_lp_token, - lp_token_amount, - amount_0_max, - amount_1_max, - )?; - instructions.extend(deposit_instr); - let signers = vec![&payer]; - - // Load lookup table - let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; - let lookup_tables = vec![lookup_table]; - - send_versioned_txn( - &rpc_client, - &instructions, - &signers, - &payer.pubkey(), - &lookup_tables, - true, - )?; - } - RaydiumCpCommands::Withdraw { - pool_id, - lp_token_amount, - } => { - // Fetch pool state irrespective of whether it's currently - // compressed or decompressed. - let pool_state = - get_compressible_account::( - &pool_id, - &pool_config.raydium_cp_program, - &light_client.get_address_tree_v2(), - &mut light_client, - ) - .await?; - - decompress_pool_and_observation_idempotent( - &mut light_client, - &rpc_client, - &pool_config, - pool_id, - pool_state.observation_key, - pool_state.amm_config, - pool_state.token_0_mint, - pool_state.token_1_mint, - ) - .await?; - - let load_pubkeys = vec![pool_state.token_0_vault, pool_state.token_1_vault]; - let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; - let [token_0_vault_account, token_1_vault_account] = array_ref![rsps, 0, 2]; - let token_0_vault_info = unpack_token(&token_0_vault_account.as_ref().unwrap().data)?; - let token_1_vault_info = unpack_token(&token_1_vault_account.as_ref().unwrap().data)?; - - let (total_token_0_amount, total_token_1_amount) = pool_state.vault_amount_without_fee( - u64::from(token_0_vault_info.base.amount), - u64::from(token_1_vault_info.base.amount), - ); - - let results = raydium_cp_swap::curve::CurveCalculator::lp_tokens_to_trading_tokens( - u128::from(lp_token_amount), - u128::from(pool_state.lp_supply), - u128::from(total_token_0_amount), - u128::from(total_token_1_amount), - raydium_cp_swap::curve::RoundDirection::Ceiling, - ) - .ok_or(raydium_cp_swap::error::ErrorCode::ZeroTradingTokens) - .unwrap(); - - let amount_0_with_slippage = - amount_with_slippage(results.token_0_amount as u64, pool_config.slippage, false); - let amount_1_with_slippage = - amount_with_slippage(results.token_1_amount as u64, pool_config.slippage, false); - - let transfer_fee = get_pool_mints_transfer_fee( - &rpc_client, - pool_state.token_0_mint, - pool_state.token_1_mint, - amount_0_with_slippage, - amount_1_with_slippage, - ); - - let amount_0_min = amount_0_with_slippage - .checked_sub(transfer_fee.0.transfer_fee) - .unwrap(); - let amount_1_min = amount_1_with_slippage - .checked_sub(transfer_fee.1.transfer_fee) - .unwrap(); - - let mut instructions = Vec::new(); - let create_user_token_0_instr = create_ata_token_account_instr( - &pool_config, - spl_token::id(), - &pool_state.token_0_mint, - &payer.pubkey(), - )?; - instructions.extend(create_user_token_0_instr); - let create_user_token_1_instr = create_ata_token_account_instr( - &pool_config, - spl_token::id(), - &pool_state.token_1_mint, - &payer.pubkey(), - )?; - instructions.extend(create_user_token_1_instr); - let owner_lp_token = compressed_token::get_associated_ctoken_address( - &payer.pubkey(), - &pool_state.lp_mint, - ); - - let withdraw_instr = withdraw_instr( - &pool_config, - pool_id, - pool_state.token_0_mint, - pool_state.token_1_mint, - pool_state.lp_mint, - pool_state.token_0_vault, - pool_state.token_1_vault, - spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &pool_state.token_0_mint, - ), - spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &pool_state.token_1_mint, - ), - owner_lp_token, // Use derived LP token account instead of user_lp_token parameter - lp_token_amount, - amount_0_min, - amount_1_min, - )?; - instructions.extend(withdraw_instr); - let signers = vec![&payer]; - - // Load lookup table - let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; - let lookup_tables = vec![lookup_table]; - - send_versioned_txn( - &rpc_client, - &instructions, - &signers, - &payer.pubkey(), - &lookup_tables, - true, - )?; - } - RaydiumCpCommands::SwapBaseIn { - pool_id, - user_input_token, - user_input_amount, - } => { - // Fetch pool state irrespective of whether it's currently - // compressed or decompressed. - let pool_state = - get_compressible_account::( - &pool_id, - &pool_config.raydium_cp_program, - &light_client.get_address_tree_v2(), - &mut light_client, - ) - .await?; - - decompress_pool_and_observation_idempotent( - &mut light_client, - &rpc_client, - &pool_config, - pool_id, - pool_state.observation_key, - pool_state.amm_config, - pool_state.token_0_mint, - pool_state.token_1_mint, - ) - .await?; - - let load_pubkeys = vec![ - pool_id, - pool_state.amm_config, - pool_state.token_0_vault, - pool_state.token_1_vault, - pool_state.token_0_mint, - pool_state.token_1_mint, - user_input_token, - ]; - let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; - let epoch = rpc_client.get_epoch_info().unwrap().epoch; - let [pool_account, amm_config_account, token_0_vault_account, token_1_vault_account, token_0_mint_account, token_1_mint_account, user_input_token_account] = - array_ref![rsps, 0, 7]; - - let pool_state = deserialize_anchor_account::( - pool_account.as_ref().unwrap(), - ) - .unwrap(); - let amm_config_state = deserialize_anchor_account::( - amm_config_account.as_ref().unwrap(), - )?; - let token_0_vault_info = unpack_token(&token_0_vault_account.as_ref().unwrap().data)?; - let token_1_vault_info = unpack_token(&token_1_vault_account.as_ref().unwrap().data)?; - let token_0_mint_info = unpack_mint(&token_0_mint_account.as_ref().unwrap().data)?; - let token_1_mint_info = unpack_mint(&token_1_mint_account.as_ref().unwrap().data)?; - let user_input_token_info = - unpack_token(&user_input_token_account.as_ref().unwrap().data)?; - - let (total_token_0_amount, total_token_1_amount) = pool_state.vault_amount_without_fee( - u64::from(token_0_vault_info.base.amount), - u64::from(token_1_vault_info.base.amount), - ); - - let ( - trade_direction, - total_input_token_amount, - total_output_token_amount, - user_input_token, - user_output_token, - input_vault, - output_vault, - input_token_mint, - output_token_mint, - input_token_program, - output_token_program, - transfer_fee, - ) = if user_input_token_info.base.mint == token_0_vault_info.base.mint { - ( - raydium_cp_swap::curve::TradeDirection::ZeroForOne, - total_token_0_amount, - total_token_1_amount, - user_input_token, - spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &pool_state.token_1_mint, - ), - pool_state.token_0_vault, - pool_state.token_1_vault, - pool_state.token_0_mint, - pool_state.token_1_mint, - pool_state.token_0_program, - pool_state.token_1_program, - get_transfer_fee(&token_0_mint_info, epoch, user_input_amount), - ) - } else { - ( - raydium_cp_swap::curve::TradeDirection::OneForZero, - total_token_1_amount, - total_token_0_amount, - user_input_token, - spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &pool_state.token_0_mint, - ), - pool_state.token_1_vault, - pool_state.token_0_vault, - pool_state.token_1_mint, - pool_state.token_0_mint, - pool_state.token_1_program, - pool_state.token_0_program, - get_transfer_fee(&token_1_mint_info, epoch, user_input_amount), - ) - }; - - let actual_amount_in = user_input_amount.saturating_sub(transfer_fee); - let result = raydium_cp_swap::curve::CurveCalculator::swap_base_input( - u128::from(actual_amount_in), - u128::from(total_input_token_amount), - u128::from(total_output_token_amount), - amm_config_state.trade_fee_rate, - amm_config_state.protocol_fee_rate, - amm_config_state.fund_fee_rate, - ) - .ok_or(raydium_cp_swap::error::ErrorCode::ZeroTradingTokens) - .unwrap(); - let amount_out = u64::try_from(result.destination_amount_swapped).unwrap(); - let transfer_fee = match trade_direction { - raydium_cp_swap::curve::TradeDirection::ZeroForOne => { - get_transfer_fee(&token_1_mint_info, epoch, amount_out) - } - raydium_cp_swap::curve::TradeDirection::OneForZero => { - get_transfer_fee(&token_0_mint_info, epoch, amount_out) - } - }; - let amount_received = amount_out.checked_sub(transfer_fee).unwrap(); - - let minimum_amount_out = - amount_with_slippage(amount_received, pool_config.slippage, false); - - let mut instructions = Vec::new(); - let create_user_output_token_instr = create_ata_token_account_instr( - &pool_config, - spl_token::id(), - &output_token_mint, - &payer.pubkey(), - )?; - instructions.extend(create_user_output_token_instr); - let swap_base_in_instr = swap_base_input_instr( - &pool_config, - pool_id, - pool_state.amm_config, - pool_state.observation_key, - user_input_token, - user_output_token, - input_vault, - output_vault, - input_token_mint, - output_token_mint, - input_token_program, - output_token_program, - user_input_amount, - minimum_amount_out, - )?; - instructions.extend(swap_base_in_instr); - let signers = vec![&payer]; - - // Load lookup table - let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; - - send_versioned_txn( - &rpc_client, - &instructions, - &signers, - &payer.pubkey(), - &[lookup_table], - true, - )?; - } - RaydiumCpCommands::SwapBaseOut { - pool_id, - user_input_token, - amount_out_less_fee, - } => { - // Fetch pool state irrespective of whether it's currently - // compressed or decompressed. - let pool_state = - get_compressible_account::( - &pool_id, - &pool_config.raydium_cp_program, - &light_client.get_address_tree_v2(), - &mut light_client, - ) - .await?; - - decompress_pool_and_observation_idempotent( - &mut light_client, - &rpc_client, - &pool_config, - pool_id, - pool_state.observation_key, - pool_state.amm_config, - pool_state.token_0_mint, - pool_state.token_1_mint, - ) - .await?; - - let load_pubkeys = vec![ - pool_id, - pool_state.amm_config, - pool_state.token_0_vault, - pool_state.token_1_vault, - pool_state.token_0_mint, - pool_state.token_1_mint, - user_input_token, - ]; - let rsps = rpc_client.get_multiple_accounts(&load_pubkeys)?; - let epoch = rpc_client.get_epoch_info().unwrap().epoch; - let [pool_account, amm_config_account, token_0_vault_account, token_1_vault_account, token_0_mint_account, token_1_mint_account, user_input_token_account] = - array_ref![rsps, 0, 7]; - - let pool_state = deserialize_anchor_account::( - pool_account.as_ref().unwrap(), - ) - .unwrap(); - let amm_config_state = deserialize_anchor_account::( - amm_config_account.as_ref().unwrap(), - )?; - let token_0_vault_info = unpack_token(&token_0_vault_account.as_ref().unwrap().data)?; - let token_1_vault_info = unpack_token(&token_1_vault_account.as_ref().unwrap().data)?; - let token_0_mint_info = unpack_mint(&token_0_mint_account.as_ref().unwrap().data)?; - let token_1_mint_info = unpack_mint(&token_1_mint_account.as_ref().unwrap().data)?; - let user_input_token_info = - unpack_token(&user_input_token_account.as_ref().unwrap().data)?; - - let (total_token_0_amount, total_token_1_amount) = pool_state.vault_amount_without_fee( - u64::from(token_0_vault_info.base.amount), - u64::from(token_1_vault_info.base.amount), - ); - - let ( - trade_direction, - total_input_token_amount, - total_output_token_amount, - user_input_token, - user_output_token, - input_vault, - output_vault, - input_token_mint, - output_token_mint, - input_token_program, - output_token_program, - out_transfer_fee, - ) = if user_input_token_info.base.mint == token_0_vault_info.base.mint { - ( - raydium_cp_swap::curve::TradeDirection::ZeroForOne, - total_token_0_amount, - total_token_1_amount, - user_input_token, - spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &pool_state.token_1_mint, - ), - pool_state.token_0_vault, - pool_state.token_1_vault, - pool_state.token_0_mint, - pool_state.token_1_mint, - pool_state.token_0_program, - pool_state.token_1_program, - get_transfer_inverse_fee(&token_1_mint_info, epoch, amount_out_less_fee), - ) - } else { - ( - raydium_cp_swap::curve::TradeDirection::OneForZero, - total_token_1_amount, - total_token_0_amount, - user_input_token, - spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &pool_state.token_0_mint, - ), - pool_state.token_1_vault, - pool_state.token_0_vault, - pool_state.token_1_mint, - pool_state.token_0_mint, - pool_state.token_1_program, - pool_state.token_0_program, - get_transfer_inverse_fee(&token_0_mint_info, epoch, amount_out_less_fee), - ) - }; - let actual_amount_out = amount_out_less_fee.checked_add(out_transfer_fee).unwrap(); - - let result = raydium_cp_swap::curve::CurveCalculator::swap_base_output( - u128::from(actual_amount_out), - u128::from(total_input_token_amount), - u128::from(total_output_token_amount), - amm_config_state.trade_fee_rate, - amm_config_state.protocol_fee_rate, - amm_config_state.fund_fee_rate, - ) - .ok_or(raydium_cp_swap::error::ErrorCode::ZeroTradingTokens) - .unwrap(); - - let source_amount_swapped = u64::try_from(result.source_amount_swapped).unwrap(); - let amount_in_transfer_fee = match trade_direction { - raydium_cp_swap::curve::TradeDirection::ZeroForOne => { - get_transfer_inverse_fee(&token_0_mint_info, epoch, source_amount_swapped) - } - raydium_cp_swap::curve::TradeDirection::OneForZero => { - get_transfer_inverse_fee(&token_1_mint_info, epoch, source_amount_swapped) - } - }; - - let input_transfer_amount = source_amount_swapped - .checked_add(amount_in_transfer_fee) - .unwrap(); - - let max_amount_in = - amount_with_slippage(input_transfer_amount, pool_config.slippage, true); - let mut instructions = Vec::new(); - let create_user_output_token_instr = create_ata_token_account_instr( - &pool_config, - spl_token::id(), - &output_token_mint, - &payer.pubkey(), - )?; - instructions.extend(create_user_output_token_instr); - let swap_base_in_instr = swap_base_output_instr( - &pool_config, - pool_id, - pool_state.amm_config, - pool_state.observation_key, - user_input_token, - user_output_token, - input_vault, - output_vault, - input_token_mint, - output_token_mint, - input_token_program, - output_token_program, - max_amount_in, - amount_out_less_fee, - )?; - instructions.extend(swap_base_in_instr); - let signers = vec![&payer]; - - // Load lookup table - let lookup_table = load_lookup_table(&rpc_client, &LOOKUP_TABLE_ADDRESS)?; - - send_versioned_txn( - &rpc_client, - &instructions, - &signers, - &payer.pubkey(), - &[lookup_table], - true, - )?; - } - RaydiumCpCommands::DecodeInstruction { instr_hex_data } => { - handle_program_instruction(&instr_hex_data, InstructionDecodeType::BaseHex)?; - } - RaydiumCpCommands::DecodeEvent { log_event } => { - handle_program_log( - &pool_config.raydium_cp_program.to_string(), - &log_event, - false, - )?; - } - RaydiumCpCommands::DecodeTxLog { tx_id } => { - let signature = Signature::from_str(&tx_id)?; - let tx = rpc_client.get_transaction_with_config( - &signature, - RpcTransactionConfig { - encoding: Some(UiTransactionEncoding::Json), - commitment: Some(CommitmentConfig::confirmed()), - max_supported_transaction_version: Some(0), - }, - )?; - let transaction = tx.transaction; - // get meta - let meta = if transaction.meta.is_some() { - transaction.meta - } else { - None - }; - // get encoded_transaction - let encoded_transaction = transaction.transaction; - // decode instruction data - parse_program_instruction( - &pool_config.raydium_cp_program.to_string(), - encoded_transaction, - meta.clone(), - )?; - // decode logs - parse_program_event(&pool_config.raydium_cp_program.to_string(), meta.clone())?; - } - RaydiumCpCommands::InitCompressionConfig {} => { - let authority = read_keypair_file(&pool_config.admin_path)?; - initialize_compression_config(&rpc_client, &pool_config, &authority).await?; - } - RaydiumCpCommands::CreateMint { - decimals, - save_keypair, - } => { - use crate::instructions::rpc::send_txn; - use crate::instructions::token_instructions::*; - - let mint_keypair = Keypair::new(); - let token_program = spl_token::id(); - let mint_authority = payer.pubkey(); - let freeze_authority = Some(&mint_authority); - - let mut light_client = LightClient::new(LightClientConfig::local()).await?; - - let create_mint_ixs = create_and_init_mint_instr( - &pool_config, - token_program, - &mint_keypair.pubkey(), - &mint_authority, - freeze_authority, - decimals, - ) - .await?; - - let create_ata_ixs = create_ata_token_account_instr( - &pool_config, - token_program, - &mint_keypair.pubkey(), - &payer.pubkey(), - )?; - - let mint_amount = 1_000_000 * 10_u64.pow(decimals as u32); - let ata_address = spl_associated_token_account::get_associated_token_address( - &payer.pubkey(), - &mint_keypair.pubkey(), - ); - - let mint_to_ixs = spl_token_mint_to_instr( - &pool_config, - token_program, - &mint_keypair.pubkey(), - &ata_address, - mint_amount, - &payer, - )?; - - let mut all_instructions = Vec::new(); - all_instructions.extend(create_mint_ixs); - all_instructions.extend(create_ata_ixs); - all_instructions.extend(mint_to_ixs); - - let recent_blockhash = rpc_client.get_latest_blockhash()?; - let transaction = solana_sdk::transaction::Transaction::new_signed_with_payer( - &all_instructions, - Some(&payer.pubkey()), - &[&payer, &mint_keypair], - recent_blockhash, - ); - - let signature = send_txn(&rpc_client, &transaction, true)?; - - // Each SPL mint has to be registered with the compression protocol via a compression token pool. - create_token_pool(&mut light_client, &mint_keypair.pubkey(), false, &payer).await?; - - println!("Mint Address: {}", mint_keypair.pubkey().to_string()); - println!("Your Token Account: {}", ata_address.to_string()); - println!( - "Minted Amount: {} tokens", - mint_amount / 10_u64.pow(decimals as u32) - ); - println!("Transaction Signature: {}", signature.to_string()); - - if let Some(path) = save_keypair { - std::fs::write( - &path, - serde_json::to_string(&mint_keypair.to_bytes().to_vec())?, - )?; - println!("Mint keypair saved to: {}", path); - } - } - } - Ok(()) -} diff --git a/client_config.ini b/client_config.ini deleted file mode 100644 index 8df7f49..0000000 --- a/client_config.ini +++ /dev/null @@ -1,9 +0,0 @@ -[Global] -http_url = http://127.0.0.1:8899 -ws_url = ws://127.0.0.1:8900/ -# Replace this example path with an absolute path to your solana id.json file -# (often: your_username/.config/solana/id.json) -payer_path = id.json -admin_path = id.json -raydium_cp_program = CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C -slippage = 0.01 \ No newline at end of file diff --git a/programs/cp-swap/Cargo.toml b/programs/cp-swap/Cargo.toml index cba84f1..2c8dfb7 100644 --- a/programs/cp-swap/Cargo.toml +++ b/programs/cp-swap/Cargo.toml @@ -24,7 +24,7 @@ test-sbf = [] [dependencies] anchor-lang = { version = "=0.31.1", features = ["init-if-needed", "idl-build"] } -anchor-spl = { version = "=0.31.1", git = "https://github.com/lightprotocol/anchor", rev = "d8a2b3d9", features = ["memo", "metadata", "idl-build"] } +anchor-spl = { version = "=0.31.1", git = "https://github.com/lightprotocol/anchor", rev = "da005d7f", features = ["memo", "idl-build"] } spl-token-2022 = { version = "7.0.0", features = ["no-entrypoint"] } spl-math = { version = "0.3", features = ["no-entrypoint"] } uint = "0.10.0" @@ -32,24 +32,34 @@ solana-security-txt = "1.1.1" bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] } arrayref = { version = "0.3.6" } -light-sdk = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor", "anchor-discriminator-compat", "v2"] } -light-sdk-types = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } -light-hasher = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["solana"] } -light-macros = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["solana"] } -light-sdk-macros = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor-discriminator-compat"] } -light-compressed-account = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } -light-compressed-token-sdk = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } -light-ctoken-types = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } - +light-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor", "anchor-discriminator", "v2", "idl-build", "cpi-context"] } +light-hasher = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121" } +light-sdk-types = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["v2", "cpi-context"] } +light-sdk-macros = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor-discriminator"] } +light-compressible = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor"] } +light-token-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor", "compressible"] } +light-compressed-account = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121" } +solana-account-info = "2.3" +solana-program = "2.2" +solana-pubkey = "2.2" +solana-program-error = "2.2" +solana-cpi = { version = "2.2" } +solana-msg = "2.2" [dev-dependencies] quickcheck = "1.0.3" proptest = "1.0" rand = "0.9.0" -light-program-test = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } -light-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["v2"] } -light-compressible-client = { git = "https://github.com/lightprotocol/light-protocol", tag = "csdk-0.3.3", features = ["anchor"] } +light-program-test = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["v2"] } +light-client = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["v2"] } +light-compressible-client = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor"] } +tokio = { version = "1", features = ["full"] } +spl-token = "7.0.0" +solana-keypair = { version = "2.2" } +solana-signer = { version = "2.2" } +solana-instruction = { version = "2.2" } +solana-sdk = { version = "2.3" } [profile.release] @@ -61,3 +71,11 @@ overflow-checks = true opt-level = 3 incremental = false codegen-units = 1 + + +[lints.rust.unexpected_cfgs] +level = "allow" +check-cfg = [ + 'cfg(target_os, values("solana"))', + 'cfg(feature, values("frozen-abi", "no-entrypoint"))', +] diff --git a/programs/cp-swap/src/error.rs b/programs/cp-swap/src/error.rs index 5a55cbb..661b41c 100644 --- a/programs/cp-swap/src/error.rs +++ b/programs/cp-swap/src/error.rs @@ -39,4 +39,6 @@ pub enum ErrorCode { InvalidRentRecipient, #[msg("Invalid LP mint address derivation")] InvalidLpMintAddress, + #[msg("Invalid account data")] + InvalidAccountData, } diff --git a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs index 9442c6c..15211e4 100644 --- a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs @@ -1,6 +1,5 @@ use crate::error::ErrorCode; use crate::states::*; -use crate::utils::ctoken::get_bumps; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_spl::token::Token; @@ -70,16 +69,10 @@ pub struct CollectFundFee<'info> { /// The SPL program 2022 to perform token transfers pub token_program_2022: Program<'info, Token2022>, - /// CHECK: checked by protocol. - pub compressed_token_program_cpi_authority: AccountInfo<'info>, - /// CHECK: checked by protocol. - pub compressed_token_program: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_0_pool_pda: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_1_pool_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, + + /// CHECK: light_token CPI authority. + pub light_token_cpi_authority: AccountInfo<'info>, } pub fn collect_fund_fee( @@ -100,13 +93,8 @@ pub fn collect_fund_fee( auth_bump = pool_state.auth_bump; pool_state.recent_epoch = Clock::get()?.epoch; } - let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( - ctx.accounts.vault_0_mint.key(), - ctx.accounts.vault_1_mint.key(), - ctx.accounts.compressed_token_program.key(), - ); + transfer_from_pool_vault_to_user( - ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.recipient_token_0_account.to_account_info(), @@ -116,17 +104,14 @@ pub fn collect_fund_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_0_pool_pda.to_account_info(), - compressed_token_0_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), amount_0, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; transfer_from_pool_vault_to_user( - ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.recipient_token_1_account.to_account_info(), @@ -136,13 +121,11 @@ pub fn collect_fund_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_1_pool_pda.to_account_info(), - compressed_token_1_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), amount_1, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; Ok(()) diff --git a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs index 520e0ed..9be9be6 100644 --- a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs @@ -1,6 +1,5 @@ use crate::error::ErrorCode; use crate::states::*; -use crate::utils::ctoken::get_bumps; use crate::utils::*; use anchor_lang::prelude::*; use anchor_spl::token::Token; @@ -71,16 +70,10 @@ pub struct CollectProtocolFee<'info> { /// The SPL program 2022 to perform token transfers pub token_program_2022: Program<'info, Token2022>, - /// CHECK: checked by protocol. - pub compressed_token_program_cpi_authority: AccountInfo<'info>, - /// CHECK: checked by protocol. - pub compressed_token_program: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_0_pool_pda: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_1_pool_pda: AccountInfo<'info>, + pub system_program: Program<'info, System>, + + /// CHECK: light_token CPI authority. + pub light_token_cpi_authority: AccountInfo<'info>, } pub fn collect_protocol_fee( @@ -110,14 +103,7 @@ pub fn collect_protocol_fee( pool_state.recent_epoch = Clock::get()?.epoch; } - let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( - ctx.accounts.vault_0_mint.key(), - ctx.accounts.vault_1_mint.key(), - ctx.accounts.compressed_token_program.key(), - ); - transfer_from_pool_vault_to_user( - ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.recipient_token_0_account.to_account_info(), @@ -127,17 +113,14 @@ pub fn collect_protocol_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_0_pool_pda.to_account_info(), - compressed_token_0_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), amount_0, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; transfer_from_pool_vault_to_user( - ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.recipient_token_1_account.to_account_info(), @@ -147,13 +130,11 @@ pub fn collect_protocol_fee( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_1_pool_pda.to_account_info(), - compressed_token_1_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), amount_1, &[&[crate::AUTH_SEED.as_bytes(), &[auth_bump]]], + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; Ok(()) diff --git a/programs/cp-swap/src/instructions/deposit.rs b/programs/cp-swap/src/instructions/deposit.rs index adbfb76..4a6ca75 100644 --- a/programs/cp-swap/src/instructions/deposit.rs +++ b/programs/cp-swap/src/instructions/deposit.rs @@ -2,13 +2,12 @@ use crate::curve::CurveCalculator; use crate::curve::RoundDirection; use crate::error::ErrorCode; use crate::states::*; -use crate::utils::ctoken::get_bumps; use crate::utils::token::*; -use crate::utils::transfer_ctoken_from_pool_vault_to_user; use anchor_lang::prelude::*; use anchor_spl::token::Token; -use anchor_spl::token_interface::{Mint, Token2022, TokenAccount}; -use light_sdk::compressible::HasCompressionInfo; +use anchor_spl::token_interface::Token2022; +use light_token_sdk::token::MintToCpi; +use anchor_spl::token_interface::{TokenAccount, Mint,TokenInterface}; #[derive(Accounts)] pub struct Deposit<'info> { @@ -17,6 +16,7 @@ pub struct Deposit<'info> { /// CHECK: pool vault and lp mint authority #[account( + mut, seeds = [ crate::AUTH_SEED.as_bytes(), ], @@ -67,6 +67,9 @@ pub struct Deposit<'info> { /// Token program 2022 pub token_program_2022: Program<'info, Token2022>, + /// CHECK: Light Token program for CPI. + pub light_token_program: Interface<'info, TokenInterface>, + /// The mint of token_0 vault #[account( address = token_0_vault.mint @@ -79,33 +82,17 @@ pub struct Deposit<'info> { )] pub vault_1_mint: Box>, - /// Lp token vault + /// Lp mint #[account( mut, - seeds = [ - POOL_VAULT_SEED.as_bytes(), - pool_state.lp_mint.as_ref() - ], - bump, - token::mint = lp_vault.mint, - token::authority = authority + address = pool_state.lp_mint @ ErrorCode::IncorrectLpMint )] - pub lp_vault: Box>, + pub lp_mint: Box>, - /// CHECK: checked by protocol. - pub compressed_token_program_cpi_authority: AccountInfo<'info>, - /// CHECK: checked by protocol. - pub compressed_token_program: AccountInfo<'info>, + pub system_program: Program<'info, System>, - /// CHECK: checked by protocol. - /// - /// Every mint must be registered in the compression protocol via a - /// compression_token_pool_pda. - #[account(mut)] - pub compressed_token_0_pool_pda: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_1_pool_pda: AccountInfo<'info>, + /// CHECK: light-token CPI authority. + pub light_token_cpi_authority: AccountInfo<'info>, } pub fn deposit( @@ -155,6 +142,18 @@ pub fn deposit( ) }; + #[cfg(feature = "enable-log")] + msg!( + "results.token_0_amount;{}, results.token_1_amount:{},transfer_token_0_amount:{},transfer_token_0_fee:{}, + transfer_token_1_amount:{},transfer_token_1_fee:{}", + results.token_0_amount, + results.token_1_amount, + transfer_token_0_amount, + transfer_token_0_fee, + transfer_token_1_amount, + transfer_token_1_fee + ); + emit!(LpChangeEvent { pool_id, lp_amount_before: pool_state.lp_supply, @@ -172,11 +171,6 @@ pub fn deposit( { return Err(ErrorCode::ExceededSlippage.into()); } - let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( - ctx.accounts.vault_0_mint.key(), - ctx.accounts.vault_1_mint.key(), - ctx.accounts.compressed_token_program.key(), - ); transfer_from_user_to_pool_vault( ctx.accounts.owner.to_account_info(), @@ -188,12 +182,10 @@ pub fn deposit( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_0_pool_pda.to_account_info(), - compressed_token_0_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), transfer_token_0_amount, + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; transfer_from_user_to_pool_vault( @@ -206,27 +198,24 @@ pub fn deposit( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_1_pool_pda.to_account_info(), - compressed_token_1_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), transfer_token_1_amount, + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; pool_state.lp_supply = pool_state.lp_supply.checked_add(lp_token_amount).unwrap(); - transfer_ctoken_from_pool_vault_to_user( - ctx.accounts.authority.to_account_info(), - ctx.accounts.lp_vault.to_account_info(), - ctx.accounts.owner_lp_token.to_account_info(), - lp_token_amount, - &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], - )?; + MintToCpi { + mint: ctx.accounts.lp_mint.to_account_info(), + destination: ctx.accounts.owner_lp_token.to_account_info(), + amount: lp_token_amount, + authority: ctx.accounts.authority.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + max_top_up: None, + } + .invoke_signed(&[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]])?; pool_state.recent_epoch = Clock::get()?.epoch; - // The account was written to, so we must update CompressionInfo. - pool_state.compression_info_mut().bump_last_written_slot()?; - Ok(()) } diff --git a/programs/cp-swap/src/instructions/initialize.rs b/programs/cp-swap/src/instructions/initialize.rs index 80329aa..9dad480 100644 --- a/programs/cp-swap/src/instructions/initialize.rs +++ b/programs/cp-swap/src/instructions/initialize.rs @@ -13,37 +13,44 @@ use anchor_spl::{ token::Token, token_interface::{Mint, TokenAccount, TokenInterface}, }; -use light_sdk::cpi::CpiAccountsSmall; -use light_sdk::{ - compressible::CompressibleConfig, - instruction::{borsh_compat::ValidityProof, PackedAddressTreeInfo}, +use light_compressible::CreateAccountsProof; +use light_sdk_macros::LightAccounts; +use light_token_sdk::{ + token::{ + CreateTokenAccountCpi, CreateTokenAtaCpi, MintToCpi, COMPRESSIBLE_CONFIG_V1, + RENT_SPONSOR as LIGHT_TOKEN_RENT_SPONSOR, + }, + utils::get_token_account_balance, }; -use light_sdk_types::CpiAccountsConfig; -use crate::LIGHT_CPI_SIGNER; -use spl_token_2022; -use std::ops::Deref; +pub const LP_MINT_SIGNER_SEED: &[u8] = b"pool_lp_mint"; -#[derive(Accounts)] +#[derive(AnchorSerialize, AnchorDeserialize, Clone)] +pub struct InitializeParams { + pub init_amount_0: u64, + pub init_amount_1: u64, + pub open_time: u64, + pub create_accounts_proof: CreateAccountsProof, + pub lp_mint_signer_bump: u8, + pub creator_lp_token_bump: u8, + pub authority_bump: u8, +} + +#[derive(Accounts, LightAccounts)] +#[instruction(params: InitializeParams)] pub struct Initialize<'info> { - /// Address paying to create the pool. Can be anyone #[account(mut)] pub creator: Signer<'info>, - /// Which config the pool belongs to. pub amm_config: Box>, - /// CHECK: - /// pool vault and lp mint authority #[account( - seeds = [ - crate::AUTH_SEED.as_bytes(), - ], + mut, + seeds = [crate::AUTH_SEED.as_bytes()], bump, )] pub authority: UncheckedAccount<'info>, - /// CHECK: Initialize an account to store the pool state #[account( init, seeds = [ @@ -54,38 +61,36 @@ pub struct Initialize<'info> { ], bump, payer = creator, - space = PoolState::INIT_SPACE + space = 8 + PoolState::INIT_SPACE )] + #[light_account(init)] pub pool_state: Box>, - /// Token_0 mint, the key must smaller than token_1 mint. #[account( constraint = token_0_mint.key() < token_1_mint.key(), mint::token_program = token_0_program, )] pub token_0_mint: Box>, - /// Token_1 mint, the key must grater then token_0 mint. - #[account( - mint::token_program = token_1_program, - )] + #[account(mint::token_program = token_1_program)] pub token_1_mint: Box>, - /// Signer pda used to derive lp_mint and its compressed address. - /// CHECK: checked by protocol. #[account( - seeds = [ - POOL_LP_MINT_SEED.as_bytes(), - pool_state.key().as_ref(), - ], + seeds = [LP_MINT_SIGNER_SEED, pool_state.key().as_ref()], bump, )] pub lp_mint_signer: UncheckedAccount<'info>, - /// CHECK: checked via mint_signer. + #[account(mut)] + #[light_account(init, mint, + mint_signer = lp_mint_signer, + authority = authority, + decimals = 9, + mint_seeds = &[LP_MINT_SIGNER_SEED, self.pool_state.to_account_info().key.as_ref(), &[params.lp_mint_signer_bump]], + authority_seeds = &[crate::AUTH_SEED.as_bytes(), &[params.authority_bump]] + )] pub lp_mint: UncheckedAccount<'info>, - /// payer token0 account #[account( mut, token::mint = token_0_mint, @@ -93,7 +98,6 @@ pub struct Initialize<'info> { )] pub creator_token_0: Box>, - /// creator token1 account #[account( mut, token::mint = token_1_mint, @@ -101,22 +105,9 @@ pub struct Initialize<'info> { )] pub creator_token_1: Box>, - /// CHECK: #[account(mut)] pub creator_lp_token: UncheckedAccount<'info>, - /// CHECK: - #[account( - mut, - seeds = [ - POOL_VAULT_SEED.as_bytes(), - lp_mint.key().as_ref() - ], - bump, - )] - pub lp_vault: UncheckedAccount<'info>, - - /// CHECK: Token_0 vault for the pool, created by contract #[account( mut, seeds = [ @@ -126,9 +117,9 @@ pub struct Initialize<'info> { ], bump, )] + #[light_account(token, authority = [crate::AUTH_SEED.as_bytes()])] pub token_0_vault: UncheckedAccount<'info>, - /// CHECK: Token_1 vault for the pool, created by contract #[account( mut, seeds = [ @@ -138,73 +129,50 @@ pub struct Initialize<'info> { ], bump, )] + #[light_account(token, authority = [crate::AUTH_SEED.as_bytes()])] pub token_1_vault: UncheckedAccount<'info>, - /// create pool fee account - #[account( - mut, - address= crate::create_pool_fee_receiver::ID, - )] - pub create_pool_fee: Box>, - - /// an account to store oracle observations #[account( init, - seeds = [ - OBSERVATION_SEED.as_bytes(), - pool_state.key().as_ref(), - ], + seeds = [OBSERVATION_SEED.as_bytes(), pool_state.key().as_ref()], bump, payer = creator, - space = ObservationState::INIT_SPACE + space = 8 + ObservationState::INIT_SPACE )] + #[light_account(init)] pub observation_state: Box>, - /// Program to create mint account and mint tokens + #[account(mut, address = crate::create_pool_fee_receiver::ID)] + pub create_pool_fee: Box>, + pub token_program: Program<'info, Token>, - /// Spl token program or token program 2022 pub token_0_program: Interface<'info, TokenInterface>, - /// Spl token program or token program 2022 pub token_1_program: Interface<'info, TokenInterface>, - /// Program to create an ATA for receiving position NFT pub associated_token_program: Program<'info, AssociatedToken>, - /// To create a new program account pub system_program: Program<'info, System>, - /// Sysvar for program account pub rent: Sysvar<'info, Rent>, - /// CHECK: checked via load_checked. pub compression_config: AccountInfo<'info>, - /// CHECK: checked in instruction. - #[account(mut)] - pub rent_recipient: AccountInfo<'info>, - /// CHECK: checked by protocol. - pub compressed_token_program_cpi_authority: AccountInfo<'info>, - /// CHECK: checked by protocol. - pub compressed_token_program: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_0_pool_pda: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_1_pool_pda: AccountInfo<'info>, + + #[account(address = COMPRESSIBLE_CONFIG_V1)] + pub light_token_compressible_config: AccountInfo<'info>, + + #[account(mut, address = LIGHT_TOKEN_RENT_SPONSOR)] + pub light_token_rent_sponsor: AccountInfo<'info>, + + pub light_token_program: AccountInfo<'info>, + + /// CHECK: light-token CPI authority. + pub light_token_cpi_authority: AccountInfo<'info>, } -// This instruction: -// 0. Runs checks and loads compression config. -// 1. Creates token vault accounts for pool tokens as compressible. -// 2. Creates user token accounts as compressible. -// 3. Initializes PoolState and ObservationState as compressible. -// 4. Creates compressed token mint for LP tokens. -// 5. Distributes initial liquidity to user and vault. -// 6. Compresses PoolState and ObservationState. pub fn initialize<'info>( ctx: Context<'_, '_, '_, 'info, Initialize<'info>>, - init_amount_0: u64, - init_amount_1: u64, - mut open_time: u64, - compression_params: InitializeCompressionParams, + params: InitializeParams, ) -> Result<()> { + let init_amount_0 = params.init_amount_0; + let init_amount_1 = params.init_amount_1; + let mut open_time = params.open_time; if !(is_supported_mint(&ctx.accounts.token_0_mint).unwrap() && is_supported_mint(&ctx.accounts.token_1_mint).unwrap()) { @@ -215,79 +183,65 @@ pub fn initialize<'info>( return err!(ErrorCode::NotApproved); } - // ZK Compression Step 1: Load compression config and check rent recipient - let compression_config = - CompressibleConfig::load_checked(&ctx.accounts.compression_config, &crate::ID)?; - let rent_recipient = &ctx.accounts.rent_recipient; - if rent_recipient.key() != compression_config.rent_recipient { - return err!(ErrorCode::InvalidRentRecipient); - } - let block_timestamp = clock::Clock::get()?.unix_timestamp as u64; - if open_time <= block_timestamp { + // open_time=0 means immediately open (no bump) + if open_time != 0 && open_time <= block_timestamp { open_time = block_timestamp + 1; } - create_compressible_token_account( - &ctx.accounts.authority.to_account_info(), - &ctx.accounts.creator.to_account_info(), - &ctx.accounts.token_0_vault.to_account_info(), - &ctx.accounts.token_0_mint.to_account_info(), - &ctx.accounts.system_program.to_account_info(), - &ctx.accounts.compressed_token_program.to_account_info(), - &[ - POOL_VAULT_SEED.as_bytes(), - ctx.accounts.pool_state.key().as_ref(), - ctx.accounts.token_0_mint.key().as_ref(), - &[ctx.bumps.token_0_vault][..], - ], - &ctx.accounts.rent.to_account_info(), - &ctx.accounts.rent_recipient.to_account_info(), - compression_config.compression_delay as u64, - )?; - - create_compressible_token_account( - &ctx.accounts.authority.to_account_info(), - &ctx.accounts.creator.to_account_info(), - &ctx.accounts.token_1_vault.to_account_info(), - &ctx.accounts.token_1_mint.to_account_info(), - &ctx.accounts.system_program.to_account_info(), - &ctx.accounts.compressed_token_program.to_account_info(), - &[ - POOL_VAULT_SEED.as_bytes(), - ctx.accounts.pool_state.key().as_ref(), - ctx.accounts.token_1_mint.key().as_ref(), - &[ctx.bumps.token_1_vault][..], - ], - &ctx.accounts.rent_recipient.to_account_info(), - &ctx.accounts.rent_recipient.to_account_info(), - compression_config.compression_delay as u64, - )?; - - let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( - ctx.accounts.token_0_mint.key(), - ctx.accounts.token_1_mint.key(), - ctx.accounts.compressed_token_program.key(), - ); - - let pool_state = &mut ctx.accounts.pool_state; - let pool_state_key = pool_state.key(); - let observation_state = &mut ctx.accounts.observation_state; - let observation_state_key = observation_state.key(); - observation_state.pool_id = pool_state_key; + let pool_state_key = ctx.accounts.pool_state.key(); + // Create token_0 vault + CreateTokenAccountCpi { + payer: ctx.accounts.creator.to_account_info(), + account: ctx.accounts.token_0_vault.to_account_info(), + mint: ctx.accounts.token_0_mint.to_account_info(), + owner: ctx.accounts.authority.key(), + } + .rent_free( + ctx.accounts.light_token_compressible_config.to_account_info(), + ctx.accounts.light_token_rent_sponsor.to_account_info(), + ctx.accounts.system_program.to_account_info(), + &crate::ID, + ) + .invoke_signed(&[ + POOL_VAULT_SEED.as_bytes(), + pool_state_key.as_ref(), + ctx.accounts.token_0_mint.key().as_ref(), + &[ctx.bumps.token_0_vault], + ])?; + + // Create token_1 vault + CreateTokenAccountCpi { + payer: ctx.accounts.creator.to_account_info(), + account: ctx.accounts.token_1_vault.to_account_info(), + mint: ctx.accounts.token_1_mint.to_account_info(), + owner: ctx.accounts.authority.key(), + } + .rent_free( + ctx.accounts.light_token_compressible_config.to_account_info(), + ctx.accounts.light_token_rent_sponsor.to_account_info(), + ctx.accounts.system_program.to_account_info(), + &crate::ID, + ) + .invoke_signed(&[ + POOL_VAULT_SEED.as_bytes(), + pool_state_key.as_ref(), + ctx.accounts.token_1_mint.key().as_ref(), + &[ctx.bumps.token_1_vault], + ])?; + + // Transfer tokens from creator to vaults transfer_from_user_to_pool_vault( ctx.accounts.creator.to_account_info(), ctx.accounts.creator_token_0.to_account_info(), ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.token_0_mint.to_account_info(), ctx.accounts.token_0_program.to_account_info(), - ctx.accounts.compressed_token_0_pool_pda.to_account_info(), - compressed_token_0_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), init_amount_0, + ctx.accounts.creator.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; transfer_from_user_to_pool_vault( @@ -296,34 +250,21 @@ pub fn initialize<'info>( ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.token_1_mint.to_account_info(), ctx.accounts.token_1_program.to_account_info(), - ctx.accounts.compressed_token_1_pool_pda.to_account_info(), - compressed_token_1_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), init_amount_1, + ctx.accounts.creator.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; - let token_0_vault = - spl_token_2022::extension::StateWithExtensions::::unpack( - ctx.accounts - .token_0_vault - .to_account_info() - .try_borrow_data()? - .deref(), - )? - .base; - let token_1_vault = - spl_token_2022::extension::StateWithExtensions::::unpack( - ctx.accounts - .token_1_vault - .to_account_info() - .try_borrow_data()? - .deref(), - )? - .base; - - CurveCalculator::validate_supply(token_0_vault.amount, token_1_vault.amount)?; + // Get vault balances - supports both light token and spl token accounts + let token_0_vault_balance = + get_token_account_balance(&ctx.accounts.token_0_vault.to_account_info()) + .map_err(|_| ErrorCode::InvalidAccountData)?; + let token_1_vault_balance = + get_token_account_balance(&ctx.accounts.token_1_vault.to_account_info()) + .map_err(|_| ErrorCode::InvalidAccountData)?; + + CurveCalculator::validate_supply(token_0_vault_balance, token_1_vault_balance)?; // Charge the fee to create a pool if ctx.accounts.amm_config.create_pool_fee != 0 { @@ -350,8 +291,9 @@ pub fn initialize<'info>( ], )?; } - let liquidity = U128::from(token_0_vault.amount) - .checked_mul(token_1_vault.amount.into()) + + let liquidity = U128::from(token_0_vault_balance) + .checked_mul(token_1_vault_balance.into()) .unwrap() .integer_sqrt() .as_u64(); @@ -360,9 +302,11 @@ pub fn initialize<'info>( let user_lp_amount = liquidity .checked_sub(lock_lp_amount) .ok_or(ErrorCode::InitLpAmountTooLess)?; - let vault_lp_amount = u64::MAX - .checked_sub(user_lp_amount) - .ok_or(ErrorCode::InitLpAmountTooLess)?; + + let pool_state = &mut ctx.accounts.pool_state; + let observation_state = &mut ctx.accounts.observation_state; + let observation_state_key = observation_state.key(); + observation_state.pool_id = pool_state_key; pool_state.initialize( ctx.bumps.authority, @@ -374,110 +318,36 @@ pub fn initialize<'info>( ctx.accounts.token_1_vault.key(), &ctx.accounts.token_0_mint, &ctx.accounts.token_1_mint, - &ctx.accounts.lp_vault, &ctx.accounts.lp_mint, observation_state_key, ); - let pool_auth_bump = pool_state.auth_bump; - - // ZK Compression Step 2: Setup CPI accounts. We compress PDAs **and** - // create a cMint (lp_mint), so we need to use 'with_cpi_context'. - let cpi_accounts = CpiAccountsSmall::new_with_config( - &ctx.accounts.creator, - ctx.remaining_accounts, - CpiAccountsConfig::new_with_cpi_context(LIGHT_CPI_SIGNER), - ); - - // ZK Compression Step 3: Compress the PDAs. - compress_pool_and_observation_pdas( - &cpi_accounts, - &pool_state, - &observation_state, - &compression_params, - &rent_recipient, - &compression_config.address_space, - )?; - - // ZK Compression Step 4: Create ctoken accounts. These match regular - // SPL token accounts but are compressible. - create_compressible_token_account( - &ctx.accounts.authority.to_account_info(), - &ctx.accounts.creator.to_account_info(), - &ctx.accounts.lp_vault.to_account_info(), - &ctx.accounts.lp_mint.to_account_info(), - &ctx.accounts.system_program.to_account_info(), - &ctx.accounts.compressed_token_program.to_account_info(), - &[ - POOL_VAULT_SEED.as_bytes(), - ctx.accounts.lp_mint.key().as_ref(), - &[ctx.bumps.lp_vault][..], - ], - &ctx.accounts.rent.to_account_info(), - &ctx.accounts.rent_recipient.to_account_info(), - compression_config.compression_delay as u64, - )?; - create_compressible_associated_token_account( - &ctx.accounts.creator.to_account_info(), - &ctx.accounts.creator.to_account_info(), - &ctx.accounts.creator_lp_token.to_account_info(), - &ctx.accounts.lp_mint.to_account_info(), - &ctx.accounts.system_program.to_account_info(), - &ctx.accounts.rent.to_account_info(), - &ctx.accounts.rent_recipient.to_account_info(), - compression_config.compression_delay as u64, - compression_params.creator_lp_token_bump, - )?; - - // ZK Compression Step 5: We create the lp cMint and distribute the lp tokens - // to the lp_vault and user based on the regular LP math. - create_and_mint_lp( - ctx.accounts.creator.to_account_info(), - ctx.accounts.authority.to_account_info(), - &ctx.accounts.lp_mint.key(), - ctx.accounts.lp_vault.to_account_info(), - ctx.accounts.creator_lp_token.to_account_info(), - ctx.accounts.lp_mint_signer.to_account_info(), - &pool_state_key, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), - ctx.accounts.compressed_token_program.to_account_info(), - ctx.bumps.lp_mint_signer, - &compression_params, - &cpi_accounts, - user_lp_amount, - vault_lp_amount, - pool_auth_bump, - )?; - // ZK Compression Step 6: Clean up compressed onchain PDAs. Always do this - // at the end of your instruction. Only PoolState and ObservationState are - // being compressed right away. All other accounts only initialized as - // compressible - for async compression once they're inactive. PoolState and - // ObservationState are compressed atomically for demo purposes. You can - // choose whether to compress_at_init or only after they've become inactive. - // If you compress_at_init, you pay 0 upfront rent, but the first - // transaction to use the account must include a - // decompress_accounts_idempotent instruction in their transaction which - // fronts then rent. Only the first touch will actually decompress the - // account; swap n+1 will still succeed. - pool_state.close(rent_recipient.clone())?; - observation_state.close(rent_recipient.clone())?; + // Create creator LP token ATA + CreateTokenAtaCpi { + payer: ctx.accounts.creator.to_account_info(), + owner: ctx.accounts.creator.to_account_info(), + mint: ctx.accounts.lp_mint.to_account_info(), + ata: ctx.accounts.creator_lp_token.to_account_info(), + bump: params.creator_lp_token_bump, + } + .idempotent() + .rent_free( + ctx.accounts.light_token_compressible_config.to_account_info(), + ctx.accounts.light_token_rent_sponsor.to_account_info(), + ctx.accounts.system_program.to_account_info(), + ) + .invoke()?; + + // Mint LP tokens to creator + MintToCpi { + mint: ctx.accounts.lp_mint.to_account_info(), + destination: ctx.accounts.creator_lp_token.to_account_info(), + amount: user_lp_amount, + authority: ctx.accounts.authority.to_account_info(), + system_program: ctx.accounts.system_program.to_account_info(), + max_top_up: None, + } + .invoke_signed(&[&[crate::AUTH_SEED.as_bytes(), &[ctx.bumps.authority]]])?; Ok(()) } - -#[derive(AnchorSerialize, AnchorDeserialize, Debug)] -pub struct InitializeCompressionParams { - // pool state - pub pool_address_tree_info: PackedAddressTreeInfo, - // observation state - pub observation_address_tree_info: PackedAddressTreeInfo, - // lp mint - pub lp_mint_address_tree_info: PackedAddressTreeInfo, - pub lp_mint_bump: u8, - pub creator_lp_token_bump: u8, - // shared - pub proof: ValidityProof, - pub output_state_tree_index: u8, -} diff --git a/programs/cp-swap/src/instructions/swap_base_input.rs b/programs/cp-swap/src/instructions/swap_base_input.rs index 359b361..bdcfbb3 100644 --- a/programs/cp-swap/src/instructions/swap_base_input.rs +++ b/programs/cp-swap/src/instructions/swap_base_input.rs @@ -2,12 +2,10 @@ use crate::curve::calculator::CurveCalculator; use crate::curve::TradeDirection; use crate::error::ErrorCode; use crate::states::*; -use crate::utils::ctoken::get_bumps; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_lang::solana_program; use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; -use light_sdk::compressible::HasCompressionInfo; #[derive(Accounts)] pub struct Swap<'info> { @@ -74,19 +72,13 @@ pub struct Swap<'info> { #[account(mut, address = pool_state.observation_key)] pub observation_state: Account<'info, ObservationState>, - /// CHECK: checked by protocol. - pub compressed_token_program_cpi_authority: AccountInfo<'info>, - /// CHECK: checked by protocol. - pub compressed_token_program: AccountInfo<'info>, - /// CHECK: checked by protocol. - /// - /// Every mint must be registered in the compression protocol via a - /// compression_token_pool_pda. - #[account(mut)] - pub compressed_token_0_pool_pda: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_1_pool_pda: AccountInfo<'info>, + /// Light Token program for CPI + pub light_token_program: Interface<'info, TokenInterface>, + + pub system_program: Program<'info, System>, + + /// CHECK: light_token CPI authority. + pub light_token_cpi_authority: AccountInfo<'info>, } pub fn swap_base_input(ctx: Context, amount_in: u64, minimum_amount_out: u64) -> Result<()> { @@ -241,39 +233,29 @@ pub fn swap_base_input(ctx: Context, amount_in: u64, minimum_amount_out: u }); require_gte!(constant_after, constant_before); - let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( - ctx.accounts.input_token_mint.key(), - ctx.accounts.output_token_mint.key(), - ctx.accounts.compressed_token_program.key(), - ); transfer_from_user_to_pool_vault( ctx.accounts.payer.to_account_info(), ctx.accounts.input_token_account.to_account_info(), ctx.accounts.input_vault.to_account_info(), ctx.accounts.input_token_mint.to_account_info(), ctx.accounts.input_token_program.to_account_info(), - ctx.accounts.compressed_token_0_pool_pda.to_account_info(), - compressed_token_0_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), input_transfer_amount, + ctx.accounts.payer.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; transfer_from_pool_vault_to_user( - ctx.accounts.payer.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.output_vault.to_account_info(), ctx.accounts.output_token_account.to_account_info(), ctx.accounts.output_token_mint.to_account_info(), ctx.accounts.output_token_program.to_account_info(), - ctx.accounts.compressed_token_1_pool_pda.to_account_info(), - compressed_token_1_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), output_transfer_amount, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], + ctx.accounts.payer.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; // update the previous price to the observation @@ -284,8 +266,5 @@ pub fn swap_base_input(ctx: Context, amount_in: u64, minimum_amount_out: u ); pool_state.recent_epoch = Clock::get()?.epoch; - // The account was written to, so we must update CompressionInfo. - pool_state.compression_info_mut().bump_last_written_slot()?; - Ok(()) } diff --git a/programs/cp-swap/src/instructions/swap_base_output.rs b/programs/cp-swap/src/instructions/swap_base_output.rs index 97fdbfe..853e460 100644 --- a/programs/cp-swap/src/instructions/swap_base_output.rs +++ b/programs/cp-swap/src/instructions/swap_base_output.rs @@ -2,11 +2,9 @@ use super::swap_base_input::Swap; use crate::curve::{calculator::CurveCalculator, TradeDirection}; use crate::error::ErrorCode; use crate::states::*; -use crate::utils::ctoken::get_bumps; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_lang::solana_program; -use light_sdk::compressible::HasCompressionInfo; pub fn swap_base_output( ctx: Context, @@ -167,40 +165,29 @@ pub fn swap_base_output( }); require_gte!(constant_after, constant_before); - let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( - ctx.accounts.input_token_mint.key(), - ctx.accounts.output_token_mint.key(), - ctx.accounts.compressed_token_program.key(), - ); - transfer_from_user_to_pool_vault( ctx.accounts.payer.to_account_info(), ctx.accounts.input_token_account.to_account_info(), ctx.accounts.input_vault.to_account_info(), ctx.accounts.input_token_mint.to_account_info(), ctx.accounts.input_token_program.to_account_info(), - ctx.accounts.compressed_token_0_pool_pda.to_account_info(), - compressed_token_0_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), input_transfer_amount, + ctx.accounts.payer.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; transfer_from_pool_vault_to_user( - ctx.accounts.payer.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.output_vault.to_account_info(), ctx.accounts.output_token_account.to_account_info(), ctx.accounts.output_token_mint.to_account_info(), ctx.accounts.output_token_program.to_account_info(), - ctx.accounts.compressed_token_1_pool_pda.to_account_info(), - compressed_token_1_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), output_transfer_amount, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], + ctx.accounts.payer.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; // update the previous price to the observation @@ -211,8 +198,5 @@ pub fn swap_base_output( ); pool_state.recent_epoch = Clock::get()?.epoch; - // The account was written to, so we must update CompressionInfo. - pool_state.compression_info_mut().bump_last_written_slot()?; - Ok(()) } diff --git a/programs/cp-swap/src/instructions/withdraw.rs b/programs/cp-swap/src/instructions/withdraw.rs index 28c77bb..e7a7be1 100644 --- a/programs/cp-swap/src/instructions/withdraw.rs +++ b/programs/cp-swap/src/instructions/withdraw.rs @@ -1,17 +1,15 @@ use crate::curve::CurveCalculator; use crate::curve::RoundDirection; use crate::error::ErrorCode; -use crate::utils::ctoken::get_bumps; use crate::states::*; use crate::utils::token::*; -use crate::utils::transfer_ctoken_from_user_to_pool_vault; use anchor_lang::prelude::*; use anchor_spl::{ memo::spl_memo, token::Token, - token_interface::{Mint, Token2022, TokenAccount}, + token_interface::{Mint, Token2022, TokenAccount, TokenInterface}, }; -use light_sdk::compressible::HasCompressionInfo; +use light_token_sdk::token::BurnCpi; #[derive(Accounts)] pub struct Withdraw<'info> { @@ -32,7 +30,7 @@ pub struct Withdraw<'info> { pub pool_state: Box>, #[account( - mut, + mut, token::authority = owner )] pub owner_lp_token: Box>, @@ -83,32 +81,12 @@ pub struct Withdraw<'info> { )] pub vault_1_mint: Box>, - /// Program lp token vault + /// Lp mint #[account( mut, - seeds = [ - POOL_VAULT_SEED.as_bytes(), - pool_state.lp_mint.as_ref() - ], - bump, - token::mint = lp_vault.mint, - token::authority = authority + address = pool_state.lp_mint @ ErrorCode::IncorrectLpMint )] - pub lp_vault: InterfaceAccount<'info, TokenAccount>, - - /// CHECK: checked by protocol. - pub compressed_token_program_cpi_authority: AccountInfo<'info>, - /// CHECK: checked by protocol. - pub compressed_token_program: AccountInfo<'info>, - /// CHECK: checked by protocol. - /// - /// Every mint must be registered in the compression protocol via a - /// compression_token_pool_pda. - #[account(mut)] - pub compressed_token_0_pool_pda: AccountInfo<'info>, - /// CHECK: checked by protocol. - #[account(mut)] - pub compressed_token_1_pool_pda: AccountInfo<'info>, + pub lp_mint: Box>, /// memo program /// CHECK: @@ -116,6 +94,14 @@ pub struct Withdraw<'info> { address = spl_memo::id() )] pub memo_program: UncheckedAccount<'info>, + + pub system_program: Program<'info, System>, + + /// CHECK: light-token CPI authority. + pub light_token_cpi_authority: AccountInfo<'info>, + + /// Light Token program for CPI + pub light_token_program: Interface<'info, TokenInterface>, } pub fn withdraw( @@ -125,7 +111,6 @@ pub fn withdraw( minimum_token_1_amount: u64, ) -> Result<()> { require_gt!(lp_token_amount, 0); - require_gt!(ctx.accounts.lp_vault.amount, 0); let pool_id = ctx.accounts.pool_state.key(); let pool_state = &mut ctx.accounts.pool_state; if !pool_state.get_status_by_bit(PoolStatusBitIndex::Withdraw) { @@ -197,23 +182,18 @@ pub fn withdraw( return Err(ErrorCode::ExceededSlippage.into()); } - transfer_ctoken_from_user_to_pool_vault( - ctx.accounts.owner.to_account_info(), - ctx.accounts.owner_lp_token.to_account_info(), - ctx.accounts.lp_vault.to_account_info(), - lp_token_amount, - )?; + BurnCpi { + source: ctx.accounts.owner_lp_token.to_account_info(), + mint: ctx.accounts.lp_mint.to_account_info(), + amount: lp_token_amount, + authority: ctx.accounts.owner.to_account_info(), + max_top_up: None, + } + .invoke()?; pool_state.lp_supply = pool_state.lp_supply.checked_sub(lp_token_amount).unwrap(); - let (compressed_token_0_pool_bump, compressed_token_1_pool_bump) = get_bumps( - ctx.accounts.vault_0_mint.key(), - ctx.accounts.vault_1_mint.key(), - ctx.accounts.compressed_token_program.key(), - ); - transfer_from_pool_vault_to_user( - ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_0_vault.to_account_info(), ctx.accounts.token_0_account.to_account_info(), @@ -223,17 +203,14 @@ pub fn withdraw( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_0_pool_pda.to_account_info(), - compressed_token_0_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), token_0_amount, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; transfer_from_pool_vault_to_user( - ctx.accounts.owner.to_account_info(), ctx.accounts.authority.to_account_info(), ctx.accounts.token_1_vault.to_account_info(), ctx.accounts.token_1_account.to_account_info(), @@ -243,18 +220,13 @@ pub fn withdraw( } else { ctx.accounts.token_program_2022.to_account_info() }, - ctx.accounts.compressed_token_1_pool_pda.to_account_info(), - compressed_token_1_pool_bump, - ctx.accounts - .compressed_token_program_cpi_authority - .to_account_info(), token_1_amount, &[&[crate::AUTH_SEED.as_bytes(), &[pool_state.auth_bump]]], + ctx.accounts.owner.to_account_info(), + ctx.accounts.light_token_cpi_authority.to_account_info(), + ctx.accounts.system_program.to_account_info(), )?; pool_state.recent_epoch = Clock::get()?.epoch; - // The account was written to, so we must update CompressionInfo. - pool_state.compression_info_mut().bump_last_written_slot().unwrap(); - Ok(()) } diff --git a/programs/cp-swap/src/lib.rs b/programs/cp-swap/src/lib.rs index 37aaec6..3bebad2 100644 --- a/programs/cp-swap/src/lib.rs +++ b/programs/cp-swap/src/lib.rs @@ -1,3 +1,5 @@ +#![allow(deprecated)] + pub mod curve; pub mod error; pub mod instructions; @@ -5,12 +7,16 @@ pub mod states; pub mod utils; use crate::curve::fees::FEE_RATE_DENOMINATOR_VALUE; -pub use crate::instructions::initialize::Initialize; -pub use crate::states::{ObservationState, PoolState}; +pub use crate::instructions::initialize::{Initialize, InitializeParams}; +pub use crate::states::{ + ObservationState, PackedObservationState, PackedPoolState, PoolState, OBSERVATION_SEED, + POOL_SEED, POOL_VAULT_SEED, +}; use anchor_lang::prelude::*; use instructions::*; -use light_sdk::derive_light_cpi_signer; -use light_sdk_macros::add_compressible_instructions; +use light_sdk::{derive_light_cpi_signer, derive_light_rent_sponsor_pda}; +use light_sdk::light_hasher::*; +use light_sdk_macros::light_program; use light_sdk_types::CpiSigner; #[cfg(not(feature = "no-entrypoint"))] @@ -32,12 +38,23 @@ declare_id!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); pub const LIGHT_CPI_SIGNER: CpiSigner = derive_light_cpi_signer!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C"); +pub const PROGRAM_RENT_SPONSOR_DATA: ([u8; 32], u8) = + derive_light_rent_sponsor_pda!("CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C", 1); + +#[inline] +pub fn program_rent_sponsor() -> Pubkey { + Pubkey::from(PROGRAM_RENT_SPONSOR_DATA.0) +} + pub mod admin { use super::{pubkey, Pubkey}; #[cfg(feature = "devnet")] pub const ID: Pubkey = pubkey!("adMCyoCgfkg7bQiJ9aBJ59H3BXLY3r5LNLfPpQfMzBe"); - #[cfg(not(feature = "devnet"))] - pub const ID: Pubkey = pubkey!("GThUX1Atko4tqhN2NaiTazWSeFWMuiUvfFnyJyUghFMJ"); + #[cfg(all(not(feature = "devnet"), not(feature = "test-sbf")))] + pub const ID: Pubkey = pubkey!("AKnL4NNf3DGWZJS6cPknBuEGnVsV4A4m5tgebLHaRSZ9"); + // Test admin - pubkey derived from Keypair::from_seed(&[1u8; 32]) + #[cfg(feature = "test-sbf")] + pub const ID: Pubkey = pubkey!("AKnL4NNf3DGWZJS6cPknBuEGnVsV4A4m5tgebLHaRSZ9"); } pub mod create_pool_fee_receiver { @@ -50,18 +67,15 @@ pub mod create_pool_fee_receiver { pub const AUTH_SEED: &str = "vault_and_lp_mint_auth_seed"; -/// ZK Compression: Auto-generates compress/decompress instructions for the -/// specified accounts. Derives compress_pool_state, compress_observation_state, -/// decompress_accounts_idempotent, initialize_compression_config, and -/// update_compression_config, as well as all relevant structs. Everything is -/// auto-added to the program IDL for consumption by clients. -#[add_compressible_instructions(PoolState, ObservationState)] +#[light_program] #[program] pub mod raydium_cp_swap { + #![allow(clippy::too_many_arguments)] use super::*; - // The configuration of AMM protocol, include trade fee and protocol fee + /// The configuration of AMM protocol, include trade fee and protocol fee + /// /// # Arguments /// /// * `ctx`- The accounts needed by instruction. @@ -157,24 +171,13 @@ pub mod raydium_cp_swap { /// # Arguments /// /// * `ctx`- The context of accounts - /// * `init_amount_0` - the initial amount_0 to deposit - /// * `init_amount_1` - the initial amount_1 to deposit - /// * `open_time` - the timestamp allowed for swap + /// * `params` - Initialize parameters including init_amount_0, init_amount_1, open_time /// pub fn initialize<'info>( ctx: Context<'_, '_, '_, 'info, Initialize<'info>>, - init_amount_0: u64, - init_amount_1: u64, - open_time: u64, - compression_params: InitializeCompressionParams, + params: InitializeParams, ) -> Result<()> { - instructions::initialize( - ctx, - init_amount_0, - init_amount_1, - open_time, - compression_params, - ) + instructions::initialize(ctx, params) } /// Deposit lp token to the pool diff --git a/programs/cp-swap/src/states/oracle.rs b/programs/cp-swap/src/states/oracle.rs index b2754db..bef2f8c 100644 --- a/programs/cp-swap/src/states/oracle.rs +++ b/programs/cp-swap/src/states/oracle.rs @@ -1,87 +1,34 @@ -/// Oracle provides price data useful for a wide variety of system designs -/// use anchor_lang::prelude::*; - -use light_sdk::{ - compressible::{CompressionInfo, HasCompressionInfo}, - sha::LightHasher, - LightDiscriminator, -}; -use light_sdk_macros::Compressible; +use light_sdk::compressible::CompressionInfo; +use light_sdk::LightDiscriminator; +use light_sdk_macros::LightAccount; #[cfg(test)] use std::time::{SystemTime, UNIX_EPOCH}; -/// Seed to derive account address and signature + pub const OBSERVATION_SEED: &str = "observation"; -// Number of ObservationState element -pub const OBSERVATION_NUM: usize = 20; +pub const OBSERVATION_NUM: usize = 2; pub const OBSERVATION_UPDATE_DURATION_DEFAULT: u64 = 15; -/// The element of observations in ObservationState #[derive(Default, Clone, Copy, AnchorSerialize, AnchorDeserialize, InitSpace, Debug)] pub struct Observation { - /// The block timestamp of the observation pub block_timestamp: u64, - /// the cumulative of token0 price during the duration time, Q32.32, the remaining 64 bit for overflow pub cumulative_token_0_price_x32: u128, - /// the cumulative of token1 price during the duration time, Q32.32, the remaining 64 bit for overflow pub cumulative_token_1_price_x32: u128, } -/// Tip: The 'Compressible' macro derives compress/decompress methods for the -/// account. CompressionInfo tracks the last_written_slot. Whenever a -/// compressible account is written to, last_written_slot must be updated. If -/// last_written_slot >= threshold (compression_delay), the account becomes -/// eligible for compression. Eligible accounts can be compressed -/// asynchronously. + +#[derive(Default, Debug, InitSpace, LightAccount)] #[account] -#[derive(LightHasher, LightDiscriminator, Compressible, InitSpace, Debug)] -#[compress_as(observations = None)] pub struct ObservationState { - /// Whether the ObservationState is initialized + pub compression_info: Option, pub initialized: bool, - /// the most-recently updated index of the observations array pub observation_index: u16, pub pool_id: Pubkey, - /// observation array - pub observations: Option<[Observation; OBSERVATION_NUM]>, - /// #[skip] is required. Is Some when the account is decompressed and None - /// when compressed. - #[skip] - pub compression_info: Option, - /// padding for feature update + pub observations: [Observation; OBSERVATION_NUM], pub padding: [u64; 4], } -impl Default for ObservationState { - #[inline] - fn default() -> ObservationState { - ObservationState { - initialized: false, - observation_index: 0, - pool_id: Pubkey::default(), - observations: None, - compression_info: None, - padding: [0u64; 4], - } - } -} - impl ObservationState { - // Writes an oracle observation to the account, returning the next observation_index. - /// Writable at most once per second. Index represents the most recently written element. - /// If the index is at the end of the allowable array length (100 - 1), the next index will turn to 0. - /// - /// # Arguments - /// - /// * `self` - The ObservationState account to write in - /// * `block_timestamp` - The current timestamp of to update - /// * `token_0_price_x32` - The token_0_price_x32 at the time of the new observation - /// * `token_1_price_x32` - The token_1_price_x32 at the time of the new observation - /// * `observation_index` - The last update index of element in the oracle array - /// - /// # Return - /// * `next_observation_index` - The new index of element to update in the oracle array - /// pub fn update( &mut self, block_timestamp: u64, @@ -91,21 +38,12 @@ impl ObservationState { let observation_index = self.observation_index; if !self.initialized { - let observations = self - .observations - .get_or_insert_with(|| [Observation::default(); OBSERVATION_NUM]); - // skip the pool init price self.initialized = true; - observations[observation_index as usize].block_timestamp = block_timestamp; - observations[observation_index as usize].cumulative_token_0_price_x32 = 0; - observations[observation_index as usize].cumulative_token_1_price_x32 = 0; - - // The account is being initialized, so we must set compression_info. - self.compression_info = Some(CompressionInfo::new_decompressed().unwrap()); + self.observations[observation_index as usize].block_timestamp = block_timestamp; + self.observations[observation_index as usize].cumulative_token_0_price_x32 = 0; + self.observations[observation_index as usize].cumulative_token_1_price_x32 = 0; } else { - let observations = &mut self.observations.as_mut().unwrap(); - - let last_observation = observations[observation_index as usize]; + let last_observation = self.observations[observation_index as usize]; let delta_time = block_timestamp.saturating_sub(last_observation.block_timestamp); if delta_time < OBSERVATION_UPDATE_DURATION_DEFAULT { return; @@ -117,30 +55,22 @@ impl ObservationState { } else { observation_index + 1 }; - observations[next_observation_index as usize].block_timestamp = block_timestamp; - // cumulative_token_price_x32 only occupies the first 64 bits, and the remaining 64 bits are used to store overflow data - observations[next_observation_index as usize].cumulative_token_0_price_x32 = + self.observations[next_observation_index as usize].block_timestamp = block_timestamp; + self.observations[next_observation_index as usize].cumulative_token_0_price_x32 = last_observation .cumulative_token_0_price_x32 .wrapping_add(delta_token_0_price_x32); - observations[next_observation_index as usize].cumulative_token_1_price_x32 = + self.observations[next_observation_index as usize].cumulative_token_1_price_x32 = last_observation .cumulative_token_1_price_x32 .wrapping_add(delta_token_1_price_x32); self.observation_index = next_observation_index; - - // The account was written to, so we must update CompressionInfo. - self.compression_info_mut() - .bump_last_written_slot() - .unwrap(); } } } -/// Returns the block timestamp truncated to 32 bits, i.e. mod 2**32 -/// pub fn block_timestamp() -> u64 { - Clock::get().unwrap().unix_timestamp as u64 // truncation is desired + Clock::get().unwrap().unix_timestamp as u64 } #[cfg(test)] diff --git a/programs/cp-swap/src/states/pool.rs b/programs/cp-swap/src/states/pool.rs index 52909e2..dce62ae 100644 --- a/programs/cp-swap/src/states/pool.rs +++ b/programs/cp-swap/src/states/pool.rs @@ -1,15 +1,15 @@ use anchor_lang::prelude::*; use anchor_spl::token_interface::Mint; -use light_sdk::{compressible::CompressionInfo, sha::LightHasher, LightDiscriminator}; - -use light_sdk_macros::Compressible; +use light_sdk::compressible::CompressionInfo; +use light_sdk::LightDiscriminator; +use light_sdk_macros::LightAccount; use std::ops::{BitAnd, BitOr, BitXor}; -/// Seed to derive account address and signature + pub const POOL_SEED: &str = "pool"; pub const POOL_LP_MINT_SEED: &str = "pool_lp_mint"; pub const POOL_VAULT_SEED: &str = "pool_vault"; -pub const Q32: u128 = (u32::MAX as u128) + 1; // 2^32 +pub const Q32: u128 = (u32::MAX as u128) + 1; pub enum PoolStatusBitIndex { Deposit, @@ -23,73 +23,33 @@ pub enum PoolStatusBitFlag { Disable, } -/// Tip: The 'Compressible' macro derives compress/decompress methods for the -/// account. CompressionInfo tracks the last_written_slot. Whenever a -/// compressible account is written to, last_written_slot must be updated. If -/// last_written_slot >= threshold (compression_delay), the account becomes -/// eligible for compression. Eligible accounts can be compressed -/// asynchronously. +#[derive(Default, Debug, InitSpace, LightAccount)] #[account] #[repr(C)] -#[derive(Default, Debug, LightHasher, LightDiscriminator, Compressible, InitSpace)] pub struct PoolState { - /// Which config the pool belongs + pub compression_info: Option, pub amm_config: Pubkey, - /// pool creator pub pool_creator: Pubkey, - /// Token A pub token_0_vault: Pubkey, - /// Token B pub token_1_vault: Pubkey, - - /// Pool tokens are issued when A or B tokens are deposited. - /// Pool tokens can be withdrawn back to the original A or B token. pub lp_mint: Pubkey, - /// Holds all LP tokens. Compressible. - pub lp_vault: Pubkey, - /// Mint information for token A pub token_0_mint: Pubkey, - /// Mint information for token B pub token_1_mint: Pubkey, - - /// token_0 program pub token_0_program: Pubkey, - /// token_1 program pub token_1_program: Pubkey, - - /// observation account to store oracle data pub observation_key: Pubkey, - pub auth_bump: u8, - /// Bitwise representation of the state of the pool - /// bit0, 1: disable deposit(value is 1), 0: normal - /// bit1, 1: disable withdraw(value is 2), 0: normal - /// bit2, 1: disable swap(value is 4), 0: normal pub status: u8, - pub lp_mint_decimals: u8, - /// mint0 and mint1 decimals pub mint_0_decimals: u8, pub mint_1_decimals: u8, - - /// True circulating supply without burns and lock ups pub lp_supply: u64, - /// The amounts of token_0 and token_1 that are owed to the liquidity provider. pub protocol_fees_token_0: u64, pub protocol_fees_token_1: u64, - pub fund_fees_token_0: u64, pub fund_fees_token_1: u64, - - /// The timestamp allowed for swap in the pool. pub open_time: u64, - /// recent epoch pub recent_epoch: u64, - /// #[skip] is required. Is Some when the account is decompressed and None - /// when compressed. - #[skip] - pub compression_info: Option, - /// padding for future updates pub padding: [u64; 1], } @@ -105,7 +65,6 @@ impl PoolState { token_1_vault: Pubkey, token_0_mint: &InterfaceAccount, token_1_mint: &InterfaceAccount, - lp_vault: &AccountInfo, lp_mint: &AccountInfo, observation_key: Pubkey, ) { @@ -114,14 +73,13 @@ impl PoolState { self.token_0_vault = token_0_vault; self.token_1_vault = token_1_vault; self.lp_mint = lp_mint.key(); - self.lp_vault = lp_vault.key(); self.token_0_mint = token_0_mint.key(); self.token_1_mint = token_1_mint.key(); self.token_0_program = *token_0_mint.to_account_info().owner; self.token_1_program = *token_1_mint.to_account_info().owner; self.observation_key = observation_key; self.auth_bump = auth_bump; - self.lp_mint_decimals = 9; // LP mint decimals are fixed at 9 + self.lp_mint_decimals = 9; self.mint_0_decimals = token_0_mint.decimals; self.mint_1_decimals = token_1_mint.decimals; self.lp_supply = lp_supply; @@ -148,7 +106,6 @@ impl PoolState { } } - /// Get status by bit, if it is `noraml` status, return true pub fn get_status_by_bit(&self, bit: PoolStatusBitIndex) -> bool { let status = u8::from(1) << (bit as u8); self.status.bitand(status) == 0 @@ -184,7 +141,7 @@ pub mod pool_test { #[test] fn get_set_status_by_bit() { let mut pool_state = PoolState::default(); - pool_state.set_status(4); // 0000100 + pool_state.set_status(4); assert_eq!( pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), false @@ -198,28 +155,24 @@ pub mod pool_test { true ); - // disable -> disable, nothing to change pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Disable); assert_eq!( pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), false ); - // disable -> enable pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Enable); assert_eq!(pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), true); - // enable -> enable, nothing to change pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Enable); assert_eq!(pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), true); - // enable -> disable pool_state.set_status_by_bit(PoolStatusBitIndex::Swap, PoolStatusBitFlag::Disable); assert_eq!( pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), false ); - pool_state.set_status(5); // 0000101 + pool_state.set_status(5); assert_eq!( pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), false @@ -233,7 +186,7 @@ pub mod pool_test { true ); - pool_state.set_status(7); // 0000111 + pool_state.set_status(7); assert_eq!( pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), false @@ -247,7 +200,7 @@ pub mod pool_test { false ); - pool_state.set_status(3); // 0000011 + pool_state.set_status(3); assert_eq!(pool_state.get_status_by_bit(PoolStatusBitIndex::Swap), true); assert_eq!( pool_state.get_status_by_bit(PoolStatusBitIndex::Deposit), diff --git a/programs/cp-swap/src/utils/compression.rs b/programs/cp-swap/src/utils/compression.rs deleted file mode 100644 index fe15078..0000000 --- a/programs/cp-swap/src/utils/compression.rs +++ /dev/null @@ -1,103 +0,0 @@ -use crate::instructions::InitializeCompressionParams; -use crate::states::*; -use anchor_lang::prelude::*; -use light_compressed_account::address::derive_address; -use light_sdk::compressible::prepare_accounts_for_compression_on_init; -use light_sdk::cpi::CpiAccountsSmall; -use light_sdk::cpi::CpiInputs; -use light_sdk_types::cpi_context_write::CpiContextWriteAccounts; - -use crate::LIGHT_CPI_SIGNER; - -// The order in which new compressed accounts are passed to the CPI. -pub const POOL_STATE_CREATION_INDEX: u8 = 0; -pub const OBSERVATION_STATE_CREATION_INDEX: u8 = 1; -pub const LP_MINT_CREATION_INDEX: u8 = 2; - -pub fn compress_pool_and_observation_pdas<'a, 'b, 'info>( - cpi_accounts: &CpiAccountsSmall<'b, 'info>, - pool_state: &Account<'info, PoolState>, - observation_state: &Account<'info, ObservationState>, - compression_params: &InitializeCompressionParams, - rent_recipient: &AccountInfo<'info>, - address_space: &[Pubkey], -) -> Result<()> { - // 1. Prepare new address params - let pool_new_address_params = compression_params - .pool_address_tree_info - .into_new_address_params_assigned_packed( - pool_state.key().to_bytes(), - true, - Some(POOL_STATE_CREATION_INDEX), - ); - let observation_new_address_params = compression_params - .observation_address_tree_info - .into_new_address_params_assigned_packed( - observation_state.key().to_bytes(), - true, - Some(OBSERVATION_STATE_CREATION_INDEX), - ); - // To save CU in exchange for ix data, you can also pass the addresses via client. - let pool_compressed_address = derive_address( - &pool_state.key().to_bytes(), - &cpi_accounts - .get_tree_address(pool_new_address_params.address_merkle_tree_account_index) - .unwrap() - .key - .to_bytes(), - &crate::ID.to_bytes(), - ); - let observation_compressed_address = derive_address( - &observation_state.key().to_bytes(), - &cpi_accounts - .get_tree_address(observation_new_address_params.address_merkle_tree_account_index) - .unwrap() - .key - .to_bytes(), - &crate::ID.to_bytes(), - ); - - // 2. Prepare the PDA accounts for direct compression_on_init. - let mut all_compressed_infos = Vec::with_capacity(2); - - let pool_state_compressed_info = prepare_accounts_for_compression_on_init::( - &[pool_state], - &[pool_compressed_address], - &[pool_new_address_params], - &[compression_params.output_state_tree_index], - &cpi_accounts, - &address_space, - rent_recipient, - )?; - all_compressed_infos.extend(pool_state_compressed_info); - - let observation_compressed_infos = prepare_accounts_for_compression_on_init::( - &[observation_state], - &[observation_compressed_address], - &[observation_new_address_params], - &[compression_params.output_state_tree_index], - &cpi_accounts, - &address_space, - rent_recipient, - )?; - all_compressed_infos.extend(observation_compressed_infos); - - // 3. Compress. We invoke the cpi_context here to save CU, because we still - // create a cMint later in the instruction. Only then will the state - // transition be fully settled. Notice we're using 'new_first_cpi' here - // instead of 'CompressedCpiContext::last_cpi_create_mint'. - let cpi_inputs = CpiInputs::new_first_cpi( - all_compressed_infos, - vec![pool_new_address_params, observation_new_address_params], - ); - let cpi_context = cpi_accounts.cpi_context().unwrap(); - let cpi_context_accounts = CpiContextWriteAccounts { - fee_payer: cpi_accounts.fee_payer(), - authority: cpi_accounts.authority().unwrap(), - cpi_context, - cpi_signer: LIGHT_CPI_SIGNER, - }; - cpi_inputs.invoke_light_system_program_cpi_context(cpi_context_accounts)?; - - Ok(()) -} diff --git a/programs/cp-swap/src/utils/ctoken.rs b/programs/cp-swap/src/utils/ctoken.rs deleted file mode 100644 index 281b9e3..0000000 --- a/programs/cp-swap/src/utils/ctoken.rs +++ /dev/null @@ -1,264 +0,0 @@ -use crate::{ - instructions::InitializeCompressionParams, - states::POOL_LP_MINT_SEED, - utils::{create_or_allocate_account, LP_MINT_CREATION_INDEX}, -}; -use anchor_lang::{ - prelude::*, - solana_program::program::{invoke, invoke_signed}, -}; -use light_compressed_token_sdk::{ - instructions::{ - create_compressible_associated_token_account_with_bump as initialize_compressible_associated_token_account_with_bump, - create_compressible_token_account as initialize_compressible_token_account, - create_mint_action_cpi, derive_compressed_mint_from_spl_mint, transfer, transfer_signed, - CreateCompressibleAssociatedTokenAccountInputs, CreateCompressibleTokenAccount, - MintActionInputs, MintActionType, - }, - CompressedProof, -}; -use light_ctoken_types::{ - instructions::mint_action::CompressedMintWithContext, - instructions::mint_action::CpiContext as CompressedCpiContext, COMPRESSIBLE_TOKEN_ACCOUNT_SIZE, -}; -use light_sdk::cpi::CpiAccountsSmall; - -pub fn transfer_ctoken_from_user_to_pool_vault<'a>( - authority: AccountInfo<'a>, - from: AccountInfo<'a>, - to_vault: AccountInfo<'a>, - amount: u64, -) -> Result<()> { - if amount == 0 { - return Ok(()); - } - - transfer(&from, &to_vault, &authority, amount)?; - Ok(()) -} - -pub fn transfer_ctoken_from_pool_vault_to_user<'a>( - authority: AccountInfo<'a>, - from_vault: AccountInfo<'a>, - to: AccountInfo<'a>, - amount: u64, - signer_seeds: &[&[&[u8]]], -) -> Result<()> { - if amount == 0 { - return Ok(()); - } - transfer_signed(&from_vault, &to, &authority, amount, signer_seeds)?; - Ok(()) -} - -pub fn create_compressible_token_account<'a>( - authority: &AccountInfo<'a>, - payer: &AccountInfo<'a>, - token_account: &AccountInfo<'a>, - mint_account: &AccountInfo<'a>, - system_program: &AccountInfo<'a>, - token_program: &AccountInfo<'a>, - signer_seeds: &[&[u8]], - rent_authority: &AccountInfo<'a>, - rent_recipient: &AccountInfo<'a>, - slots_until_compression: u64, -) -> Result<()> { - let space = COMPRESSIBLE_TOKEN_ACCOUNT_SIZE as usize; - - create_or_allocate_account( - token_program.key, - payer.to_account_info(), - system_program.to_account_info(), - token_account.to_account_info(), - signer_seeds, - space, - )?; - - let init_ix = initialize_compressible_token_account(CreateCompressibleTokenAccount { - account_pubkey: *token_account.key, - mint_pubkey: *mint_account.key, - owner_pubkey: *authority.key, - rent_authority: *rent_authority.key, - rent_recipient: *rent_recipient.key, - slots_until_compression, - }) - .map_err(|e| ProgramError::from(e))?; - - invoke( - &init_ix, - &[ - token_account.to_account_info(), - mint_account.to_account_info(), - authority.to_account_info(), - rent_authority.to_account_info(), - rent_recipient.to_account_info(), - ], - )?; - - Ok(()) -} - -pub fn create_compressible_associated_token_account<'a>( - owner: &AccountInfo<'a>, - payer: &AccountInfo<'a>, - associated_token_account: &AccountInfo<'a>, - mint_account: &AccountInfo<'a>, - system_program: &AccountInfo<'a>, - rent_authority: &AccountInfo<'a>, - rent_recipient: &AccountInfo<'a>, - slots_until_compression: u64, - bump: u8, -) -> Result<()> { - let init_ix = initialize_compressible_associated_token_account_with_bump( - CreateCompressibleAssociatedTokenAccountInputs { - payer: *payer.key, - mint: *mint_account.key, - owner: *owner.key, - rent_authority: *rent_authority.key, - rent_recipient: *rent_recipient.key, - slots_until_compression, - }, - *associated_token_account.key, - bump, - ) - .map_err(|e| ProgramError::from(e))?; - - invoke( - &init_ix, - &[ - payer.to_account_info(), - associated_token_account.to_account_info(), - mint_account.to_account_info(), - owner.to_account_info(), - system_program.to_account_info(), - ], - )?; - - Ok(()) -} - -// To reduce CU usage, you can instead also pass the bumps as instruction data. -pub fn get_bumps( - token_0_mint: Pubkey, - token_1_mint: Pubkey, - compressed_token_program: Pubkey, -) -> (u8, u8) { - let compressed_token_0_pool_bump = Pubkey::find_program_address( - &[b"pool".as_ref(), token_0_mint.as_ref()], - &compressed_token_program, - ) - .1; - let compressed_token_1_pool_bump = Pubkey::find_program_address( - &[b"pool".as_ref(), token_1_mint.as_ref()], - &compressed_token_program, - ) - .1; - (compressed_token_0_pool_bump, compressed_token_1_pool_bump) -} - -pub fn create_and_mint_lp<'a, 'b, 'info>( - creator: AccountInfo<'info>, - authority: AccountInfo<'info>, - lp_mint_key: &Pubkey, - lp_vault: AccountInfo<'info>, - creator_lp_token: AccountInfo<'info>, - lp_mint_signer: AccountInfo<'info>, - pool_state_key: &Pubkey, - compressed_token_program_cpi_authority: AccountInfo<'info>, - compressed_token_program: AccountInfo<'info>, - lp_mint_signer_bump: u8, - compression_params: &InitializeCompressionParams, - cpi_accounts: &CpiAccountsSmall<'b, 'info>, - user_lp_amount: u64, - vault_lp_amount: u64, - pool_auth_bump: u8, -) -> Result<()> { - // Get tree accounts - let output_state_queue_idx: u8 = 0; - let address_tree_idx: u8 = 1; - let output_state_queue = - *cpi_accounts.tree_accounts().unwrap()[output_state_queue_idx as usize].key; - let address_tree_pubkey = *cpi_accounts.tree_accounts().unwrap()[address_tree_idx as usize].key; - - let mint_compressed_address = - derive_compressed_mint_from_spl_mint(lp_mint_key, &address_tree_pubkey); - - let compressed_mint_with_context = CompressedMintWithContext::new( - mint_compressed_address, - compression_params.lp_mint_address_tree_info.root_index, - 9, // Our Lp mints always have 9 decimals. - Some(authority.key().into()), - Some(authority.key().into()), - lp_mint_key.into(), - ); - - // The cmint creation is implicit. Here we additionally - // mint to the creator and the pool vault. - let actions = vec![ - MintActionType::MintToDecompressed { - account: creator_lp_token.key(), - amount: user_lp_amount, - }, - MintActionType::MintToDecompressed { - account: lp_vault.key(), - amount: vault_lp_amount, - }, - ]; - - let mint_action_instruction: anchor_lang::solana_program::instruction::Instruction = - create_mint_action_cpi( - MintActionInputs::new_for_create_mint( - compressed_mint_with_context, - actions, - output_state_queue, - address_tree_pubkey, - lp_mint_signer.key(), - Some(compression_params.lp_mint_bump), - authority.key().into(), - creator.key(), - compression_params.proof.0.map(|p| CompressedProof::from(p)), - ), - Some(CompressedCpiContext::last_cpi_create_mint( - address_tree_idx, - output_state_queue_idx, - LP_MINT_CREATION_INDEX, - )), - Some(cpi_accounts.cpi_context().unwrap().key()), - ) - .map_err(|e| ProgramError::from(e))?; - - // Extend the account infos with the accounts needed for the cmint creation. - let mut account_infos = cpi_accounts.to_account_infos(); - account_infos.extend([ - compressed_token_program_cpi_authority, - compressed_token_program, - authority, - lp_mint_signer, - creator, - // accounts used by the additional mint actions: - lp_vault, - creator_lp_token, - ]); - - // Invoke. We batch settle all compression related CPIs here, hence the - // signer_seeds for the PDAs. - invoke_signed( - &mint_action_instruction, - &account_infos, - &[ - // The mint creation is checked before the PDA actions, so its - // signer_seeds come first. - &[ - POOL_LP_MINT_SEED.as_bytes(), - pool_state_key.as_ref(), - &[lp_mint_signer_bump], - ], - // Since we also create 2 compressed PDAs in our instruction cia - // cpi_context, now we need to settle via the pda authority's - // signer_seeds. - &[crate::AUTH_SEED.as_bytes(), &[pool_auth_bump]], - ], - )?; - - Ok(()) -} diff --git a/programs/cp-swap/src/utils/mod.rs b/programs/cp-swap/src/utils/mod.rs index d7ca8de..6d161ff 100644 --- a/programs/cp-swap/src/utils/mod.rs +++ b/programs/cp-swap/src/utils/mod.rs @@ -1,9 +1,5 @@ -pub mod compression; -pub mod ctoken; pub mod math; pub mod token; -pub use compression::*; -pub use ctoken::*; pub use math::*; pub use token::*; diff --git a/programs/cp-swap/src/utils/token.rs b/programs/cp-swap/src/utils/token.rs index 8828369..2f9076b 100644 --- a/programs/cp-swap/src/utils/token.rs +++ b/programs/cp-swap/src/utils/token.rs @@ -5,9 +5,8 @@ use anchor_spl::{ token_2022, token_interface::{initialize_account3, InitializeAccount3, Mint}, }; -use light_compressed_token_sdk::instructions::transfer2::{ - transfer_ctoken_to_spl_signed, transfer_spl_to_ctoken, -}; +use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID; +use light_token_sdk::token::TransferInterfaceCpi; use spl_token_2022::{ self, extension::{ @@ -17,6 +16,33 @@ use spl_token_2022::{ }; use std::collections::HashSet; +/// SPL Token mint size (first 82 bytes are SPL-compatible for light tokens) +const SPL_MINT_SIZE: usize = 82; +/// Account type byte position (byte 165) +const ACCOUNT_TYPE_OFFSET: usize = 165; +/// Account type discriminator for Mint +const ACCOUNT_TYPE_MINT: u8 = 1; + +/// Extract decimals from mint data, supporting both SPL and Light token mints. +/// For extended mints (>82 bytes), validates byte 165 == 1 (Mint type). +fn get_mint_decimals(mint_data: &[u8]) -> Result { + // For extended mints, verify account type is Mint (byte 165 == 1) + if mint_data.len() > ACCOUNT_TYPE_OFFSET { + if mint_data[ACCOUNT_TYPE_OFFSET] != ACCOUNT_TYPE_MINT { + return err!(ErrorCode::InvalidAccountData); + } + } + + // Use first 82 bytes for SPL compatibility + let mint_slice = if mint_data.len() > SPL_MINT_SIZE { + &mint_data[..SPL_MINT_SIZE] + } else { + mint_data + }; + let mint_state = StateWithExtensions::::unpack(mint_slice)?; + Ok(mint_state.base.decimals) +} + const MINT_WHITELIST: [&'static str; 4] = [ "HVbpJAQGNpkgBaYBZQBR1t7yFdvaYVp2vCQQfKKEN4tM", "Crn4x1Y2HUKko7ox2EZMT6N2t2ZyH7eKtwkBGVnhEq1g", @@ -24,72 +50,85 @@ const MINT_WHITELIST: [&'static str; 4] = [ "2b1kV6DkPAnxd5ixfnxCpjxmKwqjjaYmCZfHsFu24GXo", ]; -pub fn transfer_from_user_to_pool_vault<'a, 'b>( +pub fn transfer_from_user_to_pool_vault<'a>( authority: AccountInfo<'a>, from: AccountInfo<'a>, to_vault: AccountInfo<'a>, mint: AccountInfo<'a>, - spl_token_program: AccountInfo<'a>, - compressed_token_pool_pda: AccountInfo<'a>, - compressed_token_pool_pda_bump: u8, - compressed_token_program_authority: AccountInfo<'a>, + _token_program: AccountInfo<'a>, amount: u64, + payer: AccountInfo<'a>, + light_token_cpi_authority: AccountInfo<'a>, + system_program: AccountInfo<'a>, ) -> Result<()> { if amount == 0 { return Ok(()); } - transfer_spl_to_ctoken( - authority.clone(), - authority, + + let mint_data = mint.try_borrow_data()?; + let decimals = get_mint_decimals(&mint_data)?; + drop(mint_data); + + TransferInterfaceCpi::new( + amount, + decimals, from, to_vault, - mint, - spl_token_program, - compressed_token_pool_pda, - compressed_token_pool_pda_bump, - compressed_token_program_authority, - amount, - )?; + authority, + payer, + light_token_cpi_authority, + system_program, + ) + .invoke() + .map_err(|e| anchor_lang::prelude::ProgramError::from(e))?; + Ok(()) } pub fn transfer_from_pool_vault_to_user<'a>( - payer: AccountInfo<'a>, authority: AccountInfo<'a>, from_vault: AccountInfo<'a>, to: AccountInfo<'a>, mint: AccountInfo<'a>, - spl_token_program: AccountInfo<'a>, - compressed_token_pool_pda: AccountInfo<'a>, - compressed_token_pool_pda_bump: u8, - compressed_token_program_authority: AccountInfo<'a>, + _token_program: AccountInfo<'a>, amount: u64, signer_seeds: &[&[&[u8]]], + payer: AccountInfo<'a>, + light_token_cpi_authority: AccountInfo<'a>, + system_program: AccountInfo<'a>, ) -> Result<()> { if amount == 0 { return Ok(()); } - transfer_ctoken_to_spl_signed( - payer, - authority, + + let mint_data = mint.try_borrow_data()?; + let decimals = get_mint_decimals(&mint_data)?; + drop(mint_data); + + TransferInterfaceCpi::new( + amount, + decimals, from_vault, to, - mint, - spl_token_program, - compressed_token_pool_pda, - compressed_token_pool_pda_bump, - compressed_token_program_authority, - amount, - signer_seeds, - )?; + authority, + payer, + light_token_cpi_authority, + system_program, + ) + .invoke_signed(signer_seeds) + .map_err(|e| anchor_lang::prelude::ProgramError::from(e))?; + Ok(()) } -/// Calculate the fee for output amount pub fn get_transfer_inverse_fee(mint_info: &AccountInfo, post_fee_amount: u64) -> Result { if *mint_info.owner == Token::id() { return Ok(0); } + // Light token mints don't have transfer fees + if *mint_info.owner == Pubkey::from(LIGHT_TOKEN_PROGRAM_ID) { + return Ok(0); + } if post_fee_amount == 0 { return err!(ErrorCode::InvalidInput); } @@ -120,11 +159,14 @@ pub fn get_transfer_inverse_fee(mint_info: &AccountInfo, post_fee_amount: u64) - Ok(fee) } -/// Calculate the fee for input amount pub fn get_transfer_fee(mint_info: &AccountInfo, pre_fee_amount: u64) -> Result { if *mint_info.owner == Token::id() { return Ok(0); } + // Light token mints don't have transfer fees + if *mint_info.owner == Pubkey::from(LIGHT_TOKEN_PROGRAM_ID) { + return Ok(0); + } let mint_data = mint_info.try_borrow_data()?; let mint = StateWithExtensions::::unpack(&mint_data)?; @@ -143,6 +185,10 @@ pub fn is_supported_mint(mint_account: &InterfaceAccount) -> Result if *mint_info.owner == Token::id() { return Ok(true); } + // Support light token mints + if *mint_info.owner == Pubkey::from(LIGHT_TOKEN_PROGRAM_ID) { + return Ok(true); + } let mint_whitelist: HashSet<&str> = MINT_WHITELIST.into_iter().collect(); if mint_whitelist.contains(mint_account.key().to_string().as_str()) { return Ok(true); diff --git a/programs/cp-swap/tests/functional_test.rs b/programs/cp-swap/tests/functional_test.rs new file mode 100644 index 0000000..150bffa --- /dev/null +++ b/programs/cp-swap/tests/functional_test.rs @@ -0,0 +1,217 @@ +/// Functional integration test for cp-swap program. +/// Tests pool initialization with light-program-test framework. + +use solana_keypair::Keypair; +use solana_signer::Signer; +use light_program_test::Rpc; +use light_program_test::program_test::TestRpc; + +mod helpers; +use helpers::*; + +#[tokio::test] +async fn test_full_lifecycle() { + let program_id = raydium_cp_swap::ID; + + // ======================================================================== + // Setup + // ======================================================================== + let mut env = setup_test_environment(program_id).await; + + // Create and fund creator with more lamports for multiple transactions + let creator = Keypair::new(); + env.rpc + .airdrop_lamports(&creator.pubkey(), 100_000_000_000) + .await + .unwrap(); + + // Get admin keypair and fund it + let admin = get_admin_keypair(); + env.rpc + .airdrop_lamports(&admin.pubkey(), 10_000_000_000) + .await + .unwrap(); + + // Setup token mints with larger initial balance for lifecycle operations + let initial_balance = 1_000_000; + let tokens = + setup_token_mints(&mut env.rpc, &env.payer, &creator.pubkey(), initial_balance).await; + + // Create AMM config (use index 1 to avoid collision with test_initialize_pool) + let amm_config = create_amm_config(&mut env.rpc, &env.payer, &admin, program_id, 1).await; + assert_amm_config_created(&mut env.rpc, amm_config).await; + + // Setup create pool fee account + setup_create_pool_fee_account(&mut env.rpc, &env.payer.pubkey()); + + // Derive PDAs + let pdas = derive_amm_pdas( + &program_id, + &amm_config, + &tokens.token_0_mint, + &tokens.token_1_mint, + &creator.pubkey(), + ); + + // ======================================================================== + // Initialize Pool + // ======================================================================== + let proof_result = get_pool_create_accounts_proof(&env.rpc, &program_id, &pdas).await; + + let init_amount_0 = 100_000; + let init_amount_1 = 100_000; + + let init_instruction = build_initialize_instruction( + program_id, + creator.pubkey(), + amm_config, + &pdas, + &tokens, + env.config_pda, + &proof_result, + init_amount_0, + init_amount_1, + 0, // open_time = 0 (immediate) + ); + + env.rpc + .create_and_send_transaction(&[init_instruction], &creator.pubkey(), &[&creator]) + .await + .expect("Initialize should succeed"); + + assert_pool_initialized(&mut env.rpc, &pdas).await; + + // Check initial LP token balance (should have received initial LP tokens from initialize) + let lp_balance_after_init = get_token_balance(&mut env.rpc, pdas.creator_lp_token).await; + println!("LP balance after init: {}", lp_balance_after_init); + assert!(lp_balance_after_init > 0, "Should have received LP tokens from initialization"); + + // ======================================================================== + // Deposit + // ======================================================================== + let lp_balance_before_deposit = get_token_balance(&mut env.rpc, pdas.creator_lp_token).await; + + // Deposit: request LP tokens, allow 10% slippage on tokens provided + let deposit_lp_amount = 500; + let max_token_0 = 10_000; // Allow generous slippage + let max_token_1 = 10_000; + + let deposit_instruction = build_deposit_instruction( + program_id, + creator.pubkey(), + &pdas, + &tokens, + tokens.creator_token_0, + tokens.creator_token_1, + deposit_lp_amount, + max_token_0, + max_token_1, + ); + + env.rpc + .create_and_send_transaction(&[deposit_instruction], &creator.pubkey(), &[&creator]) + .await + .expect("Deposit should succeed"); + + assert_deposit_succeeded( + &mut env.rpc, + pdas.creator_lp_token, + lp_balance_before_deposit, + deposit_lp_amount, + ) + .await; + + println!( + "Deposit succeeded. LP balance: {}", + get_token_balance(&mut env.rpc, pdas.creator_lp_token).await + ); + + // ======================================================================== + // Swap (token_0 -> token_1) + // ======================================================================== + // Warp time forward so pool is open for swaps (open_time = block_timestamp + 1) + env.rpc.warp_to_slot(100).unwrap(); + + let token_0_balance_before = get_token_balance(&mut env.rpc, tokens.creator_token_0).await; + let token_1_balance_before = get_token_balance(&mut env.rpc, tokens.creator_token_1).await; + + // Swap: 100 token_0 for token_1, allow 50% slippage + let swap_amount_in = 100; + let min_amount_out = 1; // Allow high slippage for test stability + + let swap_instruction = build_swap_instruction( + program_id, + creator.pubkey(), + amm_config, + &pdas, + &tokens, + tokens.creator_token_0, // input + tokens.creator_token_1, // output + true, // is_token_0_input + swap_amount_in, + min_amount_out, + ); + + env.rpc + .create_and_send_transaction(&[swap_instruction], &creator.pubkey(), &[&creator]) + .await + .expect("Swap should succeed"); + + assert_swap_succeeded( + &mut env.rpc, + tokens.creator_token_0, + tokens.creator_token_1, + token_0_balance_before, + token_1_balance_before, + swap_amount_in, + min_amount_out, + ) + .await; + + println!( + "Swap succeeded. Token 0 balance: {}, Token 1 balance: {}", + get_token_balance(&mut env.rpc, tokens.creator_token_0).await, + get_token_balance(&mut env.rpc, tokens.creator_token_1).await + ); + + // ======================================================================== + // Withdraw (burn half of LP tokens) + // ======================================================================== + let lp_balance_before_withdraw = get_token_balance(&mut env.rpc, pdas.creator_lp_token).await; + let withdraw_lp_amount = lp_balance_before_withdraw / 2; + + // Allow any amount of tokens out (0 minimum) + let withdraw_instruction = build_withdraw_instruction( + program_id, + creator.pubkey(), + &pdas, + &tokens, + tokens.creator_token_0, + tokens.creator_token_1, + withdraw_lp_amount, + 0, // minimum_token_0_amount - accept any + 0, // minimum_token_1_amount - accept any + ); + + env.rpc + .create_and_send_transaction(&[withdraw_instruction], &creator.pubkey(), &[&creator]) + .await + .expect("Withdraw should succeed"); + + assert_withdraw_succeeded( + &mut env.rpc, + pdas.creator_lp_token, + lp_balance_before_withdraw, + withdraw_lp_amount, + ) + .await; + + println!( + "Withdraw succeeded. LP balance: {}, Token 0 balance: {}, Token 1 balance: {}", + get_token_balance(&mut env.rpc, pdas.creator_lp_token).await, + get_token_balance(&mut env.rpc, tokens.creator_token_0).await, + get_token_balance(&mut env.rpc, tokens.creator_token_1).await + ); + + println!("Full lifecycle test completed successfully!"); +} diff --git a/programs/cp-swap/tests/helpers.rs b/programs/cp-swap/tests/helpers.rs new file mode 100644 index 0000000..60b651b --- /dev/null +++ b/programs/cp-swap/tests/helpers.rs @@ -0,0 +1,754 @@ +/// Functional integration test for cp-swap program. +/// Tests pool initialization with light-program-test framework. + +use anchor_lang::{InstructionData, ToAccountMetas}; +use light_compressible_client::{ + get_create_accounts_proof, CreateAccountsProofInput, CreateAccountsProofResult, + InitializeRentFreeConfig, +}; +use solana_pubkey::pubkey; +use light_program_test::{ + program_test::{setup_mock_program_data, LightProgramTest, TestRpc}, + Indexer, ProgramTestConfig, Rpc, +}; +use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID; +use light_token_sdk::{ + constants::CPI_AUTHORITY_PDA, + token::{ + find_mint_address, get_associated_token_address_and_bump, CreateAssociatedTokenAccount, + CreateMint, CreateMintParams, MintTo, COMPRESSIBLE_CONFIG_V1, + RENT_SPONSOR as LIGHT_TOKEN_RENT_SPONSOR, + }, +}; +use raydium_cp_swap::{ + instructions::initialize::LP_MINT_SIGNER_SEED, + states::{AMM_CONFIG_SEED, OBSERVATION_SEED, POOL_SEED, POOL_VAULT_SEED}, + InitializeParams, AUTH_SEED, +}; +use solana_instruction::Instruction; +use solana_keypair::Keypair; +use solana_pubkey::Pubkey; +use solana_signer::Signer; +use solana_sdk::{program_pack::Pack, signature::SeedDerivable}; +use anchor_spl::memo::spl_memo; +use spl_token_2022; + + + +// ============================================================================ +// Constants +// ============================================================================ + +const RENT_SPONSOR: Pubkey = pubkey!("CLEuMG7pzJX9xAuKCFzBP154uiG1GaNo4Fq7x6KAcAfG"); + +pub fn light_token_program_id() -> Pubkey { + Pubkey::from(LIGHT_TOKEN_PROGRAM_ID) +} + +// ============================================================================ +// Types +// ============================================================================ +/// PDAs for the AMM pool. +pub struct AmmPdas { + pub pool_state: Pubkey, + pub observation_state: Pubkey, + pub authority: Pubkey, + pub authority_bump: u8, + pub token_0_vault: Pubkey, + pub token_1_vault: Pubkey, + pub lp_mint_signer: Pubkey, + pub lp_mint_signer_bump: u8, + pub lp_mint: Pubkey, + pub creator_lp_token: Pubkey, + pub creator_lp_token_bump: u8, +} + +/// Test environment setup result. +pub struct TestEnv { + pub rpc: LightProgramTest, + pub payer: Keypair, + pub config_pda: Pubkey, +} + +/// Token mints and creator accounts for the pool. +pub struct TokenSetup { + pub token_0_mint: Pubkey, + pub token_1_mint: Pubkey, + pub creator_token_0: Pubkey, + pub creator_token_1: Pubkey, +} + +// ============================================================================ +// Setup Functions +// ============================================================================ + +/// Initialize the test environment with LightProgramTest and compression config. +pub async fn setup_test_environment(program_id: Pubkey) -> TestEnv { + let mut config = + ProgramTestConfig::new_v2(true, Some(vec![("raydium_cp_swap", program_id)])); + config = config.with_light_protocol_events(); + + let mut rpc = LightProgramTest::new(config).await.unwrap(); + let payer = rpc.get_payer().insecure_clone(); + + let program_data_pda = setup_mock_program_data(&mut rpc, &payer, &program_id); + + let (init_config_ix, config_pda) = InitializeRentFreeConfig::new( + &program_id, + &payer.pubkey(), + &program_data_pda, + RENT_SPONSOR, + payer.pubkey(), + ) + .build(); + + rpc.create_and_send_transaction(&[init_config_ix], &payer.pubkey(), &[&payer]) + .await + .expect("Initialize config should succeed"); + + TestEnv { + rpc, + payer, + config_pda, + } +} + +/// Create a compressed mint with ATAs for recipients. +pub async fn setup_create_mint( + rpc: &mut LightProgramTest, + payer: &Keypair, + mint_authority: Pubkey, + decimals: u8, + recipients: Vec<(u64, Pubkey)>, +) -> (Pubkey, Vec, Keypair) { + let mint_seed = Keypair::new(); + let address_tree = rpc.get_address_tree_v2(); + let output_queue = rpc.get_random_state_tree_info().unwrap().queue; + + let compression_address = light_token_sdk::token::derive_mint_compressed_address( + &mint_seed.pubkey(), + &address_tree.tree, + ); + + let (mint, bump) = find_mint_address(&mint_seed.pubkey()); + + let rpc_result = rpc + .get_validity_proof( + vec![], + vec![light_client::indexer::AddressWithTree { + address: compression_address, + tree: address_tree.tree, + }], + None, + ) + .await + .unwrap() + .value; + + let params = CreateMintParams { + decimals, + address_merkle_tree_root_index: rpc_result.addresses[0].root_index, + mint_authority, + proof: rpc_result.proof.0.unwrap(), + compression_address, + mint, + bump, + freeze_authority: None, + extensions: None, + rent_payment: 16, + write_top_up: 766, + }; + + let create_mint_builder = CreateMint::new( + params, + mint_seed.pubkey(), + payer.pubkey(), + address_tree.tree, + output_queue, + ); + let instruction = create_mint_builder.instruction().unwrap(); + + rpc.create_and_send_transaction(&[instruction], &payer.pubkey(), &[payer, &mint_seed]) + .await + .unwrap(); + + if recipients.is_empty() { + return (mint, vec![], mint_seed); + } + + let mut ata_pubkeys = Vec::with_capacity(recipients.len()); + + for (_amount, owner) in &recipients { + let (ata_address, _bump) = get_associated_token_address_and_bump(owner, &mint); + ata_pubkeys.push(ata_address); + + let create_ata = CreateAssociatedTokenAccount::new(payer.pubkey(), *owner, mint); + let ata_instruction = create_ata.instruction().unwrap(); + + rpc.create_and_send_transaction(&[ata_instruction], &payer.pubkey(), &[payer]) + .await + .unwrap(); + } + + for (idx, (amount, _)) in recipients.iter().enumerate() { + if *amount > 0 { + let mint_instruction = MintTo { + mint, + destination: ata_pubkeys[idx], + amount: *amount, + authority: mint_authority, + max_top_up: None, + } + .instruction() + .unwrap(); + + rpc.create_and_send_transaction(&[mint_instruction], &payer.pubkey(), &[payer]) + .await + .unwrap(); + } + } + + (mint, ata_pubkeys, mint_seed) +} + +/// Create token mints and fund creator with initial balances. +pub async fn setup_token_mints( + rpc: &mut LightProgramTest, + payer: &Keypair, + creator: &Pubkey, + initial_balance: u64, +) -> TokenSetup { + let (mint_a, ata_pubkeys_a, _) = setup_create_mint( + rpc, + payer, + payer.pubkey(), + 9, + vec![(initial_balance, *creator)], + ) + .await; + + let (mint_b, ata_pubkeys_b, _) = setup_create_mint( + rpc, + payer, + payer.pubkey(), + 9, + vec![(initial_balance, *creator)], + ) + .await; + + // Ensure proper ordering: token_0_mint < token_1_mint + if mint_a < mint_b { + TokenSetup { + token_0_mint: mint_a, + token_1_mint: mint_b, + creator_token_0: ata_pubkeys_a[0], + creator_token_1: ata_pubkeys_b[0], + } + } else { + TokenSetup { + token_0_mint: mint_b, + token_1_mint: mint_a, + creator_token_0: ata_pubkeys_b[0], + creator_token_1: ata_pubkeys_a[0], + } + } +} + +// ============================================================================ +// AMM Config Functions +// ============================================================================ + +/// Create and initialize the AMM config account. +/// Get the admin keypair for testing. +/// Must match the pubkey in lib.rs admin::ID when test-sbf feature is enabled. +pub fn get_admin_keypair() -> Keypair { + // This generates pubkey: 4zvwRjXUKGfvwnParsHAS3HuSVzV5cA4McphgmoCtajS + Keypair::from_seed(&[1u8; 32]).unwrap() +} + +pub async fn create_amm_config( + rpc: &mut LightProgramTest, + payer: &Keypair, + admin: &Keypair, + program_id: Pubkey, + index: u16, +) -> Pubkey { + let (amm_config_pda, _) = Pubkey::find_program_address( + &[AMM_CONFIG_SEED.as_bytes(), &index.to_be_bytes()], + &program_id, + ); + + let create_config_accounts = raydium_cp_swap::accounts::CreateAmmConfig { + owner: admin.pubkey(), + amm_config: amm_config_pda, + system_program: solana_sdk::system_program::ID, + }; + + let create_config_data = raydium_cp_swap::instruction::CreateAmmConfig { + index, + trade_fee_rate: 2500, + protocol_fee_rate: 1000, + fund_fee_rate: 500, + create_pool_fee: 0, + }; + + let create_config_ix = Instruction { + program_id, + accounts: create_config_accounts.to_account_metas(None), + data: create_config_data.data(), + }; + + rpc.create_and_send_transaction(&[create_config_ix], &payer.pubkey(), &[payer, admin]) + .await + .expect("Create AmmConfig should succeed"); + + amm_config_pda +} + +/// Setup the create_pool_fee account (wrapped SOL token account). +pub fn setup_create_pool_fee_account(rpc: &mut LightProgramTest, owner: &Pubkey) { + let create_pool_fee_receiver = raydium_cp_swap::create_pool_fee_receiver::ID; + let wsol_mint = spl_token::native_mint::id(); + + let mut fee_receiver_data = vec![0u8; spl_token::state::Account::LEN]; + let fee_account = spl_token::state::Account { + mint: wsol_mint, + owner: *owner, + amount: 0, + delegate: solana_sdk::program_option::COption::None, + state: spl_token::state::AccountState::Initialized, + is_native: solana_sdk::program_option::COption::Some(0), + delegated_amount: 0, + close_authority: solana_sdk::program_option::COption::None, + }; + spl_token::state::Account::pack(fee_account, &mut fee_receiver_data).unwrap(); + + rpc.set_account( + create_pool_fee_receiver, + solana_sdk::account::Account { + lamports: 1_000_000_000, + data: fee_receiver_data, + owner: spl_token::id(), + executable: false, + rent_epoch: 0, + }, + ); +} + +// ============================================================================ +// PDA Derivation +// ============================================================================ + +/// Derive all AMM PDAs for the pool. +pub fn derive_amm_pdas( + program_id: &Pubkey, + amm_config: &Pubkey, + token_0_mint: &Pubkey, + token_1_mint: &Pubkey, + creator: &Pubkey, +) -> AmmPdas { + let (pool_state, _) = Pubkey::find_program_address( + &[ + POOL_SEED.as_bytes(), + amm_config.as_ref(), + token_0_mint.as_ref(), + token_1_mint.as_ref(), + ], + program_id, + ); + + let (authority, authority_bump) = + Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], program_id); + + let (observation_state, _) = Pubkey::find_program_address( + &[OBSERVATION_SEED.as_bytes(), pool_state.as_ref()], + program_id, + ); + + let (token_0_vault, _) = Pubkey::find_program_address( + &[ + POOL_VAULT_SEED.as_bytes(), + pool_state.as_ref(), + token_0_mint.as_ref(), + ], + program_id, + ); + + let (token_1_vault, _) = Pubkey::find_program_address( + &[ + POOL_VAULT_SEED.as_bytes(), + pool_state.as_ref(), + token_1_mint.as_ref(), + ], + program_id, + ); + + let (lp_mint_signer, lp_mint_signer_bump) = + Pubkey::find_program_address(&[LP_MINT_SIGNER_SEED, pool_state.as_ref()], program_id); + + let (lp_mint, _) = find_mint_address(&lp_mint_signer); + + let (creator_lp_token, creator_lp_token_bump) = + get_associated_token_address_and_bump(creator, &lp_mint); + + AmmPdas { + pool_state, + observation_state, + authority, + authority_bump, + token_0_vault, + token_1_vault, + lp_mint_signer, + lp_mint_signer_bump, + lp_mint, + creator_lp_token, + creator_lp_token_bump, + } +} + +// ============================================================================ +// Instruction Building +// ============================================================================ + +/// Get the create accounts proof for pool initialization. +pub async fn get_pool_create_accounts_proof( + rpc: &LightProgramTest, + program_id: &Pubkey, + pdas: &AmmPdas, +) -> CreateAccountsProofResult { + get_create_accounts_proof( + rpc, + program_id, + vec![ + CreateAccountsProofInput::pda(pdas.pool_state), + CreateAccountsProofInput::pda(pdas.observation_state), + CreateAccountsProofInput::mint(pdas.lp_mint_signer), + ], + ) + .await + .unwrap() +} + +/// Build the Withdraw instruction. +pub fn build_withdraw_instruction( + program_id: Pubkey, + owner: Pubkey, + pdas: &AmmPdas, + tokens: &TokenSetup, + owner_token_0: Pubkey, + owner_token_1: Pubkey, + lp_token_amount: u64, + minimum_token_0_amount: u64, + minimum_token_1_amount: u64, +) -> Instruction { + let accounts = raydium_cp_swap::accounts::Withdraw { + owner, + authority: pdas.authority, + pool_state: pdas.pool_state, + owner_lp_token: pdas.creator_lp_token, + token_0_account: owner_token_0, + token_1_account: owner_token_1, + token_0_vault: pdas.token_0_vault, + token_1_vault: pdas.token_1_vault, + token_program: spl_token::id(), + token_program_2022: spl_token_2022::id(), + vault_0_mint: tokens.token_0_mint, + vault_1_mint: tokens.token_1_mint, + lp_mint: pdas.lp_mint, + memo_program: spl_memo::id(), + system_program: solana_sdk::system_program::ID, + light_token_cpi_authority: CPI_AUTHORITY_PDA, + light_token_program: light_token_program_id(), + }; + + let instruction_data = raydium_cp_swap::instruction::Withdraw { + lp_token_amount, + minimum_token_0_amount, + minimum_token_1_amount, + }; + + Instruction { + program_id, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + } +} + +/// Build the Swap instruction. +pub fn build_swap_instruction( + program_id: Pubkey, + payer: Pubkey, + amm_config: Pubkey, + pdas: &AmmPdas, + tokens: &TokenSetup, + input_token_account: Pubkey, + output_token_account: Pubkey, + is_token_0_input: bool, // true = swap 0->1, false = swap 1->0 + amount_in: u64, + minimum_amount_out: u64, +) -> Instruction { + let (input_vault, output_vault, input_mint, output_mint) = if is_token_0_input { + ( + pdas.token_0_vault, + pdas.token_1_vault, + tokens.token_0_mint, + tokens.token_1_mint, + ) + } else { + ( + pdas.token_1_vault, + pdas.token_0_vault, + tokens.token_1_mint, + tokens.token_0_mint, + ) + }; + + let accounts = raydium_cp_swap::accounts::Swap { + payer, + authority: pdas.authority, + amm_config, + pool_state: pdas.pool_state, + input_token_account, + output_token_account, + input_vault, + output_vault, + input_token_program: light_token_program_id(), + output_token_program: light_token_program_id(), + input_token_mint: input_mint, + output_token_mint: output_mint, + observation_state: pdas.observation_state, + light_token_program: light_token_program_id(), + system_program: solana_sdk::system_program::ID, + light_token_cpi_authority: CPI_AUTHORITY_PDA, + }; + + let instruction_data = raydium_cp_swap::instruction::SwapBaseInput { + amount_in, + minimum_amount_out, + }; + + Instruction { + program_id, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + } +} + +/// Build the Deposit instruction. +pub fn build_deposit_instruction( + program_id: Pubkey, + owner: Pubkey, + pdas: &AmmPdas, + tokens: &TokenSetup, + owner_token_0: Pubkey, + owner_token_1: Pubkey, + lp_token_amount: u64, + maximum_token_0_amount: u64, + maximum_token_1_amount: u64, +) -> Instruction { + let accounts = raydium_cp_swap::accounts::Deposit { + owner, + authority: pdas.authority, + pool_state: pdas.pool_state, + owner_lp_token: pdas.creator_lp_token, + token_0_account: owner_token_0, + token_1_account: owner_token_1, + token_0_vault: pdas.token_0_vault, + token_1_vault: pdas.token_1_vault, + token_program: spl_token::id(), + token_program_2022: spl_token_2022::id(), + light_token_program: light_token_program_id(), + vault_0_mint: tokens.token_0_mint, + vault_1_mint: tokens.token_1_mint, + lp_mint: pdas.lp_mint, + system_program: solana_sdk::system_program::ID, + light_token_cpi_authority: CPI_AUTHORITY_PDA, + }; + + let instruction_data = raydium_cp_swap::instruction::Deposit { + lp_token_amount, + maximum_token_0_amount, + maximum_token_1_amount, + }; + + Instruction { + program_id, + accounts: accounts.to_account_metas(None), + data: instruction_data.data(), + } +} + +/// Build the Initialize instruction. +pub fn build_initialize_instruction( + program_id: Pubkey, + creator: Pubkey, + amm_config: Pubkey, + pdas: &AmmPdas, + tokens: &TokenSetup, + config_pda: Pubkey, + proof_result: &CreateAccountsProofResult, + init_amount_0: u64, + init_amount_1: u64, + open_time: u64, +) -> Instruction { + let init_params = InitializeParams { + init_amount_0, + init_amount_1, + open_time, + create_accounts_proof: proof_result.create_accounts_proof.clone(), + lp_mint_signer_bump: pdas.lp_mint_signer_bump, + creator_lp_token_bump: pdas.creator_lp_token_bump, + authority_bump: pdas.authority_bump, + }; + + let accounts = raydium_cp_swap::accounts::Initialize { + creator, + amm_config, + authority: pdas.authority, + pool_state: pdas.pool_state, + token_0_mint: tokens.token_0_mint, + token_1_mint: tokens.token_1_mint, + lp_mint_signer: pdas.lp_mint_signer, + lp_mint: pdas.lp_mint, + creator_token_0: tokens.creator_token_0, + creator_token_1: tokens.creator_token_1, + creator_lp_token: pdas.creator_lp_token, + token_0_vault: pdas.token_0_vault, + token_1_vault: pdas.token_1_vault, + observation_state: pdas.observation_state, + create_pool_fee: raydium_cp_swap::create_pool_fee_receiver::ID, + token_program: spl_token::id(), + token_0_program: light_token_program_id(), + token_1_program: light_token_program_id(), + associated_token_program: anchor_spl::associated_token::ID, + system_program: solana_sdk::system_program::ID, + rent: solana_sdk::sysvar::rent::ID, + compression_config: config_pda, + light_token_compressible_config: Pubkey::from(COMPRESSIBLE_CONFIG_V1), + light_token_rent_sponsor: Pubkey::from(LIGHT_TOKEN_RENT_SPONSOR), + light_token_program: light_token_program_id(), + light_token_cpi_authority: CPI_AUTHORITY_PDA, + }; + + let instruction_data = raydium_cp_swap::instruction::Initialize { + params: init_params, + }; + + Instruction { + program_id, + accounts: [ + accounts.to_account_metas(None), + proof_result.remaining_accounts.clone(), + ] + .concat(), + data: instruction_data.data(), + } +} + +// ============================================================================ +// Assertions +// ============================================================================ + +/// Get the balance of a token account. +/// Supports both SPL Token and Light Token accounts. +pub async fn get_token_balance(rpc: &mut LightProgramTest, account: Pubkey) -> u64 { + let account_data = rpc.get_account(account).await.unwrap(); + if let Some(account) = account_data { + // Token account layout: mint (32) + owner (32) + amount (8) + // Works for both SPL tokens and Light tokens + const AMOUNT_OFFSET: usize = 64; + if account.data.len() >= AMOUNT_OFFSET + 8 { + let amount_bytes = &account.data[AMOUNT_OFFSET..AMOUNT_OFFSET + 8]; + u64::from_le_bytes(amount_bytes.try_into().unwrap()) + } else { + 0 + } + } else { + 0 + } +} + +/// Verify that the pool was initialized correctly. +pub async fn assert_pool_initialized(rpc: &mut LightProgramTest, pdas: &AmmPdas) { + let pool_account = rpc.get_account(pdas.pool_state).await.unwrap(); + assert!(pool_account.is_some(), "Pool state should exist"); + + let observation_account = rpc.get_account(pdas.observation_state).await.unwrap(); + assert!( + observation_account.is_some(), + "Observation state should exist" + ); +} + +/// Assert that deposit succeeded by checking LP token balance increased. +pub async fn assert_deposit_succeeded( + rpc: &mut LightProgramTest, + owner_lp_token: Pubkey, + lp_balance_before: u64, + expected_lp_increase: u64, +) { + let lp_balance_after = get_token_balance(rpc, owner_lp_token).await; + let actual_increase = lp_balance_after.saturating_sub(lp_balance_before); + assert!( + actual_increase >= expected_lp_increase, + "LP token balance should increase by at least {}. Before: {}, After: {}, Actual increase: {}", + expected_lp_increase, + lp_balance_before, + lp_balance_after, + actual_increase + ); +} + +/// Assert that swap succeeded by checking balances changed correctly. +pub async fn assert_swap_succeeded( + rpc: &mut LightProgramTest, + input_account: Pubkey, + output_account: Pubkey, + input_balance_before: u64, + output_balance_before: u64, + expected_input_decrease: u64, + min_output_increase: u64, +) { + let input_balance_after = get_token_balance(rpc, input_account).await; + let output_balance_after = get_token_balance(rpc, output_account).await; + + let actual_input_decrease = input_balance_before.saturating_sub(input_balance_after); + let actual_output_increase = output_balance_after.saturating_sub(output_balance_before); + + assert_eq!( + actual_input_decrease, expected_input_decrease, + "Input token balance should decrease by {}. Before: {}, After: {}", + expected_input_decrease, input_balance_before, input_balance_after + ); + + assert!( + actual_output_increase >= min_output_increase, + "Output token balance should increase by at least {}. Before: {}, After: {}, Actual: {}", + min_output_increase, + output_balance_before, + output_balance_after, + actual_output_increase + ); +} + +/// Assert that withdraw succeeded by checking LP token balance decreased. +pub async fn assert_withdraw_succeeded( + rpc: &mut LightProgramTest, + owner_lp_token: Pubkey, + lp_balance_before: u64, + expected_lp_decrease: u64, +) { + let lp_balance_after = get_token_balance(rpc, owner_lp_token).await; + let actual_decrease = lp_balance_before.saturating_sub(lp_balance_after); + assert_eq!( + actual_decrease, expected_lp_decrease, + "LP token balance should decrease by {}. Before: {}, After: {}", + expected_lp_decrease, lp_balance_before, lp_balance_after + ); +} + +/// Verify that the AMM config was created. +pub async fn assert_amm_config_created(rpc: &mut LightProgramTest, amm_config: Pubkey) { + let account = rpc.get_account(amm_config).await.unwrap(); + assert!(account.is_some(), "AmmConfig account should exist"); +} diff --git a/scripts/lut.json b/scripts/lut.json deleted file mode 100644 index fadb3b3..0000000 --- a/scripts/lut.json +++ /dev/null @@ -1 +0,0 @@ -{"account":{"data":["AQAAAP//////////AAAAAAAAAAAjAQFfKLpxtXVJdt0K8yLckTFEIuQhmYfmVBFu2pUHcB7pAADmyRiwvXzPkVREinq/ao85eCmh6P0Ip/DQs6q4eFL8MganVfghOQVNRCSxWvDEMM8vS3+YeTraElLUjzZmxsvOHuvEjPsyZLvDS/XFpag0/GdQAG8phtlvI1vIh1703UQLvA/Au0fKL3TEES6UqxPPo8Y05dwX6ssDzRojzX54fPuzKHUQXK6FtbREdgftv+FFJ7+0I5EcpAQjv9FSeiZ1CSw27CL1F4MA/bRKqmr/z/Ckbhy8ZBwOPtCdoTue9QgNAckoq0XTZVlaNOh3F/uwAIoZ0i8FLJ2h+YjEfFfeOguzCf2uDjrUg+kHQ7Tbp9KFUZWBkiLHcl2rauSSjP1VCKbpdecSJePoAVrHCv9ueLC92ILkkip+g4YPN4HoZU8IqnLs6kC6LnFYzDAA3P4bI+a9VH85QjlqZUSm8DujjAkVo1cjeU6Ptl0HW2tyaZw43QLllIt1sOWgQY6Al1tEBt324ddloZPZy+FGzut5rBy0he1fWzeROoz1hX7/AKkBXyi6cbV1SXbdCvMi3JExRCLkIZmH5lQRbtqVB3Ae6QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABt324e51j94YQl285GzN2rYa/E2DuQ0n/r35KNihi/wNAckoq0XTZVlaNOh3F/uwAIoZ0i8FLJ2h+YjEfFfeOguzCf2uDjrUg+kHQ7Tbp9KFUZWBkiLHcl2rauSSjP1VDQHJSTjmAlqoRvR63cIxy1VM6ev50lx9reTflsEae74Lswoa1RVJ0Mu8LffQ6X1uPzdaf1F4vE9YrAOb/3cFlg0ByVALKmF5+LZAuuTourIKXBRnlL+ueKqjmO2NT1YiC7MKL1NY6ztCiuxrOujiAu6LiQSD7ayhhKZ8zgIv+NoNAcl29p0oXdXdmJAZucjHinlDm0UdLZpmjkYlR7pjWAuzCj+l+30neNOGxmwvUYcBH5BcgmYI9bQ1G93CnQlFDQHJjHsR9+0RfSd6DupgTsrnyeMV7FkYPMUi9B72m0ELswpaaVYQ3FdNhY1zYZ6pCnZacHb3QkTqquAA790JMg0ByaKlHaua0II3lex12tecwzKR80ACCNv3pH4Uyo+nC7MKd57DjFifOFFdPZW8pdEs/3900yXEUGr46QcKMK8NAcm2aClU5SxQxOIA5pDWNyFEzGgedDouKX5Q/jSz2wuzCo8pqKAANMsHa1t957TmV6lEy1bPZfPPgZLRjHVsDQHJxMBQw9Ct1uCfVyi+5wxWd0O75gXvV0AhZ3pGjX4LswqjxSORQaRTjRJlkOMKDsJ0yZAyJlqje0FDEap/gg0BydoNu62NBXntAkJwqhoi8SO5svaEsnL1rvZDx6HSC7MKrILMRdfDTRC6TFZYXXbWukd/yxes5+TD3Rr5FDUNAcn7Dl44tSSTIed69Ah/g/iwTX7zFHBaoQ5CON87uguzCs6Ej4Y5TeYX2JLbRYORxgDKe+RqLb3KTQFD6xl9BqfVFxksXFEhjMlMPUrxf1ja7gibof1E49vZigAAAACMlyWPTiSJ8bs9ECkUjg2DC1oTmdr/EIQEjnvY2+n4WQ==","base64"],"executable":false,"lamports":9521280,"owner":"AddressLookupTab1e1111111111111111111111111","rentEpoch":18446744073709551615,"space":1240},"pubkey":"9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ"} \ No newline at end of file diff --git a/scripts/test-with-light.sh b/scripts/test-with-light.sh deleted file mode 100755 index f23beee..0000000 --- a/scripts/test-with-light.sh +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash - -# Starts solana-test-validator with all ZK Compression programs, prover, photon -# indexer, cp-amm accounts, and a lookup table. Also deploys the -# cp-swap program. -light test-validator --validator-args "--clone DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8 \ - --clone D4FPEruKEHrG5TenZ2mpDGEfu1iUvTiqBxvpU8HLBvC2 \ - --account 9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ ./scripts/lut.json \ - --url https://api.mainnet-beta.solana.com \ - --upgradeable-program CPMMoo8L3F4NbTegBCKVNunggL7H1ZpdTHKxQB5qKP1C target/deploy/raydium_cp_swap.so ~/.config/solana/id.json" - -PHOTON_PID=$(pgrep -f photon) -PROVER_PID=$(pgrep -f prover) -VALIDATOR_PID=$(pgrep -f solana-test-validator) - -solana airdrop 1000 ~/.config/solana/id.json --url "localhost" - -echo "Running anchor test..." -anchor test --skip-local-validator --skip-deploy \ No newline at end of file diff --git a/tests/deposit.test.ts b/tests/deposit.test.ts deleted file mode 100644 index 55ace9d..0000000 --- a/tests/deposit.test.ts +++ /dev/null @@ -1,362 +0,0 @@ -import * as anchor from "@coral-xyz/anchor"; -import { Program, BN } from "@coral-xyz/anchor"; -import { RaydiumCpSwap } from "../target/types/raydium_cp_swap"; -import { - calculateFee, - calculatePreFeeAmount, - deposit, - getUserAndPoolVaultAmount, - setupDepositTest, - fetchCompressibleAccount, -} from "./utils"; -import { assert } from "chai"; -import { MAX_FEE_BASIS_POINTS, TOKEN_PROGRAM_ID } from "@solana/spl-token"; -import { - createRpc, - getDefaultAddressTreeInfo, -} from "@lightprotocol/stateless.js"; - -describe("deposit test", () => { - anchor.setProvider(anchor.AnchorProvider.env()); - const owner = anchor.Wallet.local().payer; - - const program = anchor.workspace.RaydiumCpSwap as Program; - - // Extend connection with zkcompression endpoints - const connection = createRpc(); - - const confirmOptions = { - skipPreflight: true, - }; - - it("deposit test, add the same liquidity and check the correctness of the values with and without transfer fees", async () => { - /// deposit without fee - const { poolAddress, poolState } = await setupDepositTest( - program, - connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - { transferFeeBasisPoints: 0, MaxFee: 0 } - ); - - const { - ownerToken0Account: ownerToken0AccountBefore, - ownerToken1Account: ownerToken1AccountBefore, - poolVault0TokenAccount: poolVault0TokenAccountBefore, - poolVault1TokenAccount: poolVault1TokenAccountBefore, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - poolState.token0Vault, - poolState.token1Vault - ); - - const liquidity = new BN(10000000000); - await deposit( - program, - owner, - poolState.ammConfig, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - liquidity, - new BN(10000000000), - new BN(20000000000), - confirmOptions - ); - - const { account: newPoolState } = await fetchCompressibleAccount( - poolAddress, - getDefaultAddressTreeInfo(), - program, - "poolState", - connection - ); - assert(newPoolState.lpSupply.eq(liquidity.add(poolState.lpSupply))); - - const { - ownerToken0Account: ownerToken0AccountAfter, - ownerToken1Account: ownerToken1AccountAfter, - poolVault0TokenAccount: poolVault0TokenAccountAfter, - poolVault1TokenAccount: poolVault1TokenAccountAfter, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - poolState.token0Vault, - poolState.token1Vault - ); - const input_token0_amount = - ownerToken0AccountBefore.amount - ownerToken0AccountAfter.amount; - const input_token1_amount = - ownerToken1AccountBefore.amount - ownerToken1AccountAfter.amount; - assert.equal( - poolVault0TokenAccountAfter.amount - poolVault0TokenAccountBefore.amount, - input_token0_amount - ); - assert.equal( - poolVault1TokenAccountAfter.amount - poolVault1TokenAccountBefore.amount, - input_token1_amount - ); - - // TransferFeeConfig extension is not supported. - const transferFeeConfig = { - transferFeeBasisPoints: 0, - MaxFee: 0, - }; // %0 - - // Ensure that the initialization state is the same with depsoit without fee - const { poolAddress: poolAddress2, poolState: poolState2 } = - await setupDepositTest( - program, - connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - transferFeeConfig, - confirmOptions, - { - initAmount0: new BN( - calculatePreFeeAmount( - transferFeeConfig, - poolVault0TokenAccountBefore.amount, - poolState.token0Program - ).toString() - ), - initAmount1: new BN( - calculatePreFeeAmount( - transferFeeConfig, - poolVault1TokenAccountBefore.amount, - poolState.token1Program - ).toString() - ), - }, - { - token0Program: poolState.token0Program, - token1Program: poolState.token1Program, - } - ); - const { - ownerToken0Account: ownerToken0AccountBefore2, - ownerToken1Account: ownerToken1AccountBefore2, - poolVault0TokenAccount: poolVault0TokenAccountBefore2, - poolVault1TokenAccount: poolVault1TokenAccountBefore2, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState2.token0Mint, - poolState2.token0Program, - poolState2.token1Mint, - poolState2.token1Program, - poolState2.token0Vault, - poolState2.token1Vault - ); - - // check vault init state - assert.equal( - poolVault0TokenAccountBefore2.amount, - poolVault0TokenAccountBefore.amount - ); - assert.equal( - poolVault1TokenAccountBefore2.amount, - poolVault1TokenAccountBefore.amount - ); - - await deposit( - program, - owner, - poolState2.ammConfig, - poolState2.token0Mint, - poolState2.token0Program, - poolState2.token1Mint, - poolState2.token1Program, - liquidity, - new BN(100000000000), - new BN(200000000000), - confirmOptions - ); - - const { account: newPoolState2 } = await fetchCompressibleAccount( - poolAddress2, - getDefaultAddressTreeInfo(), - program, - "poolState", - connection - ); - - assert(newPoolState2.lpSupply.eq(liquidity.add(poolState2.lpSupply))); - - const { - ownerToken0Account: ownerToken0AccountAfter2, - ownerToken1Account: ownerToken1AccountAfter2, - poolVault0TokenAccount: poolVault0TokenAccountAfter2, - poolVault1TokenAccount: poolVault1TokenAccountAfter2, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState2.token0Mint, - poolState2.token0Program, - poolState2.token1Mint, - poolState2.token1Program, - poolState2.token0Vault, - poolState2.token1Vault - ); - - const input_token0_amount_with_fee = - ownerToken0AccountBefore2.amount - ownerToken0AccountAfter2.amount; - const input_token1_amount_with_fee = - ownerToken1AccountBefore2.amount - ownerToken1AccountAfter2.amount; - assert(input_token0_amount_with_fee >= input_token0_amount); - assert(input_token1_amount_with_fee >= input_token1_amount); - - assert.equal( - input_token0_amount_with_fee, - calculateFee( - transferFeeConfig, - input_token0_amount_with_fee, - poolState2.token0Program - ) + input_token0_amount - ); - assert.equal( - input_token1_amount_with_fee, - calculateFee( - transferFeeConfig, - input_token1_amount_with_fee, - poolState2.token1Program - ) + input_token1_amount - ); - - // Add the same liquidity, the amount increment of the pool vault will be the same as without fees. - assert.equal( - poolVault0TokenAccountAfter2.amount - - poolVault0TokenAccountBefore2.amount, - input_token0_amount - ); - assert.equal( - poolVault1TokenAccountAfter2.amount - - poolVault1TokenAccountBefore2.amount, - input_token1_amount - ); - - assert.equal( - poolVault0TokenAccountAfter.amount, - poolVault0TokenAccountAfter2.amount - ); - assert.equal( - poolVault1TokenAccountAfter.amount, - poolVault1TokenAccountAfter2.amount - ); - }); - - // t22 transferFeeConfig is not supported. - it.skip("deposit test with 100% transferFeeConfig, reache maximum fee limit", async () => { - const transferFeeConfig = { - transferFeeBasisPoints: MAX_FEE_BASIS_POINTS, - MaxFee: 5000000000, - }; // %100 - - const { poolAddress, poolState } = await setupDepositTest( - program, - connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - transferFeeConfig - ); - - const { - ownerToken0Account: ownerToken0AccountBefore, - ownerToken1Account: ownerToken1AccountBefore, - poolVault0TokenAccount: poolVault0TokenAccountBefore, - poolVault1TokenAccount: poolVault1TokenAccountBefore, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - poolState.token0Vault, - poolState.token1Vault - ); - - const liquidity = new BN(10000000000); - await deposit( - program, - owner, - poolState.ammConfig, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - liquidity, - new BN(10000000000), - new BN(20000000000), - confirmOptions - ); - const newPoolState = await program.account.poolState.fetch(poolAddress); - assert(newPoolState.lpSupply.eq(liquidity.add(poolState.lpSupply))); - - const { - ownerToken0Account: ownerToken0AccountAfter, - ownerToken1Account: ownerToken1AccountAfter, - poolVault0TokenAccount: poolVault0TokenAccountAfter, - poolVault1TokenAccount: poolVault1TokenAccountAfter, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - poolState.token0Vault, - poolState.token1Vault - ); - const input_token0_amount = - ownerToken0AccountBefore.amount - ownerToken0AccountAfter.amount; - const input_token1_amount = - ownerToken1AccountBefore.amount - ownerToken1AccountAfter.amount; - - if (poolState.token0Program.equals(TOKEN_PROGRAM_ID)) { - assert.equal( - poolVault0TokenAccountAfter.amount - - poolVault0TokenAccountBefore.amount, - input_token0_amount - ); - assert.equal( - poolVault1TokenAccountAfter.amount - - poolVault1TokenAccountBefore.amount, - input_token1_amount - BigInt(transferFeeConfig.MaxFee) - ); - } else { - assert.equal( - poolVault0TokenAccountAfter.amount - - poolVault0TokenAccountBefore.amount, - input_token0_amount - BigInt(transferFeeConfig.MaxFee) - ); - assert.equal( - poolVault1TokenAccountAfter.amount - - poolVault1TokenAccountBefore.amount, - input_token1_amount - ); - } - }); -}); diff --git a/tests/initialize.test.ts b/tests/initialize.test.ts deleted file mode 100644 index cde64d7..0000000 --- a/tests/initialize.test.ts +++ /dev/null @@ -1,188 +0,0 @@ -import * as anchor from "@coral-xyz/anchor"; -import { Program, BN } from "@coral-xyz/anchor"; -import { RaydiumCpSwap } from "../target/types/raydium_cp_swap"; -import { getAccount, TOKEN_PROGRAM_ID } from "@solana/spl-token"; -import { setupInitializeTest, initialize, calculateFee } from "./utils"; -import { assert } from "chai"; -import { createRpc, featureFlags, VERSION } from "@lightprotocol/stateless.js"; -import { CompressedTokenProgram } from "@lightprotocol/compressed-token"; - -featureFlags.version = VERSION.V2; -describe("initialize test", () => { - anchor.setProvider(anchor.AnchorProvider.env()); - const owner = anchor.Wallet.local().payer; - console.log("owner: ", owner.publicKey.toString()); - - const program = anchor.workspace.RaydiumCpSwap as Program; - - const confirmOptions = { - skipPreflight: true, - }; - // Extend connection with zkcompression endpoints - const connection = createRpc(); - - it("create pool without fee", async () => { - const { configAddress, token0, token0Program, token1, token1Program } = - await setupInitializeTest( - program, - connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - { transferFeeBasisPoints: 0, MaxFee: 0 }, - confirmOptions - ); - - const initAmount0 = new BN(10000000000); - const initAmount1 = new BN(10000000000); - const { poolAddress, poolState } = await initialize( - program, - owner, - configAddress, - token0, - token0Program, - token1, - token1Program, - confirmOptions, - { initAmount0, initAmount1 } - ); - let vault0 = await getAccount( - connection, - poolState.token0Vault, - "processed", - CompressedTokenProgram.programId - ); - assert.equal(vault0.amount.toString(), initAmount0.toString()); - - let vault1 = await getAccount( - connection, - poolState.token1Vault, - "processed", - CompressedTokenProgram.programId - ); - assert.equal(vault1.amount.toString(), initAmount1.toString()); - }); - - it("create pool with fee", async () => { - const { configAddress, token0, token0Program, token1, token1Program } = - await setupInitializeTest( - program, - connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(100000000), - }, - { transferFeeBasisPoints: 0, MaxFee: 0 }, - confirmOptions - ); - - const initAmount0 = new BN(10000000000); - const initAmount1 = new BN(10000000000); - const { poolAddress, poolState } = await initialize( - program, - owner, - configAddress, - token0, - token0Program, - token1, - token1Program, - confirmOptions, - { initAmount0, initAmount1 } - ); - let vault0 = await getAccount( - connection, - poolState.token0Vault, - "processed", - CompressedTokenProgram.programId - ); - assert.equal(vault0.amount.toString(), initAmount0.toString()); - - let vault1 = await getAccount( - anchor.getProvider().connection, - poolState.token1Vault, - "processed", - CompressedTokenProgram.programId - ); - assert.equal(vault1.amount.toString(), initAmount1.toString()); - }); - - // t22 transferFeeConfig is not supported. - it.skip("create pool with token2022 mint has transfer fee", async () => { - const transferFeeConfig = { transferFeeBasisPoints: 100, MaxFee: 50000000 }; // %10 - const { configAddress, token0, token0Program, token1, token1Program } = - await setupInitializeTest( - program, - connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(100000000), - }, - transferFeeConfig, - confirmOptions - ); - - const initAmount0 = new BN(10000000000); - const initAmount1 = new BN(10000000000); - const { poolAddress, poolState } = await initialize( - program, - owner, - configAddress, - token0, - token0Program, - token1, - token1Program, - confirmOptions, - { initAmount0, initAmount1 } - ); - let vault0 = await getAccount( - anchor.getProvider().connection, - poolState.token0Vault, - "processed", - poolState.token0Program - ); - if (token0Program == TOKEN_PROGRAM_ID) { - assert.equal(vault0.amount.toString(), initAmount0.toString()); - } else { - const total = - vault0.amount + - calculateFee( - transferFeeConfig, - BigInt(initAmount0.toString()), - poolState.token0Program - ); - assert(new BN(total.toString()).gte(initAmount0)); - } - - let vault1 = await getAccount( - anchor.getProvider().connection, - poolState.token1Vault, - "processed", - poolState.token1Program - ); - if (token1Program == TOKEN_PROGRAM_ID) { - assert.equal(vault1.amount.toString(), initAmount1.toString()); - } else { - const total = - vault1.amount + - calculateFee( - transferFeeConfig, - BigInt(initAmount1.toString()), - poolState.token1Program - ); - assert(new BN(total.toString()).gte(initAmount1)); - } - }); -}); diff --git a/tests/swap.test.ts b/tests/swap.test.ts deleted file mode 100644 index b637d41..0000000 --- a/tests/swap.test.ts +++ /dev/null @@ -1,200 +0,0 @@ -import * as anchor from "@coral-xyz/anchor"; -import { Program, BN } from "@coral-xyz/anchor"; -import { RaydiumCpSwap } from "../target/types/raydium_cp_swap"; -import { setupSwapTest, swap_base_input, swap_base_output } from "./utils"; -import { assert } from "chai"; -import { getAccount, getAssociatedTokenAddressSync } from "@solana/spl-token"; - -describe("swap test", () => { - anchor.setProvider(anchor.AnchorProvider.env()); - const owner = anchor.Wallet.local().payer; - - const program = anchor.workspace.RaydiumCpSwap as Program; - - const confirmOptions = { - skipPreflight: true, - }; - - it("swap base input without transfer fee", async () => { - const { configAddress, poolAddress, poolState } = await setupSwapTest( - program, - anchor.getProvider().connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - { transferFeeBasisPoints: 0, MaxFee: 0 } - ); - const inputToken = poolState.token0Mint; - const inputTokenProgram = poolState.token0Program; - const inputTokenAccountAddr = getAssociatedTokenAddressSync( - inputToken, - owner.publicKey, - false, - inputTokenProgram - ); - const inputTokenAccountBefore = await getAccount( - anchor.getProvider().connection, - inputTokenAccountAddr, - "processed", - inputTokenProgram - ); - await sleep(1000); - let amount_in = new BN(100000000); - await swap_base_input( - program, - owner, - configAddress, - inputToken, - inputTokenProgram, - poolState.token1Mint, - poolState.token1Program, - amount_in, - new BN(0) - ); - const inputTokenAccountAfter = await getAccount( - anchor.getProvider().connection, - inputTokenAccountAddr, - "processed", - inputTokenProgram - ); - assert.equal( - inputTokenAccountBefore.amount - inputTokenAccountAfter.amount, - BigInt(amount_in.toString()) - ); - }); - - it("swap base output without transfer fee", async () => { - const { configAddress, poolAddress, poolState } = await setupSwapTest( - program, - anchor.getProvider().connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - { transferFeeBasisPoints: 0, MaxFee: 0 } - ); - const inputToken = poolState.token0Mint; - const inputTokenProgram = poolState.token0Program; - const inputTokenAccountAddr = getAssociatedTokenAddressSync( - inputToken, - owner.publicKey, - false, - inputTokenProgram - ); - const outputToken = poolState.token1Mint; - const outputTokenProgram = poolState.token1Program; - const outputTokenAccountAddr = getAssociatedTokenAddressSync( - outputToken, - owner.publicKey, - false, - outputTokenProgram - ); - const outputTokenAccountBefore = await getAccount( - anchor.getProvider().connection, - outputTokenAccountAddr, - "processed", - outputTokenProgram - ); - await sleep(1000); - let amount_out = new BN(100000000); - await swap_base_output( - program, - owner, - configAddress, - inputToken, - inputTokenProgram, - poolState.token1Mint, - poolState.token1Program, - amount_out, - new BN(10000000000000), - confirmOptions - ); - const outputTokenAccountAfter = await getAccount( - anchor.getProvider().connection, - outputTokenAccountAddr, - "processed", - outputTokenProgram - ); - assert.equal( - outputTokenAccountAfter.amount - outputTokenAccountBefore.amount, - BigInt(amount_out.toString()) - ); - }); - - it("swap base output with transfer fee", async () => { - const transferFeeConfig = { transferFeeBasisPoints: 5, MaxFee: 5000 }; // %5 - const { configAddress, poolAddress, poolState } = await setupSwapTest( - program, - anchor.getProvider().connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - transferFeeConfig - ); - - const inputToken = poolState.token0Mint; - const inputTokenProgram = poolState.token0Program; - const inputTokenAccountAddr = getAssociatedTokenAddressSync( - inputToken, - owner.publicKey, - false, - inputTokenProgram - ); - const outputToken = poolState.token1Mint; - const outputTokenProgram = poolState.token1Program; - const outputTokenAccountAddr = getAssociatedTokenAddressSync( - outputToken, - owner.publicKey, - false, - outputTokenProgram - ); - const outputTokenAccountBefore = await getAccount( - anchor.getProvider().connection, - outputTokenAccountAddr, - "processed", - outputTokenProgram - ); - await sleep(1000); - let amount_out = new BN(100000000); - await swap_base_output( - program, - owner, - configAddress, - inputToken, - inputTokenProgram, - poolState.token1Mint, - poolState.token1Program, - amount_out, - new BN(10000000000000), - confirmOptions - ); - const outputTokenAccountAfter = await getAccount( - anchor.getProvider().connection, - outputTokenAccountAddr, - "processed", - outputTokenProgram - ); - assert.equal( - outputTokenAccountAfter.amount - outputTokenAccountBefore.amount, - BigInt(amount_out.toString()) - ); - }); -}); - -function sleep(ms: number): Promise { - return new Promise((resolve) => setTimeout(resolve, ms)); -} diff --git a/tests/utils/fee.ts b/tests/utils/fee.ts deleted file mode 100644 index d023ca9..0000000 --- a/tests/utils/fee.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { - MAX_FEE_BASIS_POINTS, - ONE_IN_BASIS_POINTS, - TOKEN_PROGRAM_ID, -} from "@solana/spl-token"; -import { PublicKey } from "@solana/web3.js"; - -export function calculateFee( - transferFeeConfig: { transferFeeBasisPoints: number; MaxFee: number }, - preFeeAmount: bigint, - tokenProgram: PublicKey -): bigint { - if (tokenProgram.equals(TOKEN_PROGRAM_ID)) { - return BigInt(0); - } - if (preFeeAmount === BigInt(0)) { - return BigInt(0); - } else { - const numerator = - preFeeAmount * BigInt(transferFeeConfig.transferFeeBasisPoints); - const rawFee = - (numerator + ONE_IN_BASIS_POINTS - BigInt(1)) / ONE_IN_BASIS_POINTS; - const fee = - rawFee > transferFeeConfig.MaxFee ? transferFeeConfig.MaxFee : rawFee; - return BigInt(fee); - } -} - -export function calculatePreFeeAmount( - transferFeeConfig: { transferFeeBasisPoints: number; MaxFee: number }, - postFeeAmount: bigint, - tokenProgram: PublicKey -) { - if ( - transferFeeConfig.transferFeeBasisPoints == 0 || - tokenProgram.equals(TOKEN_PROGRAM_ID) - ) { - return postFeeAmount; - } else { - let numerator = postFeeAmount * BigInt(MAX_FEE_BASIS_POINTS); - let denominator = - MAX_FEE_BASIS_POINTS - transferFeeConfig.transferFeeBasisPoints; - - return (numerator + BigInt(denominator) - BigInt(1)) / BigInt(denominator); - } -} diff --git a/tests/utils/index.ts b/tests/utils/index.ts deleted file mode 100644 index 2bbbc15..0000000 --- a/tests/utils/index.ts +++ /dev/null @@ -1,5 +0,0 @@ -export * from "./web3"; -export * from "./pda"; -export * from "./util"; -export * from "./fee"; -export * from "./instruction"; diff --git a/tests/utils/instruction.ts b/tests/utils/instruction.ts deleted file mode 100644 index e866f08..0000000 --- a/tests/utils/instruction.ts +++ /dev/null @@ -1,1117 +0,0 @@ -import { Program, BN, IdlTypes } from "@coral-xyz/anchor"; -import { RaydiumCpSwap } from "../../target/types/raydium_cp_swap"; -import { - Connection, - ConfirmOptions, - PublicKey, - Keypair, - Signer, - SystemProgram, - SYSVAR_RENT_PUBKEY, - ComputeBudgetProgram, -} from "@solana/web3.js"; -import { - TOKEN_PROGRAM_ID, - TOKEN_2022_PROGRAM_ID, - getAssociatedTokenAddressSync, - ASSOCIATED_TOKEN_PROGRAM_ID, -} from "@solana/spl-token"; -import { - accountExist, - sendTransaction, - getAmmConfigAddress, - getAuthAddress, - getPoolAddress, - getPoolLpMintAddress, - getPoolVaultAddress, - createTokenMintAndAssociatedTokenAccount, - getOracleAccountAddress, - fetchCompressibleAccount, - POOL_SEED, - ORACLE_SEED, - getLpVaultAddress, - getPoolLpMintSignerAddress, - getPoolLpMintCompressedAddress, -} from "./index"; -import { - createRpc, - bn, - sendAndConfirmTx, - featureFlags, - VERSION, - Rpc, - deriveAddressV2, - initializeCompressionConfig, - selectStateTreeInfo, - getDefaultAddressTreeInfo, - packTreeInfos, - deriveCompressionConfigAddress, - createPackedAccountsSmall, - buildAndSignTx, - PackedStateTreeInfo, - createPackedAccountsSmallWithCpiContext, -} from "@lightprotocol/stateless.js"; - -import { - CompressedTokenProgram, - createTokenPool, - getAssociatedCTokenAddressAndBump, -} from "@lightprotocol/compressed-token"; -import { bs58 } from "@coral-xyz/anchor/dist/cjs/utils/bytes"; - -featureFlags.version = VERSION.V2; -const COMPRESSION_DELAY = 100; -const ADDRESS_SPACE = [ - new PublicKey("EzKE84aVTkCUhDHLELqyJaq1Y7UVVmqxXqZjVHwHY3rK"), -]; - -type CompressedAccountVariant = - IdlTypes["compressedAccountVariant"]; - -export async function setupInitializeTest( - program: Program, - connection: Rpc, - owner: Signer, - config: { - config_index: number; - tradeFeeRate: BN; - protocolFeeRate: BN; - fundFeeRate: BN; - create_fee: BN; - }, - transferFeeConfig: { transferFeeBasisPoints: number; MaxFee: number } = { - transferFeeBasisPoints: 0, - MaxFee: 0, - }, - confirmOptions?: ConfirmOptions -) { - const [{ token0, token0Program }, { token1, token1Program }] = - await createTokenMintAndAssociatedTokenAccount( - connection, - owner, - new Keypair(), - transferFeeConfig - ); - const configAddress = await createAmmConfig( - program, - connection, - owner, - config.config_index, - config.tradeFeeRate, - config.protocolFeeRate, - config.fundFeeRate, - config.create_fee, - confirmOptions - ); - - const [address, _] = deriveCompressionConfigAddress(program.programId); - if (!(await accountExist(connection, address))) { - await initializeCompressionConfig( - connection, - owner, - program.programId, - program.provider.wallet.payer, - COMPRESSION_DELAY, - program.provider.wallet.payer.publicKey, - ADDRESS_SPACE - ); - } - return { - configAddress, - token0, - token0Program, - token1, - token1Program, - }; -} - -export async function setupDepositTest( - program: Program, - connection: Connection, - owner: Signer, - config: { - config_index: number; - tradeFeeRate: BN; - protocolFeeRate: BN; - fundFeeRate: BN; - create_fee: BN; - }, - transferFeeConfig: { transferFeeBasisPoints: number; MaxFee: number } = { - transferFeeBasisPoints: 0, - MaxFee: 0, - }, - confirmOptions?: ConfirmOptions, - initAmount: { initAmount0: BN; initAmount1: BN } = { - initAmount0: new BN(10000000000), - initAmount1: new BN(20000000000), - }, - tokenProgramRequired?: { - token0Program: PublicKey; - token1Program: PublicKey; - } -) { - const configAddress = await createAmmConfig( - program, - connection, - owner, - config.config_index, - config.tradeFeeRate, - config.protocolFeeRate, - config.fundFeeRate, - config.create_fee, - confirmOptions - ); - - const [address, _] = deriveCompressionConfigAddress(program.programId); - if (!(await accountExist(connection, address))) { - // Extend connection with zkcompression endpoints - const rpc = createRpc(); - const txId = await initializeCompressionConfig( - rpc, - owner, - program.programId, - program.provider.wallet.payer, - COMPRESSION_DELAY, - program.provider.wallet.payer.publicKey, - ADDRESS_SPACE - ); - console.log("initializeCompressionConfig signature:", txId); - } - - while (1) { - const [{ token0, token0Program }, { token1, token1Program }] = - await createTokenMintAndAssociatedTokenAccount( - connection, - owner, - new Keypair(), - transferFeeConfig - ); - - if (tokenProgramRequired != undefined) { - if ( - token0Program.equals(tokenProgramRequired.token0Program) && - token1Program.equals(tokenProgramRequired.token1Program) - ) { - return await initialize( - program, - owner, - configAddress, - token0, - token0Program, - token1, - token1Program, - confirmOptions, - initAmount - ); - } - } else { - return await initialize( - program, - owner, - configAddress, - token0, - token0Program, - token1, - token1Program, - confirmOptions, - initAmount - ); - } - } -} - -export async function setupSwapTest( - program: Program, - connection: Connection, - owner: Signer, - config: { - config_index: number; - tradeFeeRate: BN; - protocolFeeRate: BN; - fundFeeRate: BN; - create_fee: BN; - }, - transferFeeConfig: { transferFeeBasisPoints: number; MaxFee: number } = { - transferFeeBasisPoints: 0, - MaxFee: 0, - }, - confirmOptions?: ConfirmOptions -) { - const configAddress = await createAmmConfig( - program, - connection, - owner, - config.config_index, - config.tradeFeeRate, - config.protocolFeeRate, - config.fundFeeRate, - config.create_fee, - confirmOptions - ); - - const [address, _] = deriveCompressionConfigAddress(program.programId); - if (!(await accountExist(connection, address))) { - // Extend connection with zkcompression endpoints - const rpc = createRpc(); - await initializeCompressionConfig( - rpc, - owner, - program.programId, - program.provider.wallet.payer, - COMPRESSION_DELAY, - program.provider.wallet.payer.publicKey, - ADDRESS_SPACE - ); - } - - const [{ token0, token0Program }, { token1, token1Program }] = - await createTokenMintAndAssociatedTokenAccount( - connection, - owner, - new Keypair(), - transferFeeConfig - ); - - const { poolAddress, poolState } = await initialize( - program, - owner, - configAddress, - token0, - token0Program, - token1, - token1Program, - confirmOptions - ); - - await deposit( - program, - owner, - poolState.ammConfig, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - new BN(10000000000), - new BN(100000000000), - new BN(100000000000), - confirmOptions - ); - return { - configAddress: poolState.ammConfig, - poolAddress, - poolState, - }; -} - -export async function createAmmConfig( - program: Program, - connection: Connection, - owner: Signer, - config_index: number, - tradeFeeRate: BN, - protocolFeeRate: BN, - fundFeeRate: BN, - create_fee: BN, - confirmOptions?: ConfirmOptions -): Promise { - const [address, _] = await getAmmConfigAddress( - config_index, - program.programId - ); - if (await accountExist(connection, address)) { - return address; - } - - const ix = await program.methods - .createAmmConfig( - config_index, - tradeFeeRate, - protocolFeeRate, - fundFeeRate, - create_fee - ) - .accounts({ - owner: owner.publicKey, - ammConfig: address, - systemProgram: SystemProgram.programId, - }) - .instruction(); - - await sendTransaction(connection, [ix], [owner], confirmOptions); - - return address; -} - -export async function initialize( - program: Program, - creator: Signer, - configAddress: PublicKey, - token0: PublicKey, - token0Program: PublicKey, - token1: PublicKey, - token1Program: PublicKey, - confirmOptions?: ConfirmOptions, - initAmount: { initAmount0: BN; initAmount1: BN } = { - initAmount0: new BN(10000000000), - initAmount1: new BN(20000000000), - }, - createPoolFee = new PublicKey("DNXgeM9EiiaAbaWvwjHj9fQQLAX5ZsfHyvmYUNRAdNC8") -) { - // Extend connection with zkcompression endpoints - const rpc = createRpc(); - - const addressTreeInfo = getDefaultAddressTreeInfo(); - const stateTreeInfo = selectStateTreeInfo(await rpc.getStateTreeInfos()); - - const [auth, authBump] = await getAuthAddress(program.programId); - - const [poolAddress] = await getPoolAddress( - configAddress, - token0, - token1, - program.programId - ); - - // 1. mintSigner - const [lpMintSignerAddress] = getPoolLpMintSignerAddress( - poolAddress, - program.programId - ); - // 2. lpMint - const [lpMintAddress, lpMintBump] = await getPoolLpMintAddress( - lpMintSignerAddress - ); - - // 3. cMint - const lpMintCompressedAddress = getPoolLpMintCompressedAddress( - lpMintSignerAddress, - addressTreeInfo - ); - - const [vault0] = await getPoolVaultAddress( - poolAddress, - token0, - program.programId - ); - const [vault1] = await getPoolVaultAddress( - poolAddress, - token1, - program.programId - ); - - const [observationAddress] = await getOracleAccountAddress( - poolAddress, - program.programId - ); - - const creatorToken0 = getAssociatedTokenAddressSync( - token0, - creator.publicKey, - false, - token0Program - ); - const creatorToken1 = getAssociatedTokenAddressSync( - token1, - creator.publicKey, - false, - token1Program - ); - - // 1. Derive compressed addresses - const poolCompressedAddress = deriveAddressV2( - poolAddress.toBytes(), - addressTreeInfo.tree.toBytes(), - program.programId.toBytes() - ); - - const observationCompressedAddress = deriveAddressV2( - observationAddress.toBytes(), - addressTreeInfo.tree.toBytes(), - program.programId.toBytes() - ); - - // Get validity proof - // Must match the ordering used by the program when invoking the cpi. - const proofRpcResult = await rpc.getValidityProofV0( - [], - [ - { - tree: addressTreeInfo.tree, - queue: addressTreeInfo.queue, - address: bn(poolCompressedAddress), - }, - { - tree: addressTreeInfo.tree, - queue: addressTreeInfo.queue, - address: bn(observationCompressedAddress), - }, - { - tree: addressTreeInfo.tree, - queue: addressTreeInfo.queue, - address: bn(lpMintCompressedAddress), - }, - ] - ); - - // Set up compression-related accounts - const remainingAccounts = createPackedAccountsSmallWithCpiContext( - program.programId, - stateTreeInfo.cpiContext - ); - // adds state tree and address tree - const outputStateTreeIndex = remainingAccounts.insertOrGet( - stateTreeInfo.queue - ); - const packedTreeInfos = packTreeInfos(proofRpcResult, remainingAccounts); - - const [creatorLpToken, creatorLpTokenBump] = - getAssociatedCTokenAddressAndBump(creator.publicKey, lpMintAddress); - - // Create compression-related ix data - // 229 Bytes +1 - const compressionParams = { - // poolstate - poolAddressTreeInfo: packedTreeInfos.addressTrees[0], - // observation - observationAddressTreeInfo: packedTreeInfos.addressTrees[1], - // mint - lpMintAddressTreeInfo: packedTreeInfos.addressTrees[2], - lpMintBump, - // shared - proof: { 0: proofRpcResult.compressedProof }, - outputStateTreeIndex, - creatorLpTokenBump, - }; - // Get compression config PDA - const [compressionConfig] = deriveCompressionConfigAddress(program.programId); - - const packedAccountMetas = remainingAccounts.toAccountMetas(); - - const [lpVault] = await getLpVaultAddress(lpMintAddress, program.programId); - - const initializeIx = await program.methods - .initialize( - initAmount.initAmount0, - initAmount.initAmount1, - new BN(0), - compressionParams - ) - .accountsStrict({ - creator: creator.publicKey, - ammConfig: configAddress, - authority: auth, - poolState: poolAddress, - token0Mint: token0, - token1Mint: token1, - lpMint: lpMintAddress, - creatorToken0, - creatorToken1, - creatorLpToken, - lpVault, - token0Vault: vault0, - token1Vault: vault1, - createPoolFee, - observationState: observationAddress, - tokenProgram: TOKEN_PROGRAM_ID, - token0Program: token0Program, - token1Program: token1Program, - associatedTokenProgram: ASSOCIATED_TOKEN_PROGRAM_ID, - systemProgram: SystemProgram.programId, - rent: SYSVAR_RENT_PUBKEY, - compressionConfig, - rentRecipient: creator.publicKey, - lpMintSigner: lpMintSignerAddress, - compressedTokenProgramCpiAuthority: - CompressedTokenProgram.deriveCpiAuthorityPda, - compressedTokenProgram: CompressedTokenProgram.programId, - compressedToken0PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(token0), - compressedToken1PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(token1), - }) - .remainingAccounts(packedAccountMetas.remainingAccounts) - .instruction(); - - const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_200_000, - }); - const { blockhash } = await program.provider.connection.getLatestBlockhash(); - const { value: lookupTableAccount } = await rpc.getAddressLookupTable( - new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") - ); - - const tx = buildAndSignTx( - [computeBudgetIx, initializeIx], - creator, - blockhash, - [], - [lookupTableAccount] - ); - const txId = await sendAndConfirmTx(rpc, tx, confirmOptions); - console.log("initialize signature:", txId); - - const { account: poolState } = await fetchCompressibleAccount( - poolAddress, - addressTreeInfo, - program, - "poolState", - rpc - ); - - if (!poolState) { - throw new Error("Failed to fetch pool state"); - } - - return { poolAddress, poolState }; -} - -export async function decompressIdempotent( - program: Program, - owner: Signer, - poolAddress: PublicKey, - poolBump: number, - observationAddress: PublicKey, - observationBump: number, - configAddress: PublicKey, - token0: PublicKey, - token1: PublicKey, - rpc: Rpc, - confirmOptions?: ConfirmOptions -): Promise { - const addressTreeInfo = getDefaultAddressTreeInfo(); - - // Fetch pool state - const { account: poolState, merkleContext: poolMerkleContext } = - await fetchCompressibleAccount( - poolAddress, - addressTreeInfo, - program, - "poolState", - rpc - ); - - // Fetch observation state - const { account: observationState, merkleContext: observationMerkleContext } = - await fetchCompressibleAccount( - observationAddress, - addressTreeInfo, - program, - "observationState", - rpc - ); - - if (!poolMerkleContext && !observationMerkleContext) return; - - // Derive compressed addresses - const poolCompressedAddress = deriveAddressV2( - poolAddress.toBytes(), - addressTreeInfo.tree.toBytes(), - program.programId.toBytes() - ); - - const observationCompressedAddress = deriveAddressV2( - observationAddress.toBytes(), - addressTreeInfo.tree.toBytes(), - program.programId.toBytes() - ); - - const proof = await rpc.getValidityProofV0([ - { - hash: poolMerkleContext.hash, - tree: poolMerkleContext.treeInfo.tree, - queue: poolMerkleContext.treeInfo.queue, - }, - { - hash: observationMerkleContext.hash, - tree: observationMerkleContext.treeInfo.tree, - queue: observationMerkleContext.treeInfo.queue, - }, - ]); - - // Prepare remaining accounts - const remainingAccounts = createPackedAccountsSmall(program.programId); - remainingAccounts.addPreAccountsMeta({ - isSigner: false, - isWritable: true, - pubkey: poolAddress, - }); - remainingAccounts.addPreAccountsMeta({ - isSigner: false, - isWritable: true, - pubkey: observationAddress, - }); - const packedTreeInfos = packTreeInfos(proof, remainingAccounts); - - // Prepare compressed accounts data - const compressedAccountsData: { - meta: { - treeInfo: PackedStateTreeInfo; - address: number[]; - outputStateTreeIndex: number; - }; - data: CompressedAccountVariant; - seeds: Buffer[]; - }[] = [ - { - meta: { - treeInfo: packedTreeInfos.stateTrees.packedTreeInfos[0], - address: Array.from(poolCompressedAddress), - outputStateTreeIndex: packedTreeInfos.stateTrees.outputTreeIndex, - }, - data: { poolState: [poolState] }, - seeds: [ - POOL_SEED, - configAddress.toBuffer(), - token0.toBuffer(), - token1.toBuffer(), - ], - }, - { - meta: { - treeInfo: packedTreeInfos.stateTrees.packedTreeInfos[1], - address: Array.from(observationCompressedAddress), - outputStateTreeIndex: packedTreeInfos.stateTrees.outputTreeIndex, - }, - data: { observationState: [observationState] }, - seeds: [ORACLE_SEED, poolAddress.toBuffer()], - }, - ]; - - const decompressIx = await program.methods - .decompressAccountsIdempotent( - { 0: proof.compressedProof }, - compressedAccountsData, - Buffer.from([poolBump, observationBump]), - compressedAccountsData.length - ) - .accountsStrict({ - feePayer: owner.publicKey, - rentPayer: owner.publicKey, - config: deriveCompressionConfigAddress(program.programId)[0], - }) - .remainingAccounts(remainingAccounts.toAccountMetas().remainingAccounts) - .instruction(); - - // Build and send transaction - const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_200_000, - }); - const { blockhash } = await program.provider.connection.getLatestBlockhash(); - const { value: lookupTableAccount } = await rpc.getAddressLookupTable( - new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") - ); - const tx = buildAndSignTx( - [computeBudgetIx, decompressIx], - owner, - blockhash, - [], - [lookupTableAccount] - ); - const decompressTxId = await sendAndConfirmTx(rpc, tx, confirmOptions); - - return decompressTxId; -} - -export async function deposit( - program: Program, - owner: Signer, - configAddress: PublicKey, - token0: PublicKey, - token0Program: PublicKey, - token1: PublicKey, - token1Program: PublicKey, - lp_token_amount: BN, - maximum_token_0_amount: BN, - maximum_token_1_amount: BN, - confirmOptions?: ConfirmOptions -) { - // Extend connection with zkcompression endpoints - const rpc = createRpc(); - const [auth] = await getAuthAddress(program.programId); - const [poolAddress, poolBump] = await getPoolAddress( - configAddress, - token0, - token1, - program.programId - ); - - const [mintSigner] = getPoolLpMintSignerAddress( - poolAddress, - program.programId - ); - const [lpMintAddress] = await getPoolLpMintAddress(mintSigner); - const [lpVaultAddress] = await getLpVaultAddress( - lpMintAddress, - program.programId - ); - - const [vault0] = await getPoolVaultAddress( - poolAddress, - token0, - program.programId - ); - const [vault1] = await getPoolVaultAddress( - poolAddress, - token1, - program.programId - ); - const ownerLpToken = getAssociatedTokenAddressSync( - lpMintAddress, - owner.publicKey, - false, - CompressedTokenProgram.programId, - CompressedTokenProgram.programId - ); - - const ownerToken0 = getAssociatedTokenAddressSync( - token0, - owner.publicKey, - false, - token0Program - ); - const ownerToken1 = getAssociatedTokenAddressSync( - token1, - owner.publicKey, - false, - token1Program - ); - - // Fetch observation address - const [observationAddress, observationBump] = await getOracleAccountAddress( - poolAddress, - program.programId - ); - - // Decompress accounts - await decompressIdempotent( - program, - owner, - poolAddress, - poolBump, - observationAddress, - observationBump, - configAddress, - token0, - token1, - rpc, - confirmOptions - ); - - const depositIx = await program.methods - .deposit(lp_token_amount, maximum_token_0_amount, maximum_token_1_amount) - .accountsStrict({ - owner: owner.publicKey, - authority: auth, - poolState: poolAddress, - ownerLpToken, - token0Account: ownerToken0, - token1Account: ownerToken1, - token0Vault: vault0, - token1Vault: vault1, - tokenProgram: TOKEN_PROGRAM_ID, - tokenProgram2022: TOKEN_2022_PROGRAM_ID, - vault0Mint: token0, - vault1Mint: token1, - lpVault: lpVaultAddress, - compressedTokenProgram: CompressedTokenProgram.programId, - compressedTokenProgramCpiAuthority: - CompressedTokenProgram.deriveCpiAuthorityPda, - compressedToken0PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(token0), - compressedToken1PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(token1), - }) - .instruction(); - - const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_200_000, - }); - const { blockhash } = await program.provider.connection.getLatestBlockhash(); - const { value: lookupTableAccount } = await rpc.getAddressLookupTable( - new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") - ); - const depositTx = buildAndSignTx( - [computeBudgetIx, depositIx], - owner, - blockhash, - [], - [lookupTableAccount] - ); - const depositTxId = await sendAndConfirmTx(rpc, depositTx, confirmOptions); - console.log("deposit signature:", depositTxId); - return depositTxId; -} - -export async function withdraw( - program: Program, - owner: Signer, - configAddress: PublicKey, - token0: PublicKey, - token0Program: PublicKey, - token1: PublicKey, - token1Program: PublicKey, - lp_token_amount: BN, - minimum_token_0_amount: BN, - minimum_token_1_amount: BN, - confirmOptions?: ConfirmOptions -) { - const [auth] = await getAuthAddress(program.programId); - const [poolAddress] = await getPoolAddress( - configAddress, - token0, - token1, - program.programId - ); - - const [lpMintSignerAddress] = getPoolLpMintSignerAddress( - poolAddress, - program.programId - ); - const [lpMintAddress] = await getPoolLpMintAddress(lpMintSignerAddress); - - const [lpVaultAddress] = await getLpVaultAddress( - lpMintAddress, - program.programId - ); - const [vault0] = await getPoolVaultAddress( - poolAddress, - token0, - program.programId - ); - const [vault1] = await getPoolVaultAddress( - poolAddress, - token1, - program.programId - ); - const ownerLpToken = getAssociatedTokenAddressSync( - lpMintAddress, - owner.publicKey, - false, - CompressedTokenProgram.programId, - CompressedTokenProgram.programId - ); - - const ownerToken0 = getAssociatedTokenAddressSync( - token0, - owner.publicKey, - false, - token0Program - ); - const ownerToken1 = getAssociatedTokenAddressSync( - token1, - owner.publicKey, - false, - token1Program - ); - - const withdrawIx = await program.methods - .withdraw(lp_token_amount, minimum_token_0_amount, minimum_token_1_amount) - .accountsStrict({ - owner: owner.publicKey, - authority: auth, - poolState: poolAddress, - ownerLpToken, - token0Account: ownerToken0, - token1Account: ownerToken1, - token0Vault: vault0, - token1Vault: vault1, - tokenProgram: TOKEN_PROGRAM_ID, - tokenProgram2022: TOKEN_2022_PROGRAM_ID, - vault0Mint: token0, - vault1Mint: token1, - lpVault: lpVaultAddress, - compressedTokenProgram: CompressedTokenProgram.programId, - compressedTokenProgramCpiAuthority: - CompressedTokenProgram.deriveCpiAuthorityPda, - compressedToken0PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(token0), - compressedToken1PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(token1), - memoProgram: new PublicKey("MemoSq4gqABAXKb96qnH8TysNcWxMyWCqXgDLGmfcHr"), - }) - .instruction(); - - const computeBudgetIx = ComputeBudgetProgram.setComputeUnitLimit({ - units: 1_200_000, - }); - const rpc = createRpc(); - const { blockhash } = await program.provider.connection.getLatestBlockhash(); - const { value: lookupTableAccount } = await rpc.getAddressLookupTable( - new PublicKey("9NYFyEqPkyXUhkerbGHXUXkvb4qpzeEdHuGpgbgpH1NJ") - ); - const withdrawTx = buildAndSignTx( - [computeBudgetIx, withdrawIx], - owner, - blockhash, - [], - [lookupTableAccount] - ); - const withdrawTxId = await sendAndConfirmTx(rpc, withdrawTx, confirmOptions); - console.log("withdraw signature:", withdrawTxId); - return withdrawTxId; -} - -export async function swap_base_input( - program: Program, - owner: Signer, - configAddress: PublicKey, - inputToken: PublicKey, - inputTokenProgram: PublicKey, - outputToken: PublicKey, - outputTokenProgram: PublicKey, - amount_in: BN, - minimum_amount_out: BN, - confirmOptions?: ConfirmOptions -) { - const [auth] = await getAuthAddress(program.programId); - const [poolAddress] = await getPoolAddress( - configAddress, - inputToken, - outputToken, - program.programId - ); - - const [inputVault] = await getPoolVaultAddress( - poolAddress, - inputToken, - program.programId - ); - const [outputVault] = await getPoolVaultAddress( - poolAddress, - outputToken, - program.programId - ); - - const inputTokenAccount = getAssociatedTokenAddressSync( - inputToken, - owner.publicKey, - false, - inputTokenProgram - ); - const outputTokenAccount = getAssociatedTokenAddressSync( - outputToken, - owner.publicKey, - false, - outputTokenProgram - ); - const [observationAddress] = await getOracleAccountAddress( - poolAddress, - program.programId - ); - const observationState = await program.account.observationState.fetch( - observationAddress - ); - - const ix = await program.methods - .swapBaseInput(amount_in, minimum_amount_out) - .accountsStrict({ - payer: owner.publicKey, - authority: auth, - ammConfig: configAddress, - poolState: poolAddress, - inputTokenAccount, - outputTokenAccount, - inputVault, - outputVault, - inputTokenProgram: inputTokenProgram, - outputTokenProgram: outputTokenProgram, - inputTokenMint: inputToken, - outputTokenMint: outputToken, - observationState: observationAddress, - compressedTokenProgram: CompressedTokenProgram.programId, - compressedTokenProgramCpiAuthority: - CompressedTokenProgram.deriveCpiAuthorityPda, - compressedToken0PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(inputToken), - compressedToken1PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(outputToken), - }) - .instruction(); - const tx = await sendTransaction( - program.provider.connection, - [ix], - [owner], - confirmOptions - ); - console.log("swap signature:", tx); - return tx; -} - -export async function swap_base_output( - program: Program, - owner: Signer, - configAddress: PublicKey, - inputToken: PublicKey, - inputTokenProgram: PublicKey, - outputToken: PublicKey, - outputTokenProgram: PublicKey, - amount_out_less_fee: BN, - max_amount_in: BN, - confirmOptions?: ConfirmOptions -) { - const [auth] = await getAuthAddress(program.programId); - const [poolAddress] = await getPoolAddress( - configAddress, - inputToken, - outputToken, - program.programId - ); - - const [inputVault] = await getPoolVaultAddress( - poolAddress, - inputToken, - program.programId - ); - const [outputVault] = await getPoolVaultAddress( - poolAddress, - outputToken, - program.programId - ); - - const inputTokenAccount = getAssociatedTokenAddressSync( - inputToken, - owner.publicKey, - false, - inputTokenProgram - ); - const outputTokenAccount = getAssociatedTokenAddressSync( - outputToken, - owner.publicKey, - false, - outputTokenProgram - ); - const [observationAddress] = await getOracleAccountAddress( - poolAddress, - program.programId - ); - - const tx = await program.methods - .swapBaseOutput(max_amount_in, amount_out_less_fee) - .accountsStrict({ - payer: owner.publicKey, - authority: auth, - ammConfig: configAddress, - poolState: poolAddress, - inputTokenAccount, - outputTokenAccount, - inputVault, - outputVault, - inputTokenProgram: inputTokenProgram, - outputTokenProgram: outputTokenProgram, - inputTokenMint: inputToken, - outputTokenMint: outputToken, - observationState: observationAddress, - compressedTokenProgram: CompressedTokenProgram.programId, - compressedTokenProgramCpiAuthority: - CompressedTokenProgram.deriveCpiAuthorityPda, - compressedToken0PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(inputToken), - compressedToken1PoolPda: - CompressedTokenProgram.deriveTokenPoolPda(outputToken), - }) - .rpc(confirmOptions); - - console.log("swap signature:", tx); - - return tx; -} diff --git a/tests/utils/pda.ts b/tests/utils/pda.ts deleted file mode 100644 index 849c495..0000000 --- a/tests/utils/pda.ts +++ /dev/null @@ -1,182 +0,0 @@ -import * as anchor from "@coral-xyz/anchor"; -import { PublicKey } from "@solana/web3.js"; -import { TreeInfo } from "@lightprotocol/stateless.js"; -import { - deriveCompressedMintAddress, - findMintAddress, -} from "@lightprotocol/compressed-token"; - -export const AMM_CONFIG_SEED = Buffer.from( - anchor.utils.bytes.utf8.encode("amm_config") -); -export const POOL_SEED = Buffer.from(anchor.utils.bytes.utf8.encode("pool")); -export const POOL_VAULT_SEED = Buffer.from( - anchor.utils.bytes.utf8.encode("pool_vault") -); -export const POOL_AUTH_SEED = Buffer.from( - anchor.utils.bytes.utf8.encode("vault_and_lp_mint_auth_seed") -); -export const POOL_LPMINT_SEED = Buffer.from( - anchor.utils.bytes.utf8.encode("pool_lp_mint") -); -export const TICK_ARRAY_SEED = Buffer.from( - anchor.utils.bytes.utf8.encode("tick_array") -); - -export const OPERATION_SEED = Buffer.from( - anchor.utils.bytes.utf8.encode("operation") -); - -export const ORACLE_SEED = Buffer.from( - anchor.utils.bytes.utf8.encode("observation") -); - -export function u16ToBytes(num: number) { - const arr = new ArrayBuffer(2); - const view = new DataView(arr); - view.setUint16(0, num, false); - return new Uint8Array(arr); -} - -export function i16ToBytes(num: number) { - const arr = new ArrayBuffer(2); - const view = new DataView(arr); - view.setInt16(0, num, false); - return new Uint8Array(arr); -} - -export function u32ToBytes(num: number) { - const arr = new ArrayBuffer(4); - const view = new DataView(arr); - view.setUint32(0, num, false); - return new Uint8Array(arr); -} - -export function i32ToBytes(num: number) { - const arr = new ArrayBuffer(4); - const view = new DataView(arr); - view.setInt32(0, num, false); - return new Uint8Array(arr); -} - -export async function getAmmConfigAddress( - index: number, - programId: PublicKey -): Promise<[PublicKey, number]> { - const [address, bump] = await PublicKey.findProgramAddress( - [AMM_CONFIG_SEED, u16ToBytes(index)], - programId - ); - return [address, bump]; -} - -export async function getAuthAddress( - programId: PublicKey -): Promise<[PublicKey, number]> { - const [address, bump] = await PublicKey.findProgramAddress( - [POOL_AUTH_SEED], - programId - ); - return [address, bump]; -} - -export async function getPoolAddress( - ammConfig: PublicKey, - tokenMint0: PublicKey, - tokenMint1: PublicKey, - programId: PublicKey -): Promise<[PublicKey, number]> { - const [address, bump] = await PublicKey.findProgramAddress( - [ - POOL_SEED, - ammConfig.toBuffer(), - tokenMint0.toBuffer(), - tokenMint1.toBuffer(), - ], - programId - ); - - return [address, bump]; -} - -export function getPoolSignerSeeds( - ammConfig: PublicKey, - tokenMint0: PublicKey, - tokenMint1: PublicKey, - programId: PublicKey -): Buffer[] { - const seeds = [ - POOL_SEED, - ammConfig.toBuffer(), - tokenMint0.toBuffer(), - tokenMint1.toBuffer(), - ]; - const [_, bump] = PublicKey.findProgramAddressSync(seeds, programId); - return Array.from(seeds).concat([Buffer.from([bump])]); -} - -export async function getPoolVaultAddress( - pool: PublicKey, - vaultTokenMint: PublicKey, - programId: PublicKey -): Promise<[PublicKey, number]> { - const [address, bump] = await PublicKey.findProgramAddress( - [POOL_VAULT_SEED, pool.toBuffer(), vaultTokenMint.toBuffer()], - programId - ); - return [address, bump]; -} -export async function getLpVaultAddress( - lpMint: PublicKey, - programId: PublicKey -): Promise<[PublicKey, number]> { - const [address, bump] = await PublicKey.findProgramAddress( - [POOL_VAULT_SEED, lpMint.toBuffer()], - programId - ); - return [address, bump]; -} - -// pda used to derive lp_mint and its compressed address. -export function getPoolLpMintSignerAddress( - pool: PublicKey, - programId: PublicKey -): [PublicKey, number] { - const [address, bump] = PublicKey.findProgramAddressSync( - [POOL_LPMINT_SEED, pool.toBuffer()], - programId - ); - return [address, bump]; -} - -export async function getPoolLpMintAddress( - mintSignerAddress: PublicKey -): Promise<[PublicKey, number]> { - return findMintAddress(mintSignerAddress); -} - -export async function getOracleAccountAddress( - pool: PublicKey, - programId: PublicKey -): Promise<[PublicKey, number]> { - const [address, bump] = await PublicKey.findProgramAddress( - [ORACLE_SEED, pool.toBuffer()], - programId - ); - - return [address, bump]; -} - -/** - * Derives the compressed mint address from the mint seed and address tree. - * @param mintSeed The mint seed public key. - * @param addressTreePubkey The address tree public key. - * @returns Buffer (32 bytes) compressed mint address. - */ - -export function getPoolLpMintCompressedAddress( - mintSigner: PublicKey, - addressTreeInfo: TreeInfo -): number[] { - return deriveCompressedMintAddress(mintSigner, addressTreeInfo); -} diff --git a/tests/utils/util.ts b/tests/utils/util.ts deleted file mode 100644 index 907e454..0000000 --- a/tests/utils/util.ts +++ /dev/null @@ -1,333 +0,0 @@ -import * as anchor from "@coral-xyz/anchor"; -import { web3 } from "@coral-xyz/anchor"; -import { - Connection, - PublicKey, - Keypair, - Signer, - TransactionInstruction, - SystemProgram, - Transaction, - sendAndConfirmTransaction, -} from "@solana/web3.js"; -import { - createMint, - TOKEN_PROGRAM_ID, - getOrCreateAssociatedTokenAccount, - mintTo, - TOKEN_2022_PROGRAM_ID, - getAssociatedTokenAddressSync, - ExtensionType, - getMintLen, - createInitializeTransferFeeConfigInstruction, - createInitializeMintInstruction, - getAccount, -} from "@solana/spl-token"; -import { sendTransaction } from "./index"; -import { - COMPRESSED_TOKEN_PROGRAM_ID, - createRpc, -} from "@lightprotocol/stateless.js"; -import { - CompressedTokenProgram, - createTokenPool, -} from "@lightprotocol/compressed-token"; - -// create a token mint and a token2022 mint with transferFeeConfig -export async function createTokenMintAndAssociatedTokenAccount( - connection: Connection, - payer: Signer, - mintAuthority: Signer, - transferFeeConfig: { transferFeeBasisPoints: number; MaxFee: number } -) { - let ixs: TransactionInstruction[] = []; - ixs.push( - web3.SystemProgram.transfer({ - fromPubkey: payer.publicKey, - toPubkey: mintAuthority.publicKey, - lamports: web3.LAMPORTS_PER_SOL, - }) - ); - await sendTransaction(connection, ixs, [payer]); - - interface Token { - address: PublicKey; - program: PublicKey; - } - - let tokenArray: Token[] = []; - let token0 = await createMint( - connection, - mintAuthority, - mintAuthority.publicKey, - null, - 9 - ); - tokenArray.push({ address: token0, program: TOKEN_PROGRAM_ID }); - - let token1 = await createMint( - connection, - mintAuthority, - mintAuthority.publicKey, - null, - 9, - undefined, - undefined, - TOKEN_2022_PROGRAM_ID - ); - - tokenArray.push({ address: token1, program: TOKEN_2022_PROGRAM_ID }); - - tokenArray.sort(function (x, y) { - const buffer1 = x.address.toBuffer(); - const buffer2 = y.address.toBuffer(); - - for (let i = 0; i < buffer1.length && i < buffer2.length; i++) { - if (buffer1[i] < buffer2[i]) { - return -1; - } - if (buffer1[i] > buffer2[i]) { - return 1; - } - } - - if (buffer1.length < buffer2.length) { - return -1; - } - if (buffer1.length > buffer2.length) { - return 1; - } - - return 0; - }); - - token0 = tokenArray[0].address; - token1 = tokenArray[1].address; - // console.log("Token 0", token0.toString()); - // console.log("Token 1", token1.toString()); - const token0Program = tokenArray[0].program; - const token1Program = tokenArray[1].program; - - const ownerToken0Account = await getOrCreateAssociatedTokenAccount( - connection, - payer, - token0, - payer.publicKey, - false, - "processed", - { skipPreflight: true }, - token0Program - ); - - await mintTo( - connection, - payer, - token0, - ownerToken0Account.address, - mintAuthority, - 100_000_000_000_000, - [], - { skipPreflight: true }, - token0Program - ); - const ownerToken1Account = await getOrCreateAssociatedTokenAccount( - connection, - payer, - token1, - payer.publicKey, - false, - "processed", - { skipPreflight: true }, - token1Program - ); - - await mintTo( - connection, - payer, - token1, - ownerToken1Account.address, - mintAuthority, - 100_000_000_000_000, - [], - { skipPreflight: true }, - token1Program - ); - - // SPL mints have to be registered in the compression protocol. - const rpc = createRpc(); - await createTokenPool( - rpc, - payer, - token0, - { skipPreflight: true }, - token0Program - ); - - await createTokenPool( - rpc, - payer, - token1, - { skipPreflight: true }, - token1Program - ); - - return [ - { token0, token0Program }, - { token1, token1Program }, - ]; -} - -async function createMintWithTransferFee( - connection: Connection, - payer: Signer, - mintAuthority: Signer, - mintKeypair = Keypair.generate(), - transferFeeConfig: { transferFeeBasisPoints: number; MaxFee: number } -) { - const transferFeeConfigAuthority = Keypair.generate(); - const withdrawWithheldAuthority = Keypair.generate(); - - const extensions = [ExtensionType.TransferFeeConfig]; - - const mintLen = getMintLen(extensions); - const decimals = 9; - - const mintLamports = await connection.getMinimumBalanceForRentExemption( - mintLen - ); - const mintTransaction = new Transaction().add( - SystemProgram.createAccount({ - fromPubkey: payer.publicKey, - newAccountPubkey: mintKeypair.publicKey, - space: mintLen, - lamports: mintLamports, - programId: TOKEN_2022_PROGRAM_ID, - }), - createInitializeTransferFeeConfigInstruction( - mintKeypair.publicKey, - transferFeeConfigAuthority.publicKey, - withdrawWithheldAuthority.publicKey, - transferFeeConfig.transferFeeBasisPoints, - BigInt(transferFeeConfig.MaxFee), - TOKEN_2022_PROGRAM_ID - ), - createInitializeMintInstruction( - mintKeypair.publicKey, - decimals, - mintAuthority.publicKey, - null, - TOKEN_2022_PROGRAM_ID - ) - ); - await sendAndConfirmTransaction( - connection, - mintTransaction, - [payer, mintKeypair], - undefined - ); - - return mintKeypair.publicKey; -} - -export async function getUserAndPoolVaultAmount( - owner: PublicKey, - token0Mint: PublicKey, - token0Program: PublicKey, - token1Mint: PublicKey, - token1Program: PublicKey, - poolToken0Vault: PublicKey, - poolToken1Vault: PublicKey -) { - const ownerToken0AccountAddr = getAssociatedTokenAddressSync( - token0Mint, - owner, - false, - token0Program - ); - - const ownerToken1AccountAddr = getAssociatedTokenAddressSync( - token1Mint, - owner, - false, - token1Program - ); - - const ownerToken0Account = await getAccount( - anchor.getProvider().connection, - ownerToken0AccountAddr, - "processed", - token0Program - ); - - const ownerToken1Account = await getAccount( - anchor.getProvider().connection, - ownerToken1AccountAddr, - "processed", - token1Program - ); - - const poolVault0TokenAccount = await getAccount( - anchor.getProvider().connection, - poolToken0Vault, - "processed", - CompressedTokenProgram.programId - ); - - const poolVault1TokenAccount = await getAccount( - anchor.getProvider().connection, - poolToken1Vault, - "processed", - CompressedTokenProgram.programId - ); - - return { - ownerToken0Account, - ownerToken1Account, - poolVault0TokenAccount, - poolVault1TokenAccount, - }; -} - -export async function getUserAndPoolLpAmount( - owner: PublicKey, - lpMint: PublicKey, - lpVault: PublicKey -) { - const userLpTokenAddr = getAssociatedTokenAddressSync( - lpMint, - owner, - undefined, - COMPRESSED_TOKEN_PROGRAM_ID, - COMPRESSED_TOKEN_PROGRAM_ID - ); - - const userLpAccount = await getAccount( - anchor.getProvider().connection, - userLpTokenAddr, - "processed", - COMPRESSED_TOKEN_PROGRAM_ID - ); - - const poolLpVaultAccount = await getAccount( - anchor.getProvider().connection, - lpVault, - "processed", - COMPRESSED_TOKEN_PROGRAM_ID - ); - - return { - userLpAccount, - poolLpVaultAccount, - }; -} - -export function isEqual(amount1: bigint, amount2: bigint) { - if ( - BigInt(amount1) === BigInt(amount2) || - BigInt(amount1) - BigInt(amount2) === BigInt(1) || - BigInt(amount1) - BigInt(amount2) === BigInt(-1) - ) { - return true; - } - return false; -} diff --git a/tests/utils/web3.ts b/tests/utils/web3.ts deleted file mode 100644 index 91f4d5c..0000000 --- a/tests/utils/web3.ts +++ /dev/null @@ -1,102 +0,0 @@ -import * as anchor from "@coral-xyz/anchor"; -import { Program, Idl, IdlAccounts } from "@coral-xyz/anchor"; -import { - Connection, - Signer, - Transaction, - TransactionInstruction, - TransactionSignature, - ConfirmOptions, - PublicKey, -} from "@solana/web3.js"; -import { Rpc, TreeInfo, MerkleContext } from "@lightprotocol/stateless.js"; - -export async function accountExist( - connection: anchor.web3.Connection, - account: anchor.web3.PublicKey -) { - const info = await connection.getAccountInfo(account); - if (info == null || info.data.length == 0) { - return false; - } - return true; -} - -export async function sendTransaction( - connection: Connection, - ixs: TransactionInstruction[], - signers: Array, - options?: ConfirmOptions -): Promise { - const tx = new Transaction(); - for (var i = 0; i < ixs.length; i++) { - tx.add(ixs[i]); - } - - if (options == undefined) { - options = { - preflightCommitment: "confirmed", - commitment: "confirmed", - }; - } - - const sendOpt = options && { - skipPreflight: options.skipPreflight, - preflightCommitment: options.preflightCommitment || options.commitment, - }; - - tx.recentBlockhash = (await connection.getLatestBlockhash()).blockhash; - const signature = await connection.sendTransaction(tx, signers, sendOpt); - - const status = ( - await connection.confirmTransaction(signature, options.commitment) - ).value; - - if (status.err) { - throw new Error( - `Raw transaction ${signature} failed (${JSON.stringify(status)})` - ); - } - return signature; -} - -export async function getBlockTimestamp( - connection: Connection -): Promise { - let slot = await connection.getSlot(); - return await connection.getBlockTime(slot); -} - -// Anchor-only -export async function fetchCompressibleAccount< - TIdl extends Idl, - TAccountName extends keyof IdlAccounts ->( - address: PublicKey, - addressTreeInfo: TreeInfo, - anchorProgram: Program, - accountName: TAccountName, - rpc: Rpc -): Promise<{ - account: IdlAccounts[TAccountName]; - merkleContext?: MerkleContext; -} | null> { - // Fetches account info irrespective of whether it's currently compressed or - // decompressed. - const info = await rpc.getCompressibleAccountInfo( - address, - anchorProgram.programId, - addressTreeInfo, - rpc - ); - - if (info) { - const account = anchorProgram.coder.accounts.decode( - accountName as string, - info.accountInfo.data - ) as IdlAccounts[TAccountName]; - return { account, merkleContext: info.merkleContext }; - } - - return null; -} diff --git a/tests/withdraw.test.ts b/tests/withdraw.test.ts deleted file mode 100644 index c21fd0d..0000000 --- a/tests/withdraw.test.ts +++ /dev/null @@ -1,162 +0,0 @@ -import * as anchor from "@coral-xyz/anchor"; -import { Program, BN } from "@coral-xyz/anchor"; -import { RaydiumCpSwap } from "../target/types/raydium_cp_swap"; -import { - deposit, - getUserAndPoolVaultAmount, - isEqual, - setupDepositTest, - withdraw, -} from "./utils"; -import { assert } from "chai"; - -describe("withdraw test", () => { - anchor.setProvider(anchor.AnchorProvider.env()); - const owner = anchor.Wallet.local().payer; - const program = anchor.workspace.RaydiumCpSwap as Program; - - const confirmOptions = { - skipPreflight: true, - }; - - it("withdraw half of lp ", async () => { - const { poolAddress, poolState } = await setupDepositTest( - program, - anchor.getProvider().connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - { transferFeeBasisPoints: 0, MaxFee: 0 } - ); - const liquidity = new BN(10000000000); - await deposit( - program, - owner, - poolState.ammConfig, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - liquidity, - new BN(10000000000), - new BN(20000000000) - ); - - await withdraw( - program, - owner, - poolState.ammConfig, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - liquidity.divn(2), - new BN(10000000), - new BN(1000000), - confirmOptions - ); - const newPoolState = await program.account.poolState.fetch(poolAddress); - - assert(newPoolState.lpSupply.eq(liquidity.divn(2).add(poolState.lpSupply))); - }); - - it("withdraw all lp ", async () => { - const { poolAddress, poolState } = await setupDepositTest( - program, - anchor.getProvider().connection, - owner, - { - config_index: 0, - tradeFeeRate: new BN(10), - protocolFeeRate: new BN(1000), - fundFeeRate: new BN(25000), - create_fee: new BN(0), - }, - { transferFeeBasisPoints: 0, MaxFee: 0 } - ); - const liquidity = new BN(10000000000); - const { - ownerToken0Account: ownerToken0AccountBefore, - ownerToken1Account: ownerToken1AccountBefore, - poolVault0TokenAccount: poolVault0TokenAccountBefore, - poolVault1TokenAccount: poolVault1TokenAccountBefore, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - poolState.token0Vault, - poolState.token1Vault - ); - - await deposit( - program, - owner, - poolState.ammConfig, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - liquidity, - new BN(10000000000), - new BN(20000000000) - ); - - await withdraw( - program, - owner, - poolState.ammConfig, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - liquidity, - new BN(10000000), - new BN(1000000), - confirmOptions - ); - - const newPoolState = await program.account.poolState.fetch(poolAddress); - assert(newPoolState.lpSupply.eq(poolState.lpSupply)); - - const { - ownerToken0Account: ownerToken0AccountAfter, - ownerToken1Account: ownerToken1AccountAfter, - poolVault0TokenAccount: poolVault0TokenAccountAfter, - poolVault1TokenAccount: poolVault1TokenAccountAfter, - } = await getUserAndPoolVaultAmount( - owner.publicKey, - poolState.token0Mint, - poolState.token0Program, - poolState.token1Mint, - poolState.token1Program, - poolState.token0Vault, - poolState.token1Vault - ); - - assert( - isEqual(ownerToken0AccountBefore.amount, ownerToken0AccountAfter.amount) - ); - assert( - isEqual(ownerToken1AccountBefore.amount, ownerToken1AccountAfter.amount) - ); - assert( - isEqual( - poolVault0TokenAccountBefore.amount, - poolVault0TokenAccountAfter.amount - ) - ); - assert( - isEqual( - poolVault1TokenAccountBefore.amount, - poolVault1TokenAccountAfter.amount - ) - ); - }); -}); From 2e9bb717fc30b23e90a7a1129b227e0391278b16 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= Date: Mon, 19 Jan 2026 15:38:23 +0000 Subject: [PATCH 11/15] Revise README for Rentfree AMM implementation Updated README to reflect the Rentfree AMM example and its features. --- README.md | 30 ++++++++++++++++++++++-------- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index f4a55e9..57c6e1b 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,30 @@ -# raydium-cp-swap +# Rentfree AMM example -An AMM reference implementation based on Raydium's CP AMM. +Fork of Raydium AMM that creates markets without paying rent-exemption. -We added: +- drop-in SDK, minimal code diff +- no extra CU overhead on hot paths +- no UX diff on hot paths -- rent-free +The SDK pays rent-exemption for: +- PoolState +- Token Vaults +- User ATAs +- LP Mint + +Migrating to Rent Free accounts is easy because Light-token is a superset of SPL-token. + +1. add [#light_program] tag + +1. Retrofit your Anchor Accounts + + + + + +# Client -Original readme: -- No Openbook market ID is required for pool creation -- Token22 is supported -- Built-in price oracle ## Environment Setup From da2d04d78b5ab9101f77468d6db4792817a997de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= Date: Mon, 19 Jan 2026 15:38:45 +0000 Subject: [PATCH 12/15] Update README to simplify migration instructions Removed outdated instructions for migrating to Rent Free accounts. --- README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/README.md b/README.md index 57c6e1b..8e1aa02 100644 --- a/README.md +++ b/README.md @@ -14,16 +14,6 @@ The SDK pays rent-exemption for: Migrating to Rent Free accounts is easy because Light-token is a superset of SPL-token. -1. add [#light_program] tag - -1. Retrofit your Anchor Accounts - - - - - -# Client - ## Environment Setup From 7cd989844ef27fe8504263cd4a6af6296f68df2b Mon Sep 17 00:00:00 2001 From: ananas-block <58553958+ananas-block@users.noreply.github.com> Date: Tue, 20 Jan 2026 06:21:38 +0000 Subject: [PATCH 13/15] chore: impl program trait (#20) * update git deps * cleanup * bump deps again * bump git commits --- .gitignore | 4 + Cargo.lock | 350 +++++++++-- Cargo.toml | 1 + programs/cp-swap/Cargo.toml | 19 +- .../instructions/admin/collect_fund_fee.rs | 8 +- .../admin/collect_protocol_fee.rs | 8 +- programs/cp-swap/src/instructions/deposit.rs | 6 +- .../cp-swap/src/instructions/initialize.rs | 6 +- .../src/instructions/swap_base_input.rs | 2 +- programs/cp-swap/src/instructions/withdraw.rs | 2 +- programs/cp-swap/src/lib.rs | 7 +- programs/cp-swap/src/states/oracle.rs | 3 +- programs/cp-swap/src/states/pool.rs | 5 +- programs/cp-swap/src/utils/token.rs | 4 +- programs/cp-swap/tests/functional_test.rs | 72 ++- programs/cp-swap/tests/helpers.rs | 115 +++- programs/cp-swap/tests/program.rs | 567 ++++++++++++++++++ programs/cp-swap/tests/program_test.rs | 223 +++++++ 18 files changed, 1293 insertions(+), 109 deletions(-) create mode 100644 programs/cp-swap/tests/program.rs create mode 100644 programs/cp-swap/tests/program_test.rs diff --git a/.gitignore b/.gitignore index 9d2ca43..508a755 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,7 @@ test-ledger Makefile expand.rs +# For devenv tests, copy from ../light-protocol/cli/accounts +# cp ../light-protocol/cli/accounts target/deploy +# cp ../light-protocol/target/deploy/*.so target/deploy +cli/ diff --git a/Cargo.lock b/Cargo.lock index dc7cad7..bddb2eb 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,6 +12,30 @@ dependencies = [ "regex", ] +[[package]] +name = "account-compression" +version = "2.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +dependencies = [ + "aligned-sized", + "anchor-lang", + "bytemuck", + "light-account-checks", + "light-batched-merkle-tree", + "light-bounded-vec", + "light-compressed-account", + "light-concurrent-merkle-tree", + "light-hash-set", + "light-hasher", + "light-indexed-merkle-tree", + "light-merkle-tree-metadata", + "light-zero-copy", + "num-bigint 0.4.6", + "solana-sdk", + "solana-security-txt", + "zerocopy", +] + [[package]] name = "adler2" version = "2.0.1" @@ -126,7 +150,7 @@ dependencies = [ [[package]] name = "aligned-sized" version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "proc-macro2", "quote", @@ -230,6 +254,28 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "anchor-compressed-token" +version = "2.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +dependencies = [ + "account-compression", + "anchor-lang", + "anchor-spl", + "light-compressed-account", + "light-hasher", + "light-heap", + "light-system-program-anchor", + "light-token-interface", + "light-zero-copy", + "pinocchio-pubkey", + "solana-sdk", + "solana-security-txt", + "spl-token 7.0.0", + "spl-token-2022 7.0.0", + "zerocopy", +] + [[package]] name = "anchor-derive-accounts" version = "0.31.1" @@ -2459,8 +2505,9 @@ dependencies = [ [[package]] name = "light-account-checks" version = "0.6.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ + "pinocchio", "solana-account-info", "solana-msg", "solana-program-error", @@ -2472,7 +2519,7 @@ dependencies = [ [[package]] name = "light-array-map" version = "0.1.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "tinyvec", ] @@ -2480,7 +2527,7 @@ dependencies = [ [[package]] name = "light-batched-merkle-tree" version = "0.7.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -2504,7 +2551,7 @@ dependencies = [ [[package]] name = "light-bloom-filter" version = "0.5.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "bitvec", "num-bigint 0.4.6", @@ -2528,14 +2575,17 @@ dependencies = [ [[package]] name = "light-client" version = "0.17.2" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ + "anchor-lang", "async-trait", "base64 0.13.1", "borsh 0.10.4", "bs58", + "futures", "lazy_static", "light-compressed-account", + "light-compressible", "light-concurrent-merkle-tree", "light-event", "light-hasher", @@ -2549,6 +2599,7 @@ dependencies = [ "num-bigint 0.4.6", "photon-api", "rand 0.8.5", + "smallvec", "solana-account", "solana-account-decoder-client-types", "solana-address-lookup-table-interface", @@ -2568,6 +2619,8 @@ dependencies = [ "solana-transaction", "solana-transaction-error", "solana-transaction-status-client-types", + "spl-pod", + "spl-token-2022-interface", "thiserror 2.0.18", "tokio", "tracing", @@ -2576,7 +2629,7 @@ dependencies = [ [[package]] name = "light-compressed-account" version = "0.7.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -2586,6 +2639,7 @@ dependencies = [ "light-poseidon 0.3.0", "light-program-profiler", "light-zero-copy", + "pinocchio", "solana-msg", "solana-program-error", "solana-pubkey", @@ -2595,59 +2649,69 @@ dependencies = [ ] [[package]] -name = "light-compressible" -version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +name = "light-compressed-token" +version = "2.1.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ - "aligned-sized", + "account-compression", + "anchor-compressed-token", "anchor-lang", + "arrayvec", + "bitvec", "borsh 0.10.4", - "bytemuck", "light-account-checks", + "light-array-map", "light-compressed-account", + "light-compressible", "light-hasher", - "light-macros", + "light-heap", "light-program-profiler", + "light-sdk", + "light-sdk-pinocchio", "light-sdk-types", + "light-system-program-anchor", + "light-token-interface", "light-zero-copy", + "pinocchio", "pinocchio-pubkey", - "solana-msg", - "solana-program-error", + "pinocchio-system", + "pinocchio-token-program", "solana-pubkey", - "solana-sysvar", - "thiserror 2.0.18", + "solana-security-txt", + "spl-pod", + "spl-token 7.0.0", + "spl-token-2022 7.0.0", + "tinyvec", "zerocopy", ] [[package]] -name = "light-compressible-client" -version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +name = "light-compressible" +version = "0.2.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ + "aligned-sized", "anchor-lang", - "async-trait", "borsh 0.10.4", - "futures", - "light-client", + "bytemuck", + "light-account-checks", "light-compressed-account", - "light-compressible", - "light-sdk", - "light-token-interface", - "light-token-sdk", - "smallvec", - "solana-account", - "solana-instruction", - "solana-program", - "solana-program-error", + "light-hasher", + "light-macros", + "light-program-profiler", + "light-sdk-types", + "light-zero-copy", + "pinocchio", + "pinocchio-pubkey", "solana-pubkey", - "spl-token-2022 7.0.0", "thiserror 2.0.18", + "zerocopy", ] [[package]] name = "light-concurrent-merkle-tree" version = "5.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "borsh 0.10.4", "light-bounded-vec", @@ -2660,7 +2724,7 @@ dependencies = [ [[package]] name = "light-event" version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "borsh 0.10.4", "light-compressed-account", @@ -2669,10 +2733,22 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "light-hash-set" +version = "4.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +dependencies = [ + "light-hasher", + "num-bigint 0.4.6", + "num-traits", + "solana-program-error", + "thiserror 2.0.18", +] + [[package]] name = "light-hasher" version = "5.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", @@ -2686,10 +2762,18 @@ dependencies = [ "tinyvec", ] +[[package]] +name = "light-heap" +version = "2.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +dependencies = [ + "anchor-lang", +] + [[package]] name = "light-indexed-array" version = "0.3.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "light-hasher", "num-bigint 0.4.6", @@ -2700,7 +2784,7 @@ dependencies = [ [[package]] name = "light-indexed-merkle-tree" version = "5.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "light-bounded-vec", "light-concurrent-merkle-tree", @@ -2715,7 +2799,7 @@ dependencies = [ [[package]] name = "light-macros" version = "2.2.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "bs58", "proc-macro2", @@ -2727,7 +2811,7 @@ dependencies = [ [[package]] name = "light-merkle-tree-metadata" version = "0.7.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -2743,7 +2827,7 @@ dependencies = [ [[package]] name = "light-merkle-tree-reference" version = "4.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "light-hasher", "light-indexed-array", @@ -2799,8 +2883,9 @@ dependencies = [ [[package]] name = "light-program-test" version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ + "account-compression", "anchor-lang", "async-trait", "base64 0.13.1", @@ -2808,9 +2893,12 @@ dependencies = [ "bs58", "bytemuck", "chrono", + "light-batched-merkle-tree", "light-client", "light-compressed-account", - "light-compressible-client", + "light-compressed-token", + "light-compressible", + "light-concurrent-merkle-tree", "light-event", "light-hasher", "light-indexed-array", @@ -2818,6 +2906,7 @@ dependencies = [ "light-merkle-tree-metadata", "light-merkle-tree-reference", "light-prover-client", + "light-registry", "light-sdk", "light-sdk-types", "light-token-interface", @@ -2850,7 +2939,7 @@ dependencies = [ [[package]] name = "light-prover-client" version = "5.0.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "ark-bn254 0.5.0", "ark-serialize 0.5.0", @@ -2870,10 +2959,36 @@ dependencies = [ "tracing", ] +[[package]] +name = "light-registry" +version = "2.1.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +dependencies = [ + "account-compression", + "aligned-sized", + "anchor-lang", + "borsh 0.10.4", + "light-account-checks", + "light-batched-merkle-tree", + "light-compressible", + "light-macros", + "light-merkle-tree-metadata", + "light-program-profiler", + "light-system-program-anchor", + "light-token-interface", + "light-zero-copy", + "solana-account-info", + "solana-instruction", + "solana-pubkey", + "solana-sdk", + "solana-security-txt", + "spl-pod", +] + [[package]] name = "light-sdk" version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "anchor-lang", "bincode", @@ -2903,7 +3018,7 @@ dependencies = [ [[package]] name = "light-sdk-macros" version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "darling", "light-hasher", @@ -2914,10 +3029,26 @@ dependencies = [ "syn 2.0.114", ] +[[package]] +name = "light-sdk-pinocchio" +version = "0.17.1" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +dependencies = [ + "borsh 0.10.4", + "light-account-checks", + "light-compressed-account", + "light-hasher", + "light-macros", + "light-sdk-macros", + "light-sdk-types", + "pinocchio", + "thiserror 2.0.18", +] + [[package]] name = "light-sdk-types" version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -2932,7 +3063,7 @@ dependencies = [ [[package]] name = "light-sparse-merkle-tree" version = "0.3.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "light-hasher", "light-indexed-array", @@ -2941,10 +3072,23 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "light-system-program-anchor" +version = "2.0.0" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +dependencies = [ + "account-compression", + "aligned-sized", + "anchor-lang", + "light-compressed-account", + "light-zero-copy", + "zerocopy", +] + [[package]] name = "light-token-interface" version = "0.1.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "aligned-sized", "anchor-lang", @@ -2971,9 +3115,10 @@ dependencies = [ [[package]] name = "light-token-sdk" version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "anchor-lang", + "anchor-spl", "arrayvec", "borsh 0.10.4", "light-account-checks", @@ -2983,6 +3128,7 @@ dependencies = [ "light-macros", "light-program-profiler", "light-sdk", + "light-sdk-macros", "light-sdk-types", "light-token-interface", "light-token-types", @@ -3000,7 +3146,7 @@ dependencies = [ [[package]] name = "light-token-types" version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "anchor-lang", "borsh 0.10.4", @@ -3015,7 +3161,7 @@ dependencies = [ [[package]] name = "light-verifier" version = "6.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "groth16-solana", "light-compressed-account", @@ -3025,7 +3171,7 @@ dependencies = [ [[package]] name = "light-zero-copy" version = "0.5.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "light-zero-copy-derive", "solana-program-error", @@ -3035,7 +3181,7 @@ dependencies = [ [[package]] name = "light-zero-copy-derive" version = "0.5.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "lazy_static", "proc-macro2", @@ -3513,7 +3659,7 @@ dependencies = [ [[package]] name = "photon-api" version = "0.53.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=c08e515e11705e9d29879e3eb95ea4a631133121#c08e515e11705e9d29879e3eb95ea4a631133121" +source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" dependencies = [ "reqwest 0.12.28", "serde", @@ -3562,6 +3708,12 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b971851087bc3699b001954ad02389d50c41405ece3548cbcafc88b3e20017a" +[[package]] +name = "pinocchio-log" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd11022408f312e6179ece321c1f7dc0d1b2aa7765fddd39b2a7378d65a899e8" + [[package]] name = "pinocchio-pubkey" version = "0.3.0" @@ -3573,6 +3725,35 @@ dependencies = [ "sha2-const-stable", ] +[[package]] +name = "pinocchio-system" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "141ed5eafb4ab04568bb0e224e3dc9a9de13c933de4c004e0d1a553498be3a7c" +dependencies = [ + "pinocchio", + "pinocchio-pubkey", +] + +[[package]] +name = "pinocchio-token-interface" +version = "0.0.0" +source = "git+https://github.com/Lightprotocol/token?rev=9ea04560a039d1a44f0411b5eaa7c0b79ed575ab#9ea04560a039d1a44f0411b5eaa7c0b79ed575ab" +dependencies = [ + "pinocchio", + "pinocchio-pubkey", +] + +[[package]] +name = "pinocchio-token-program" +version = "0.1.0" +source = "git+https://github.com/Lightprotocol/token?rev=9ea04560a039d1a44f0411b5eaa7c0b79ed575ab#9ea04560a039d1a44f0411b5eaa7c0b79ed575ab" +dependencies = [ + "pinocchio", + "pinocchio-log", + "pinocchio-token-interface", +] + [[package]] name = "pkg-config" version = "0.3.32" @@ -3916,18 +4097,13 @@ name = "raydium-cp-swap" version = "0.2.0" dependencies = [ "anchor-lang", - "anchor-spl", "arrayref", + "bincode", + "blake3", "bytemuck", "light-client", - "light-compressed-account", - "light-compressible", - "light-compressible-client", - "light-hasher", "light-program-test", "light-sdk", - "light-sdk-macros", - "light-sdk-types", "light-token-sdk", "proptest", "quickcheck", @@ -7258,6 +7434,36 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "spl-token-2022-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62d7ae2ee6b856f8ddcbdc3b3a9f4d2141582bbe150f93e5298ee97e0251fa04" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction 0.4.1", + "spl-token-confidential-transfer-proof-generation 0.4.1", + "spl-token-group-interface 0.6.0", + "spl-token-metadata-interface 0.7.0", + "spl-type-length-value 0.8.0", + "thiserror 2.0.18", +] + [[package]] name = "spl-token-confidential-transfer-ciphertext-arithmetic" version = "0.2.1" @@ -7316,6 +7522,26 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "512c85bdbbb4cbcc2038849a9e164c958b16541f252b53ea1a3933191c0a4a1a" +dependencies = [ + "bytemuck", + "solana-account-info", + "solana-curve25519", + "solana-instruction", + "solana-instructions-sysvar", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "solana-sdk-ids", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.18", +] + [[package]] name = "spl-token-confidential-transfer-proof-generation" version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index 172ad47..1a290f6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = ["programs/*"] [workspace.dependencies] proc-macro2 = "1.0.95" +blake3 = "=1.8.2" [profile.release] overflow-checks = true diff --git a/programs/cp-swap/Cargo.toml b/programs/cp-swap/Cargo.toml index 2c8dfb7..7db8b93 100644 --- a/programs/cp-swap/Cargo.toml +++ b/programs/cp-swap/Cargo.toml @@ -19,26 +19,21 @@ enable-log = [] devnet = [] client = [] anchor-debug = [] -idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"] +idl-build = ["anchor-lang/idl-build", "light-sdk/idl-build", "light-token-sdk/idl-build"] test-sbf = [] [dependencies] anchor-lang = { version = "=0.31.1", features = ["init-if-needed", "idl-build"] } -anchor-spl = { version = "=0.31.1", git = "https://github.com/lightprotocol/anchor", rev = "da005d7f", features = ["memo", "idl-build"] } spl-token-2022 = { version = "7.0.0", features = ["no-entrypoint"] } spl-math = { version = "0.3", features = ["no-entrypoint"] } uint = "0.10.0" solana-security-txt = "1.1.1" bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] } arrayref = { version = "0.3.6" } +blake3 = { workspace = true } -light-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor", "anchor-discriminator", "v2", "idl-build", "cpi-context"] } -light-hasher = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121" } -light-sdk-types = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["v2", "cpi-context"] } -light-sdk-macros = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor-discriminator"] } -light-compressible = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor"] } -light-token-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor", "compressible"] } -light-compressed-account = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121" } +light-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["anchor", "anchor-discriminator", "v2", "idl-build", "cpi-context"] } +light-token-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["anchor", "idl-build", "anchor-spl-memo", "anchor-spl-associated-token"] } solana-account-info = "2.3" solana-program = "2.2" solana-pubkey = "2.2" @@ -51,15 +46,15 @@ quickcheck = "1.0.3" proptest = "1.0" rand = "0.9.0" -light-program-test = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["v2"] } -light-client = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["v2"] } -light-compressible-client = { git = "https://github.com/Lightprotocol/light-protocol", rev = "c08e515e11705e9d29879e3eb95ea4a631133121", features = ["anchor"] } +light-program-test = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["v2", "devenv"] } +light-client = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["v2"] } tokio = { version = "1", features = ["full"] } spl-token = "7.0.0" solana-keypair = { version = "2.2" } solana-signer = { version = "2.2" } solana-instruction = { version = "2.2" } solana-sdk = { version = "2.3" } +bincode = "1.3" [profile.release] diff --git a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs index 15211e4..390b697 100644 --- a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs @@ -2,10 +2,10 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; -use anchor_spl::token::Token; -use anchor_spl::token_interface::Mint; -use anchor_spl::token_interface::Token2022; -use anchor_spl::token_interface::TokenAccount; +use light_token_sdk::anchor::anchor_spl::token::Token; +use light_token_sdk::anchor::anchor_spl::token_interface::Mint; +use light_token_sdk::anchor::anchor_spl::token_interface::Token2022; +use light_token_sdk::anchor::anchor_spl::token_interface::TokenAccount; #[derive(Accounts)] pub struct CollectFundFee<'info> { /// Only admin or fund_owner can collect fee now diff --git a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs index 9be9be6..8e88178 100644 --- a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs @@ -2,10 +2,10 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::*; use anchor_lang::prelude::*; -use anchor_spl::token::Token; -use anchor_spl::token_interface::Mint; -use anchor_spl::token_interface::Token2022; -use anchor_spl::token_interface::TokenAccount; +use light_token_sdk::anchor::anchor_spl::token::Token; +use light_token_sdk::anchor::anchor_spl::token_interface::Mint; +use light_token_sdk::anchor::anchor_spl::token_interface::Token2022; +use light_token_sdk::anchor::anchor_spl::token_interface::TokenAccount; #[derive(Accounts)] pub struct CollectProtocolFee<'info> { diff --git a/programs/cp-swap/src/instructions/deposit.rs b/programs/cp-swap/src/instructions/deposit.rs index 4a6ca75..a23e2a2 100644 --- a/programs/cp-swap/src/instructions/deposit.rs +++ b/programs/cp-swap/src/instructions/deposit.rs @@ -4,10 +4,10 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; -use anchor_spl::token::Token; -use anchor_spl::token_interface::Token2022; +use light_token_sdk::anchor::anchor_spl::token::Token; +use light_token_sdk::anchor::anchor_spl::token_interface::Token2022; use light_token_sdk::token::MintToCpi; -use anchor_spl::token_interface::{TokenAccount, Mint,TokenInterface}; +use light_token_sdk::anchor::anchor_spl::token_interface::{TokenAccount, Mint,TokenInterface}; #[derive(Accounts)] pub struct Deposit<'info> { diff --git a/programs/cp-swap/src/instructions/initialize.rs b/programs/cp-swap/src/instructions/initialize.rs index 9dad480..d042798 100644 --- a/programs/cp-swap/src/instructions/initialize.rs +++ b/programs/cp-swap/src/instructions/initialize.rs @@ -7,14 +7,14 @@ use anchor_lang::{ prelude::*, solana_program::{clock, program::invoke, system_instruction}, }; -use anchor_spl::{ +use light_token_sdk::anchor::anchor_spl::{ associated_token::AssociatedToken, token::spl_token, token::Token, token_interface::{Mint, TokenAccount, TokenInterface}, }; -use light_compressible::CreateAccountsProof; -use light_sdk_macros::LightAccounts; +use light_sdk::interface::CreateAccountsProof; +use light_token_sdk::anchor::LightAccounts; use light_token_sdk::{ token::{ CreateTokenAccountCpi, CreateTokenAtaCpi, MintToCpi, COMPRESSIBLE_CONFIG_V1, diff --git a/programs/cp-swap/src/instructions/swap_base_input.rs b/programs/cp-swap/src/instructions/swap_base_input.rs index bdcfbb3..a45ffde 100644 --- a/programs/cp-swap/src/instructions/swap_base_input.rs +++ b/programs/cp-swap/src/instructions/swap_base_input.rs @@ -5,7 +5,7 @@ use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_lang::solana_program; -use anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; +use light_token_sdk::anchor::anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; #[derive(Accounts)] pub struct Swap<'info> { diff --git a/programs/cp-swap/src/instructions/withdraw.rs b/programs/cp-swap/src/instructions/withdraw.rs index e7a7be1..4fc0733 100644 --- a/programs/cp-swap/src/instructions/withdraw.rs +++ b/programs/cp-swap/src/instructions/withdraw.rs @@ -4,7 +4,7 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; -use anchor_spl::{ +use light_token_sdk::anchor::anchor_spl::{ memo::spl_memo, token::Token, token_interface::{Mint, Token2022, TokenAccount, TokenInterface}, diff --git a/programs/cp-swap/src/lib.rs b/programs/cp-swap/src/lib.rs index 3bebad2..6636db2 100644 --- a/programs/cp-swap/src/lib.rs +++ b/programs/cp-swap/src/lib.rs @@ -14,10 +14,9 @@ pub use crate::states::{ }; use anchor_lang::prelude::*; use instructions::*; -use light_sdk::{derive_light_cpi_signer, derive_light_rent_sponsor_pda}; -use light_sdk::light_hasher::*; -use light_sdk_macros::light_program; -use light_sdk_types::CpiSigner; +use light_token_sdk::anchor::{ + derive_light_cpi_signer, derive_light_rent_sponsor_pda, light_program, CpiSigner, +}; #[cfg(not(feature = "no-entrypoint"))] solana_security_txt::security_txt! { diff --git a/programs/cp-swap/src/states/oracle.rs b/programs/cp-swap/src/states/oracle.rs index bef2f8c..1d714f0 100644 --- a/programs/cp-swap/src/states/oracle.rs +++ b/programs/cp-swap/src/states/oracle.rs @@ -1,7 +1,6 @@ use anchor_lang::prelude::*; -use light_sdk::compressible::CompressionInfo; use light_sdk::LightDiscriminator; -use light_sdk_macros::LightAccount; +use light_token_sdk::anchor::{CompressionInfo, LightAccount}; #[cfg(test)] use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/programs/cp-swap/src/states/pool.rs b/programs/cp-swap/src/states/pool.rs index dce62ae..200be7d 100644 --- a/programs/cp-swap/src/states/pool.rs +++ b/programs/cp-swap/src/states/pool.rs @@ -1,8 +1,7 @@ use anchor_lang::prelude::*; -use anchor_spl::token_interface::Mint; -use light_sdk::compressible::CompressionInfo; +use light_token_sdk::anchor::anchor_spl::token_interface::Mint; use light_sdk::LightDiscriminator; -use light_sdk_macros::LightAccount; +use light_token_sdk::anchor::{CompressionInfo, LightAccount}; use std::ops::{BitAnd, BitOr, BitXor}; pub const POOL_SEED: &str = "pool"; diff --git a/programs/cp-swap/src/utils/token.rs b/programs/cp-swap/src/utils/token.rs index 2f9076b..d5fdbb3 100644 --- a/programs/cp-swap/src/utils/token.rs +++ b/programs/cp-swap/src/utils/token.rs @@ -1,11 +1,11 @@ use crate::error::ErrorCode; use anchor_lang::{prelude::*, system_program}; -use anchor_spl::{ +use light_token_sdk::anchor::anchor_spl::{ token::{Token, TokenAccount}, token_2022, token_interface::{initialize_account3, InitializeAccount3, Mint}, }; -use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID; +use light_sdk::constants::LIGHT_TOKEN_PROGRAM_ID; use light_token_sdk::token::TransferInterfaceCpi; use spl_token_2022::{ self, diff --git a/programs/cp-swap/tests/functional_test.rs b/programs/cp-swap/tests/functional_test.rs index 150bffa..9b6218c 100644 --- a/programs/cp-swap/tests/functional_test.rs +++ b/programs/cp-swap/tests/functional_test.rs @@ -1,12 +1,14 @@ /// Functional integration test for cp-swap program. /// Tests pool initialization with light-program-test framework. +use light_client::interface::AccountInterfaceExt; +use light_program_test::program_test::TestRpc; +use light_program_test::Rpc; use solana_keypair::Keypair; use solana_signer::Signer; -use light_program_test::Rpc; -use light_program_test::program_test::TestRpc; mod helpers; +mod program; use helpers::*; #[tokio::test] @@ -215,3 +217,69 @@ async fn test_full_lifecycle() { println!("Full lifecycle test completed successfully!"); } + +/// Test SDK initialization from fetched accounts and account requirements. +#[tokio::test] +async fn test_sdk_from_keyed_accounts() { + use program::{CpSwapSdk, CpSwapInstruction}; + use light_client::interface::LightProgramInterface; + + let program_id = raydium_cp_swap::ID; + + // Setup environment and initialize pool + let mut setup = setup_pool_environment(program_id, 2).await; + + // Initialize pool first (SDK requires actual account data) + let proof_result = get_pool_create_accounts_proof(&setup.env.rpc, &program_id, &setup.pdas).await; + let init_ix = build_initialize_instruction( + program_id, + setup.creator.pubkey(), + setup.amm_config, + &setup.pdas, + &setup.tokens, + setup.env.config_pda, + &proof_result, + 100_000, + 100_000, + 0, + ); + setup.env.rpc + .create_and_send_transaction(&[init_ix], &setup.creator.pubkey(), &[&setup.creator]) + .await + .expect("Initialize should succeed"); + + // Fetch pool state account + let pool_interface = setup.env.rpc + .get_account_interface(&setup.pdas.pool_state, &program_id) + .await + .expect("get_account_interface should succeed"); + + // Create SDK from fetched account + let sdk = CpSwapSdk::from_keyed_accounts(&[pool_interface]) + .expect("from_keyed_accounts should succeed"); + + // Verify SDK parsed addresses match expected + assert_eq!(sdk.pool_state_pubkey, Some(setup.pdas.pool_state)); + assert_eq!(sdk.observation_key, Some(setup.pdas.observation_state)); + assert_eq!(sdk.token_0_vault, Some(setup.pdas.token_0_vault)); + assert_eq!(sdk.token_1_vault, Some(setup.pdas.token_1_vault)); + assert_eq!(sdk.lp_mint, Some(setup.pdas.lp_mint)); + assert_eq!(sdk.amm_config, Some(setup.amm_config)); + assert_eq!(sdk.token_0_mint, Some(setup.tokens.token_0_mint)); + assert_eq!(sdk.token_1_mint, Some(setup.tokens.token_1_mint)); + + // Check account requirements for each instruction type + let swap_accounts = sdk.get_accounts_to_update(&CpSwapInstruction::Swap); + assert_eq!(swap_accounts.len(), 6, "Swap needs 6 accounts: pool, observation, vault0, vault1, mint0, mint1"); + + let deposit_accounts = sdk.get_accounts_to_update(&CpSwapInstruction::Deposit); + assert_eq!(deposit_accounts.len(), 7, "Deposit needs 7 accounts: pool, observation, vault0, vault1, lp_mint, mint0, mint1"); + + let withdraw_accounts = sdk.get_accounts_to_update(&CpSwapInstruction::Withdraw); + assert_eq!(withdraw_accounts.len(), 7, "Withdraw needs 7 accounts: pool, observation, vault0, vault1, lp_mint, mint0, mint1"); + + // Verify program_id method + assert_eq!(sdk.program_id(), program_id); + + println!("SDK initialization test completed successfully!"); +} diff --git a/programs/cp-swap/tests/helpers.rs b/programs/cp-swap/tests/helpers.rs index 60b651b..3336708 100644 --- a/programs/cp-swap/tests/helpers.rs +++ b/programs/cp-swap/tests/helpers.rs @@ -1,8 +1,10 @@ +#![allow(dead_code)] + /// Functional integration test for cp-swap program. /// Tests pool initialization with light-program-test framework. use anchor_lang::{InstructionData, ToAccountMetas}; -use light_compressible_client::{ +use light_client::interface::{ get_create_accounts_proof, CreateAccountsProofInput, CreateAccountsProofResult, InitializeRentFreeConfig, }; @@ -11,7 +13,6 @@ use light_program_test::{ program_test::{setup_mock_program_data, LightProgramTest, TestRpc}, Indexer, ProgramTestConfig, Rpc, }; -use light_sdk_types::LIGHT_TOKEN_PROGRAM_ID; use light_token_sdk::{ constants::CPI_AUTHORITY_PDA, token::{ @@ -19,6 +20,7 @@ use light_token_sdk::{ CreateMint, CreateMintParams, MintTo, COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR as LIGHT_TOKEN_RENT_SPONSOR, }, + constants::LIGHT_TOKEN_PROGRAM_ID, }; use raydium_cp_swap::{ instructions::initialize::LP_MINT_SIGNER_SEED, @@ -30,7 +32,7 @@ use solana_keypair::Keypair; use solana_pubkey::Pubkey; use solana_signer::Signer; use solana_sdk::{program_pack::Pack, signature::SeedDerivable}; -use anchor_spl::memo::spl_memo; +use light_token_sdk::anchor::anchor_spl::memo::spl_memo; use spl_token_2022; @@ -74,6 +76,8 @@ pub struct TestEnv { pub struct TokenSetup { pub token_0_mint: Pubkey, pub token_1_mint: Pubkey, + pub token_0_mint_signer: Pubkey, + pub token_1_mint_signer: Pubkey, pub creator_token_0: Pubkey, pub creator_token_1: Pubkey, } @@ -218,7 +222,7 @@ pub async fn setup_token_mints( creator: &Pubkey, initial_balance: u64, ) -> TokenSetup { - let (mint_a, ata_pubkeys_a, _) = setup_create_mint( + let (mint_a, ata_pubkeys_a, mint_seed_a) = setup_create_mint( rpc, payer, payer.pubkey(), @@ -227,7 +231,7 @@ pub async fn setup_token_mints( ) .await; - let (mint_b, ata_pubkeys_b, _) = setup_create_mint( + let (mint_b, ata_pubkeys_b, mint_seed_b) = setup_create_mint( rpc, payer, payer.pubkey(), @@ -241,6 +245,8 @@ pub async fn setup_token_mints( TokenSetup { token_0_mint: mint_a, token_1_mint: mint_b, + token_0_mint_signer: mint_seed_a.pubkey(), + token_1_mint_signer: mint_seed_b.pubkey(), creator_token_0: ata_pubkeys_a[0], creator_token_1: ata_pubkeys_b[0], } @@ -248,6 +254,8 @@ pub async fn setup_token_mints( TokenSetup { token_0_mint: mint_b, token_1_mint: mint_a, + token_0_mint_signer: mint_seed_b.pubkey(), + token_1_mint_signer: mint_seed_a.pubkey(), creator_token_0: ata_pubkeys_b[0], creator_token_1: ata_pubkeys_a[0], } @@ -620,7 +628,7 @@ pub fn build_initialize_instruction( token_program: spl_token::id(), token_0_program: light_token_program_id(), token_1_program: light_token_program_id(), - associated_token_program: anchor_spl::associated_token::ID, + associated_token_program: light_token_sdk::anchor::anchor_spl::associated_token::ID, system_program: solana_sdk::system_program::ID, rent: solana_sdk::sysvar::rent::ID, compression_config: config_pda, @@ -668,6 +676,49 @@ pub async fn get_token_balance(rpc: &mut LightProgramTest, account: Pubkey) -> u } } +/// Assert that an account exists on-chain. +pub async fn assert_onchain_exists(rpc: &mut LightProgramTest, pda: &Pubkey) { + assert!( + rpc.get_account(*pda).await.unwrap().is_some(), + "Account {} should exist on-chain", + pda + ); +} + +/// Assert that an account is closed (doesn't exist or has 0 lamports). +pub async fn assert_onchain_closed(rpc: &mut LightProgramTest, pda: &Pubkey) { + let acc = rpc.get_account(*pda).await.unwrap(); + assert!( + acc.is_none() || acc.unwrap().lamports == 0, + "Account {} should be closed", + pda + ); +} + +/// Assert all pool accounts exist on-chain (hot or decompressed state). +pub async fn assert_pool_accounts_exist(rpc: &mut LightProgramTest, pdas: &AmmPdas, tokens: &TokenSetup) { + assert_onchain_exists(rpc, &pdas.pool_state).await; + assert_onchain_exists(rpc, &pdas.observation_state).await; + assert_onchain_exists(rpc, &pdas.lp_mint).await; + assert_onchain_exists(rpc, &pdas.token_0_vault).await; + assert_onchain_exists(rpc, &pdas.token_1_vault).await; + assert_onchain_exists(rpc, &pdas.creator_lp_token).await; + assert_onchain_exists(rpc, &tokens.token_0_mint).await; + assert_onchain_exists(rpc, &tokens.token_1_mint).await; +} + +/// Assert all pool accounts are compressed (closed on-chain). +pub async fn assert_pool_accounts_compressed(rpc: &mut LightProgramTest, pdas: &AmmPdas, tokens: &TokenSetup) { + assert_onchain_closed(rpc, &pdas.pool_state).await; + assert_onchain_closed(rpc, &pdas.observation_state).await; + assert_onchain_closed(rpc, &pdas.lp_mint).await; + assert_onchain_closed(rpc, &pdas.token_0_vault).await; + assert_onchain_closed(rpc, &pdas.token_1_vault).await; + assert_onchain_closed(rpc, &pdas.creator_lp_token).await; + assert_onchain_closed(rpc, &tokens.token_0_mint).await; + assert_onchain_closed(rpc, &tokens.token_1_mint).await; +} + /// Verify that the pool was initialized correctly. pub async fn assert_pool_initialized(rpc: &mut LightProgramTest, pdas: &AmmPdas) { let pool_account = rpc.get_account(pdas.pool_state).await.unwrap(); @@ -752,3 +803,55 @@ pub async fn assert_amm_config_created(rpc: &mut LightProgramTest, amm_config: P let account = rpc.get_account(amm_config).await.unwrap(); assert!(account.is_some(), "AmmConfig account should exist"); } + +// ============================================================================ +// Unified Setup Functions for SDK-based Tests +// ============================================================================ + +/// Complete pool setup result containing all necessary state. +pub struct PoolSetup { + pub env: TestEnv, + pub creator: Keypair, + pub tokens: TokenSetup, + pub amm_config: Pubkey, + pub pdas: AmmPdas, +} + +/// Setup a complete pool environment in a single call. +pub async fn setup_pool_environment(program_id: Pubkey, amm_config_index: u16) -> PoolSetup { + let mut env = setup_test_environment(program_id).await; + + let creator = Keypair::new(); + env.rpc + .airdrop_lamports(&creator.pubkey(), 100_000_000_000) + .await + .unwrap(); + + let admin = get_admin_keypair(); + env.rpc + .airdrop_lamports(&admin.pubkey(), 10_000_000_000) + .await + .unwrap(); + + let initial_balance = 1_000_000; + let tokens = setup_token_mints(&mut env.rpc, &env.payer, &creator.pubkey(), initial_balance).await; + + let amm_config = create_amm_config(&mut env.rpc, &env.payer, &admin, program_id, amm_config_index).await; + setup_create_pool_fee_account(&mut env.rpc, &env.payer.pubkey()); + + let pdas = derive_amm_pdas( + &program_id, + &amm_config, + &tokens.token_0_mint, + &tokens.token_1_mint, + &creator.pubkey(), + ); + + PoolSetup { + env, + creator, + tokens, + amm_config, + pdas, + } +} diff --git a/programs/cp-swap/tests/program.rs b/programs/cp-swap/tests/program.rs new file mode 100644 index 0000000..861670b --- /dev/null +++ b/programs/cp-swap/tests/program.rs @@ -0,0 +1,567 @@ +#![allow(dead_code)] + +/// CpSwap SDK implementing LightProgramInterface trait. +/// +/// Provides: +/// - Parsing pool accounts from AccountInterface +/// - Tracking account state (hot/cold) +/// - Building AccountSpec for load instructions + +use anchor_lang::AnchorDeserialize; +use light_client::interface::{ + AccountInterface, AccountSpec, AccountToFetch, ColdContext, LightProgramInterface, PdaSpec, + TokenAccountInterface, +}; +use light_sdk::LightDiscriminator; +use light_token_sdk::compat::{CTokenData, TokenData}; +use raydium_cp_swap::instructions::initialize::LP_MINT_SIGNER_SEED; +use raydium_cp_swap::{ + raydium_cp_swap::{LightAccountVariant, TokenAccountVariant}, + states::{ObservationState, PoolState}, + AUTH_SEED, +}; +use solana_pubkey::Pubkey; +use std::collections::HashMap; + +pub const PROGRAM_ID: Pubkey = raydium_cp_swap::ID; + +/// Instructions supported by the cp-swap program. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum CpSwapInstruction { + Swap, + Deposit, + Withdraw, +} + +/// Error type for SDK operations. +#[derive(Debug, Clone)] +pub enum CpSwapSdkError { + ParseError(String), + UnknownDiscriminator([u8; 8]), + MissingField(&'static str), + PoolStateNotParsed, + AccountNotFound(Pubkey), +} + +impl std::fmt::Display for CpSwapSdkError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::ParseError(msg) => write!(f, "Parse error: {}", msg), + Self::UnknownDiscriminator(disc) => write!(f, "Unknown discriminator: {:?}", disc), + Self::MissingField(field) => write!(f, "Missing field: {}", field), + Self::PoolStateNotParsed => write!(f, "Pool state must be parsed first"), + Self::AccountNotFound(key) => write!(f, "Account not found: {}", key), + } + } +} + +impl std::error::Error for CpSwapSdkError {} + +/// SDK for managing cp-swap pool accounts and building decompression instructions. +#[derive(Debug, Clone)] +pub struct CpSwapSdk { + /// Pool state pubkey + pub pool_state_pubkey: Option, + /// AMM config pubkey + pub amm_config: Option, + /// Token 0 mint pubkey + pub token_0_mint: Option, + /// Token 1 mint pubkey + pub token_1_mint: Option, + /// Token 0 vault pubkey + pub token_0_vault: Option, + /// Token 1 vault pubkey + pub token_1_vault: Option, + /// LP mint pubkey + pub lp_mint: Option, + /// LP mint signer pubkey + pub lp_mint_signer: Option, + /// Observation state pubkey + pub observation_key: Option, + /// Authority pubkey + pub authority: Option, + /// Cached PDA specs keyed by pubkey (includes pool_state, observation, and vaults) + pda_specs: HashMap>, + /// Cached mint interfaces keyed by pubkey + mint_specs: HashMap, +} + +impl Default for CpSwapSdk { + fn default() -> Self { + Self::new() + } +} + +impl CpSwapSdk { + /// Create a new empty SDK instance. + pub fn new() -> Self { + Self { + pool_state_pubkey: None, + amm_config: None, + token_0_mint: None, + token_1_mint: None, + token_0_vault: None, + token_1_vault: None, + lp_mint: None, + lp_mint_signer: None, + observation_key: None, + authority: None, + pda_specs: HashMap::new(), + mint_specs: HashMap::new(), + } + } + + /// Parse pool state from AccountInterface and populate SDK fields. + fn parse_pool_state(&mut self, interface: AccountInterface) -> Result<(), CpSwapSdkError> { + let data = interface.data(); + if data.len() < 8 { + return Err(CpSwapSdkError::ParseError( + "Account data too short".to_string(), + )); + } + + // Skip 8-byte discriminator + let pool_state = PoolState::deserialize(&mut &data[8..]) + .map_err(|e| CpSwapSdkError::ParseError(e.to_string()))?; + + let pool_pubkey = interface.key; + self.pool_state_pubkey = Some(pool_pubkey); + self.amm_config = Some(pool_state.amm_config); + self.token_0_mint = Some(pool_state.token_0_mint); + self.token_1_mint = Some(pool_state.token_1_mint); + self.token_0_vault = Some(pool_state.token_0_vault); + self.token_1_vault = Some(pool_state.token_1_vault); + self.lp_mint = Some(pool_state.lp_mint); + self.observation_key = Some(pool_state.observation_key); + + // Derive lp_mint_signer and authority PDAs + let (lp_mint_signer, _) = + Pubkey::find_program_address(&[LP_MINT_SIGNER_SEED, pool_pubkey.as_ref()], &PROGRAM_ID); + self.lp_mint_signer = Some(lp_mint_signer); + + let (authority, _) = Pubkey::find_program_address(&[AUTH_SEED.as_bytes()], &PROGRAM_ID); + self.authority = Some(authority); + + // Create PdaSpec with variant + let variant = LightAccountVariant::PoolState { + data: pool_state.clone(), + amm_config: pool_state.amm_config, + token_0_mint: pool_state.token_0_mint, + token_1_mint: pool_state.token_1_mint, + }; + let spec = PdaSpec::new(interface, variant, PROGRAM_ID); + self.pda_specs.insert(pool_pubkey, spec); + + Ok(()) + } + + /// Parse observation state from AccountInterface. + fn parse_observation_state(&mut self, interface: AccountInterface) -> Result<(), CpSwapSdkError> { + let pool_state = self + .pool_state_pubkey + .ok_or(CpSwapSdkError::PoolStateNotParsed)?; + + let data = interface.data(); + if data.len() < 8 { + return Err(CpSwapSdkError::ParseError( + "Account data too short".to_string(), + )); + } + + let obs_pubkey = interface.key; + let obs_state = ObservationState::deserialize(&mut &data[8..]) + .map_err(|e| CpSwapSdkError::ParseError(e.to_string()))?; + + let variant = LightAccountVariant::ObservationState { + data: obs_state, + pool_state, + }; + let spec = PdaSpec::new(interface, variant, PROGRAM_ID); + self.pda_specs.insert(obs_pubkey, spec); + + Ok(()) + } + + /// Store token vault interface. + /// Vaults are program-owned PDAs, so we convert them to PdaSpec with CTokenData variant. + pub fn set_token_vault(&mut self, interface: TokenAccountInterface, is_vault_0: bool) { + let key = interface.key; + let pool_state = self.pool_state_pubkey.expect("pool_state must be set before vaults"); + let mint = if is_vault_0 { + self.token_0_mint.expect("token_0_mint must be set") + } else { + self.token_1_mint.expect("token_1_mint must be set") + }; + + // Build TokenData from TokenAccountInterface + let token_data = TokenData { + mint: interface.mint(), + owner: interface.owner(), + amount: interface.amount(), + delegate: if interface.parsed.delegate.option == [1, 0, 0, 0] { + Some(Pubkey::from(interface.parsed.delegate.value)) + } else { + None + }, + state: light_token_sdk::compat::AccountState::Initialized, + tlv: None, + }; + + // Build variant based on which vault this is + let variant = if is_vault_0 { + LightAccountVariant::CTokenData(CTokenData { + variant: TokenAccountVariant::Token0Vault { + pool_state, + token_0_mint: mint, + }, + token_data, + }) + } else { + LightAccountVariant::CTokenData(CTokenData { + variant: TokenAccountVariant::Token1Vault { + pool_state, + token_1_mint: mint, + }, + token_data, + }) + }; + + // Convert TokenAccountInterface to AccountInterface for PdaSpec + // For cold vaults, we need to convert ColdContext::Token to ColdContext::Account + let cold = if let Some(ColdContext::Token(ct)) = &interface.cold { + Some(ColdContext::Account(ct.account.clone())) + } else { + None + }; + + let account_interface = AccountInterface { + key, + account: interface.account.clone(), + cold, + }; + + let spec = PdaSpec::new(account_interface, variant, PROGRAM_ID); + + self.pda_specs.insert(key, spec); + if is_vault_0 { + self.token_0_vault = Some(key); + } else { + self.token_1_vault = Some(key); + } + } + + /// Store LP mint interface. + pub fn set_lp_mint(&mut self, interface: AccountInterface) { + let key = interface.key; + self.lp_mint = Some(key); + self.mint_specs.insert(key, interface); + } + + /// Parse token vault from AccountInterface and store as PdaSpec. + fn parse_token_vault( + &mut self, + account: &AccountInterface, + is_vault_0: bool, + ) -> Result<(), CpSwapSdkError> { + let pool_state = self + .pool_state_pubkey + .ok_or(CpSwapSdkError::PoolStateNotParsed)?; + + // Deserialize token data properly + let token_data = TokenData::deserialize(&mut &account.data()[..]) + .map_err(|e| CpSwapSdkError::ParseError(e.to_string()))?; + + // Build variant based on which vault this is + let variant = if is_vault_0 { + let token_0_mint = self + .token_0_mint + .ok_or(CpSwapSdkError::MissingField("token_0_mint"))?; + LightAccountVariant::CTokenData(CTokenData { + variant: TokenAccountVariant::Token0Vault { + pool_state, + token_0_mint, + }, + token_data, + }) + } else { + let token_1_mint = self + .token_1_mint + .ok_or(CpSwapSdkError::MissingField("token_1_mint"))?; + LightAccountVariant::CTokenData(CTokenData { + variant: TokenAccountVariant::Token1Vault { + pool_state, + token_1_mint, + }, + token_data, + }) + }; + + // For token vaults, convert ColdContext::Token to ColdContext::Account + // because they're decompressed as PDAs, not as token accounts + let interface = if account.is_cold() { + let compressed_account = match &account.cold { + Some(ColdContext::Token(ct)) => ct.account.clone(), + Some(ColdContext::Account(ca)) => ca.clone(), + None => return Err(CpSwapSdkError::MissingField("cold_context")), + }; + AccountInterface { + key: account.key, + account: account.account.clone(), + cold: Some(ColdContext::Account(compressed_account)), + } + } else { + account.clone() + }; + + let spec = PdaSpec::new(interface, variant, PROGRAM_ID); + self.pda_specs.insert(account.key, spec); + + Ok(()) + } + + /// Parse LP mint from AccountInterface. + fn parse_mint(&mut self, account: &AccountInterface) -> Result<(), CpSwapSdkError> { + self.mint_specs.insert(account.key, account.clone()); + Ok(()) + } + + /// Parse any account and route to appropriate parser. + fn parse_account(&mut self, account: &AccountInterface) -> Result<(), CpSwapSdkError> { + // Check if this is a known vault by pubkey + if Some(account.key) == self.token_0_vault { + return self.parse_token_vault(account, true); + } + if Some(account.key) == self.token_1_vault { + return self.parse_token_vault(account, false); + } + + // Check discriminator for pool/observation state + let data = account.data(); + if data.len() >= 8 { + let discriminator: [u8; 8] = data[..8].try_into().unwrap_or_default(); + + if discriminator == PoolState::LIGHT_DISCRIMINATOR { + return self.parse_pool_state(account.clone()); + } + if discriminator == ObservationState::LIGHT_DISCRIMINATOR { + return self.parse_observation_state(account.clone()); + } + } + + // Check if this is an LP mint by matching the signer + if let Some(lp_mint_signer) = self.lp_mint_signer { + if let Some(mint_signer) = account.mint_signer() { + if Pubkey::new_from_array(mint_signer) == lp_mint_signer { + return self.parse_mint(account); + } + } + } + + // Check if this is a vault mint (token_0_mint or token_1_mint) + if Some(account.key) == self.token_0_mint || Some(account.key) == self.token_1_mint { + return self.parse_mint(account); + } + + Ok(()) + } + + /// Check if pool state is cold. + pub fn is_pool_state_cold(&self) -> bool { + self.pool_state_pubkey + .and_then(|k| self.pda_specs.get(&k)) + .map_or(false, |s| s.is_cold()) + } + + /// Check if observation state is cold. + pub fn is_observation_cold(&self) -> bool { + self.observation_key + .and_then(|k| self.pda_specs.get(&k)) + .map_or(false, |s| s.is_cold()) + } + + /// Check if token 0 vault is cold. + pub fn is_vault_0_cold(&self) -> bool { + self.token_0_vault + .and_then(|k| self.pda_specs.get(&k)) + .map_or(false, |s| s.is_cold()) + } + + /// Check if token 1 vault is cold. + pub fn is_vault_1_cold(&self) -> bool { + self.token_1_vault + .and_then(|k| self.pda_specs.get(&k)) + .map_or(false, |s| s.is_cold()) + } + + /// Check if LP mint is cold. + pub fn is_lp_mint_cold(&self) -> bool { + self.lp_mint + .and_then(|k| self.mint_specs.get(&k)) + .map_or(false, |s| s.is_cold()) + } + + /// Get pool state pubkey. + pub fn pool_state(&self) -> Option { + self.pool_state_pubkey + } +} + +impl LightProgramInterface for CpSwapSdk { + type Variant = LightAccountVariant; + type Instruction = CpSwapInstruction; + type Error = CpSwapSdkError; + + fn program_id(&self) -> Pubkey { + PROGRAM_ID + } + + fn from_keyed_accounts(accounts: &[AccountInterface]) -> Result { + let mut sdk = Self::new(); + + // First pass: find and parse pool state + for account in accounts { + let data = account.data(); + if data.len() >= 8 { + let discriminator: [u8; 8] = data[..8].try_into().unwrap_or_default(); + if discriminator == PoolState::LIGHT_DISCRIMINATOR { + sdk.parse_pool_state(account.clone())?; + break; + } + } + } + + if sdk.pool_state_pubkey.is_none() { + return Err(CpSwapSdkError::MissingField("pool_state")); + } + + // Second pass: parse other accounts + for account in accounts { + let data = account.data(); + if data.len() >= 8 { + let discriminator: [u8; 8] = data[..8].try_into().unwrap_or_default(); + if discriminator == ObservationState::LIGHT_DISCRIMINATOR { + sdk.parse_observation_state(account.clone())?; + } + } + } + + Ok(sdk) + } + + fn get_accounts_to_update(&self, ix: &Self::Instruction) -> Vec { + let mut accounts = Vec::new(); + + // All instructions need pool_state and observation_state + if let Some(pubkey) = self.pool_state_pubkey { + accounts.push(AccountToFetch::pda(pubkey, PROGRAM_ID)); + } + if let Some(pubkey) = self.observation_key { + accounts.push(AccountToFetch::pda(pubkey, PROGRAM_ID)); + } + + // All instructions need token vaults + if let Some(pubkey) = self.token_0_vault { + accounts.push(AccountToFetch::token(pubkey)); + } + if let Some(pubkey) = self.token_1_vault { + accounts.push(AccountToFetch::token(pubkey)); + } + + // All instructions need vault mints (token_0_mint and token_1_mint) + if let Some(pubkey) = self.token_0_mint { + accounts.push(AccountToFetch::mint(pubkey)); + } + if let Some(pubkey) = self.token_1_mint { + accounts.push(AccountToFetch::mint(pubkey)); + } + + // Deposit and Withdraw also need LP mint + match ix { + CpSwapInstruction::Deposit | CpSwapInstruction::Withdraw => { + if let Some(pubkey) = self.lp_mint { + accounts.push(AccountToFetch::mint(pubkey)); + } + } + CpSwapInstruction::Swap => {} + } + + accounts + } + + fn update(&mut self, accounts: &[AccountInterface]) -> Result<(), Self::Error> { + for account in accounts { + self.parse_account(account)?; + } + Ok(()) + } + + fn get_all_specs(&self) -> Vec> { + let mut specs = Vec::new(); + + // Add PDA specs (includes pool_state, observation, and vaults) + for spec in self.pda_specs.values() { + specs.push(AccountSpec::Pda(spec.clone())); + } + + // Add mint specs + for spec in self.mint_specs.values() { + specs.push(AccountSpec::Mint(spec.clone())); + } + + specs + } + + fn get_specs_for_instruction(&self, ix: &Self::Instruction) -> Vec> { + let mut specs = Vec::new(); + + // Pool state and observation state needed for all instructions + if let Some(pubkey) = self.pool_state_pubkey { + if let Some(spec) = self.pda_specs.get(&pubkey) { + specs.push(AccountSpec::Pda(spec.clone())); + } + } + if let Some(pubkey) = self.observation_key { + if let Some(spec) = self.pda_specs.get(&pubkey) { + specs.push(AccountSpec::Pda(spec.clone())); + } + } + + // Token vaults needed for all instructions (stored as PDA specs with CTokenData variant) + if let Some(pubkey) = self.token_0_vault { + if let Some(spec) = self.pda_specs.get(&pubkey) { + specs.push(AccountSpec::Pda(spec.clone())); + } + } + if let Some(pubkey) = self.token_1_vault { + if let Some(spec) = self.pda_specs.get(&pubkey) { + specs.push(AccountSpec::Pda(spec.clone())); + } + } + + // Vault mints (token_0_mint and token_1_mint) needed for all instructions + if let Some(pubkey) = self.token_0_mint { + if let Some(spec) = self.mint_specs.get(&pubkey) { + specs.push(AccountSpec::Mint(spec.clone())); + } + } + if let Some(pubkey) = self.token_1_mint { + if let Some(spec) = self.mint_specs.get(&pubkey) { + specs.push(AccountSpec::Mint(spec.clone())); + } + } + + // LP mint needed for deposit/withdraw + match ix { + CpSwapInstruction::Deposit | CpSwapInstruction::Withdraw => { + if let Some(pubkey) = self.lp_mint { + if let Some(spec) = self.mint_specs.get(&pubkey) { + specs.push(AccountSpec::Mint(spec.clone())); + } + } + } + CpSwapInstruction::Swap => {} + } + + specs + } +} diff --git a/programs/cp-swap/tests/program_test.rs b/programs/cp-swap/tests/program_test.rs new file mode 100644 index 0000000..78a5fda --- /dev/null +++ b/programs/cp-swap/tests/program_test.rs @@ -0,0 +1,223 @@ +/// Clean integration test for cp-swap using CpSwapSdk. +/// Tests the full lifecycle: Initialize -> Warp -> Compress -> Load -> Execute Operations + +use light_client::interface::{ + create_load_instructions, AccountInterfaceExt, AccountSpec, LightProgramInterface, +}; +use light_program_test::program_test::TestRpc; +use light_program_test::Rpc; +use solana_instruction::Instruction; +use solana_sdk::transaction::Transaction; +use solana_signer::Signer; + +mod helpers; +mod program; + +use helpers::*; +use program::{CpSwapInstruction, CpSwapSdk}; + +fn log_transaction_size(name: &str, ixs: &[Instruction]) { + let tx = Transaction::new_with_payer(ixs, None); + let serialized = bincode::serialize(&tx).expect("Failed to serialize transaction"); + println!("{}: {} bytes ({} instructions)", name, serialized.len(), ixs.len()); +} + +#[tokio::test] +async fn test_sdk_lifecycle() { + let program_id = raydium_cp_swap::ID; + + // ==================== PHASE 1: Setup & Initialize Pool ==================== + let mut setup = setup_pool_environment(program_id, 10).await; + + let proof_result = + get_pool_create_accounts_proof(&setup.env.rpc, &program_id, &setup.pdas).await; + let init_ix = build_initialize_instruction( + program_id, + setup.creator.pubkey(), + setup.amm_config, + &setup.pdas, + &setup.tokens, + setup.env.config_pda, + &proof_result, + 100_000, + 100_000, + 0, + ); + log_transaction_size("Initialize transaction", &[init_ix.clone()]); + setup + .env + .rpc + .create_and_send_transaction(&[init_ix], &setup.creator.pubkey(), &[&setup.creator]) + .await + .unwrap(); + + // ==================== PHASE 2: Verify Hot Accounts Exist ==================== + assert_pool_accounts_exist(&mut setup.env.rpc, &setup.pdas, &setup.tokens).await; + + // ==================== PHASE 3: Warp to Trigger Compression ==================== + setup + .env + .rpc + .warp_epoch_forward(30) + .await + .unwrap(); + + // ==================== PHASE 4: Assert All Accounts Are Compressed ==================== + assert_pool_accounts_compressed(&mut setup.env.rpc, &setup.pdas, &setup.tokens).await; + + // ==================== PHASE 5: Create SDK from Compressed State ==================== + let pool_interface = setup + .env + .rpc + .get_account_interface(&setup.pdas.pool_state, &program_id) + .await + .expect("pool should be compressed"); + assert!( + pool_interface.is_cold(), + "pool_state should be cold after warp" + ); + + let mut sdk = CpSwapSdk::from_keyed_accounts(&[pool_interface]) + .expect("from_keyed_accounts should succeed"); + + // ==================== PHASE 6: Fetch & Update SDK ==================== + let accounts_to_fetch = sdk.get_accounts_to_update(&CpSwapInstruction::Deposit); + let keyed_accounts = setup + .env + .rpc + .get_multiple_account_interfaces(&accounts_to_fetch) + .await + .expect("get_multiple_account_interfaces should succeed"); + + sdk.update(&keyed_accounts) + .expect("sdk.update should succeed"); + + // ==================== PHASE 7: Build Specs for Load ==================== + let mut all_specs = sdk.get_specs_for_instruction(&CpSwapInstruction::Deposit); + + // Fetch creator's ATAs (compressed) and add to specs + let creator_lp_ata_interface = setup + .env + .rpc + .get_ata_interface(&setup.creator.pubkey(), &setup.pdas.lp_mint) + .await + .expect("get_ata_interface for creator_lp_token should succeed"); + all_specs.push(AccountSpec::Ata(creator_lp_ata_interface)); + + let creator_token_0_interface = setup + .env + .rpc + .get_ata_interface(&setup.creator.pubkey(), &setup.tokens.token_0_mint) + .await + .expect("get_ata_interface for creator_token_0 should succeed"); + all_specs.push(AccountSpec::Ata(creator_token_0_interface)); + + let creator_token_1_interface = setup + .env + .rpc + .get_ata_interface(&setup.creator.pubkey(), &setup.tokens.token_1_mint) + .await + .expect("get_ata_interface for creator_token_1 should succeed"); + all_specs.push(AccountSpec::Ata(creator_token_1_interface)); + + // ==================== PHASE 8: Create Load Instructions ==================== + let all_load_ixs = create_load_instructions( + &all_specs, + setup.env.payer.pubkey(), + setup.env.config_pda, + setup.env.payer.pubkey(), + &setup.env.rpc, + ) + .await + .expect("create_load_instructions should succeed"); + + // ==================== PHASE 9: Execute Load ==================== + log_transaction_size("Load transaction", &all_load_ixs); + setup + .env + .rpc + .create_and_send_transaction( + &all_load_ixs, + &setup.env.payer.pubkey(), + &[&setup.env.payer, &setup.creator], + ) + .await + .expect("Load should succeed"); + + // ==================== PHASE 10: Verify Accounts Are Loaded ==================== + assert_pool_accounts_exist(&mut setup.env.rpc, &setup.pdas, &setup.tokens).await; + + // ==================== PHASE 11: Execute Operations ==================== + // Deposit + let deposit_ix = build_deposit_instruction( + program_id, + setup.creator.pubkey(), + &setup.pdas, + &setup.tokens, + setup.tokens.creator_token_0, + setup.tokens.creator_token_1, + 500, + 10_000, + 10_000, + ); + log_transaction_size("Deposit transaction", &[deposit_ix.clone()]); + + // Log combined Load + Deposit + let mut load_plus_deposit = all_load_ixs.clone(); + load_plus_deposit.push(deposit_ix.clone()); + log_transaction_size("Load + Deposit transaction", &load_plus_deposit); + + setup + .env + .rpc + .create_and_send_transaction(&[deposit_ix], &setup.creator.pubkey(), &[&setup.creator]) + .await + .unwrap(); + + // Swap + let swap_ix = build_swap_instruction( + program_id, + setup.creator.pubkey(), + setup.amm_config, + &setup.pdas, + &setup.tokens, + setup.tokens.creator_token_0, + setup.tokens.creator_token_1, + true, + 100, + 1, + ); + log_transaction_size("Swap transaction", &[swap_ix.clone()]); + + // Log combined Load + Swap + let mut load_plus_swap = all_load_ixs.clone(); + load_plus_swap.push(swap_ix.clone()); + log_transaction_size("Load + Swap transaction", &load_plus_swap); + + setup + .env + .rpc + .create_and_send_transaction(&[swap_ix], &setup.creator.pubkey(), &[&setup.creator]) + .await + .unwrap(); + + // Withdraw + let lp_balance = get_token_balance(&mut setup.env.rpc, setup.pdas.creator_lp_token).await; + let withdraw_ix = build_withdraw_instruction( + program_id, + setup.creator.pubkey(), + &setup.pdas, + &setup.tokens, + setup.tokens.creator_token_0, + setup.tokens.creator_token_1, + lp_balance / 2, + 0, + 0, + ); + setup + .env + .rpc + .create_and_send_transaction(&[withdraw_ix], &setup.creator.pubkey(), &[&setup.creator]) + .await + .unwrap(); +} From ea8122e999bbace49e80254452a19284e841ccf9 Mon Sep 17 00:00:00 2001 From: ananas-block <58553958+ananas-block@users.noreply.github.com> Date: Tue, 20 Jan 2026 07:27:01 +0000 Subject: [PATCH 14/15] chore: use released crates (#21) * chore: update light-protocol dependencies to released crates - Update light-sdk to 0.18.0 - Update light-token to 0.3.0 - Update light-program-test to 0.18.0 - Update light-client to 0.18.0 - Add light-hasher 5 - Add light-anchor-spl 0.31.1 - Remove v2 feature flags (now default) * chore: use released versions --- Cargo.lock | 475 +++++++----------- programs/cp-swap/Cargo.toml | 12 +- .../instructions/admin/collect_fund_fee.rs | 8 +- .../admin/collect_protocol_fee.rs | 8 +- programs/cp-swap/src/instructions/deposit.rs | 8 +- .../cp-swap/src/instructions/initialize.rs | 8 +- .../src/instructions/swap_base_input.rs | 2 +- programs/cp-swap/src/instructions/withdraw.rs | 4 +- programs/cp-swap/src/lib.rs | 2 +- programs/cp-swap/src/states/oracle.rs | 2 +- programs/cp-swap/src/states/pool.rs | 4 +- programs/cp-swap/src/utils/token.rs | 4 +- programs/cp-swap/tests/helpers.rs | 10 +- programs/cp-swap/tests/program.rs | 4 +- 14 files changed, 211 insertions(+), 340 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index bddb2eb..785203f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -12,30 +12,6 @@ dependencies = [ "regex", ] -[[package]] -name = "account-compression" -version = "2.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" -dependencies = [ - "aligned-sized", - "anchor-lang", - "bytemuck", - "light-account-checks", - "light-batched-merkle-tree", - "light-bounded-vec", - "light-compressed-account", - "light-concurrent-merkle-tree", - "light-hash-set", - "light-hasher", - "light-indexed-merkle-tree", - "light-merkle-tree-metadata", - "light-zero-copy", - "num-bigint 0.4.6", - "solana-sdk", - "solana-security-txt", - "zerocopy", -] - [[package]] name = "adler2" version = "2.0.1" @@ -150,7 +126,8 @@ dependencies = [ [[package]] name = "aligned-sized" version = "1.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48a526ec4434d531d488af59fe866f36b310fe8906691c75dffa664450a3800a" dependencies = [ "proc-macro2", "quote", @@ -254,28 +231,6 @@ dependencies = [ "syn 1.0.109", ] -[[package]] -name = "anchor-compressed-token" -version = "2.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" -dependencies = [ - "account-compression", - "anchor-lang", - "anchor-spl", - "light-compressed-account", - "light-hasher", - "light-heap", - "light-system-program-anchor", - "light-token-interface", - "light-zero-copy", - "pinocchio-pubkey", - "solana-sdk", - "solana-security-txt", - "spl-token 7.0.0", - "spl-token-2022 7.0.0", - "zerocopy", -] - [[package]] name = "anchor-derive-accounts" version = "0.31.1" @@ -360,21 +315,6 @@ dependencies = [ "serde", ] -[[package]] -name = "anchor-spl" -version = "0.31.1" -source = "git+https://github.com/lightprotocol/anchor?rev=da005d7f#da005d7f1f977d5220eaa65da26cdae2df0fe25e" -dependencies = [ - "anchor-lang", - "spl-associated-token-account 6.0.0", - "spl-memo", - "spl-pod", - "spl-token 7.0.0", - "spl-token-2022 6.0.0", - "spl-token-group-interface 0.5.0", - "spl-token-metadata-interface 0.6.0", -] - [[package]] name = "anchor-syn" version = "0.31.1" @@ -2505,9 +2445,9 @@ dependencies = [ [[package]] name = "light-account-checks" version = "0.6.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0785da22cd4a7667583141ca56c790a5c8afa2b22ad2a08204d78881035524e8" dependencies = [ - "pinocchio", "solana-account-info", "solana-msg", "solana-program-error", @@ -2516,29 +2456,47 @@ dependencies = [ "thiserror 2.0.18", ] +[[package]] +name = "light-anchor-spl" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1c802e3de6de4bb03bc9e9bacbba8aa94823a083046aaf0ef275b1321984e3" +dependencies = [ + "anchor-lang", + "spl-associated-token-account 6.0.0", + "spl-memo", + "spl-pod", + "spl-token 7.0.0", + "spl-token-2022 6.0.0", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", +] + [[package]] name = "light-array-map" version = "0.1.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "859dc5b406a8bf0b114f686e6f2e36d0e939bad6f579492a520d309b52fde1f8" dependencies = [ "tinyvec", ] [[package]] name = "light-batched-merkle-tree" -version = "0.7.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13cb8bc778065ee71d1990fdc94112e35dc63a5e387a323284a49f40d123d8e0" dependencies = [ "aligned-sized", "borsh 0.10.4", "light-account-checks", "light-bloom-filter", - "light-compressed-account", + "light-compressed-account 0.8.0", "light-hasher", "light-macros", "light-merkle-tree-metadata", "light-verifier", - "light-zero-copy", + "light-zero-copy 0.6.0", "solana-account-info", "solana-msg", "solana-program-error", @@ -2551,7 +2509,8 @@ dependencies = [ [[package]] name = "light-bloom-filter" version = "0.5.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8a609e3c9179f0ae8488cc70c5413c86dfd97dad7ad85fee2ad8da2d0a11e61" dependencies = [ "bitvec", "num-bigint 0.4.6", @@ -2574,8 +2533,9 @@ dependencies = [ [[package]] name = "light-client" -version = "0.17.2" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b1f3cd013364dbe5c45a9e9a8faee1af30dccb600cd56a41e296ed8d5684768" dependencies = [ "anchor-lang", "async-trait", @@ -2584,7 +2544,7 @@ dependencies = [ "bs58", "futures", "lazy_static", - "light-compressed-account", + "light-compressed-account 0.8.0", "light-compressible", "light-concurrent-merkle-tree", "light-event", @@ -2593,8 +2553,8 @@ dependencies = [ "light-merkle-tree-metadata", "light-prover-client", "light-sdk", + "light-token", "light-token-interface", - "light-token-sdk", "litesvm", "num-bigint 0.4.6", "photon-api", @@ -2629,79 +2589,58 @@ dependencies = [ [[package]] name = "light-compressed-account" version = "0.7.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "058df2733fa6a3e4bda6f162a6c5d41f10fc8c6f6ddb992af1de76b60214e4a6" dependencies = [ - "anchor-lang", "borsh 0.10.4", - "bytemuck", "light-hasher", "light-macros", - "light-poseidon 0.3.0", "light-program-profiler", - "light-zero-copy", - "pinocchio", - "solana-msg", - "solana-program-error", - "solana-pubkey", + "light-zero-copy 0.5.0", "thiserror 2.0.18", "tinyvec", "zerocopy", ] [[package]] -name = "light-compressed-token" -version = "2.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +name = "light-compressed-account" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "768ae5a56d8c9cf315d132b3faa5b067f95b3d6a294c579e82f8f0e0bf29c7cc" dependencies = [ - "account-compression", - "anchor-compressed-token", "anchor-lang", - "arrayvec", - "bitvec", "borsh 0.10.4", - "light-account-checks", - "light-array-map", - "light-compressed-account", - "light-compressible", + "bytemuck", "light-hasher", - "light-heap", + "light-macros", + "light-poseidon 0.3.0", "light-program-profiler", - "light-sdk", - "light-sdk-pinocchio", - "light-sdk-types", - "light-system-program-anchor", - "light-token-interface", - "light-zero-copy", - "pinocchio", - "pinocchio-pubkey", - "pinocchio-system", - "pinocchio-token-program", + "light-zero-copy 0.6.0", + "solana-msg", + "solana-program-error", "solana-pubkey", - "solana-security-txt", - "spl-pod", - "spl-token 7.0.0", - "spl-token-2022 7.0.0", + "thiserror 2.0.18", "tinyvec", "zerocopy", ] [[package]] name = "light-compressible" -version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff0f0065beb8d16df587b3ea17082e11dea3f67c98813b4bcc061eecd94561f" dependencies = [ "aligned-sized", "anchor-lang", "borsh 0.10.4", "bytemuck", "light-account-checks", - "light-compressed-account", + "light-compressed-account 0.8.0", "light-hasher", "light-macros", "light-program-profiler", "light-sdk-types", - "light-zero-copy", - "pinocchio", + "light-zero-copy 0.6.0", "pinocchio-pubkey", "solana-pubkey", "thiserror 2.0.18", @@ -2711,7 +2650,8 @@ dependencies = [ [[package]] name = "light-concurrent-merkle-tree" version = "5.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db96f47253a0907aaa46dac15cecb27b5510130e48da0b36690dcd2e99a6d558" dependencies = [ "borsh 0.10.4", "light-bounded-vec", @@ -2723,32 +2663,22 @@ dependencies = [ [[package]] name = "light-event" -version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1674c9d85b32a9e8abb90cccdee18e35ae29daa1126fdb81a8a28c0a54802096" dependencies = [ "borsh 0.10.4", - "light-compressed-account", - "light-hasher", - "light-zero-copy", - "thiserror 2.0.18", -] - -[[package]] -name = "light-hash-set" -version = "4.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" -dependencies = [ + "light-compressed-account 0.8.0", "light-hasher", - "num-bigint 0.4.6", - "num-traits", - "solana-program-error", + "light-zero-copy 0.6.0", "thiserror 2.0.18", ] [[package]] name = "light-hasher" version = "5.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c822662e6e109bac0e132a43fd52a4ef684811245a794e048cf9cda001e934c8" dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", @@ -2762,18 +2692,11 @@ dependencies = [ "tinyvec", ] -[[package]] -name = "light-heap" -version = "2.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" -dependencies = [ - "anchor-lang", -] - [[package]] name = "light-indexed-array" version = "0.3.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f14f984030d86b6f07bd8f5ae04e2c40fcd0c3bdfcc7a291fff1ed59c9e6554" dependencies = [ "light-hasher", "num-bigint 0.4.6", @@ -2784,7 +2707,8 @@ dependencies = [ [[package]] name = "light-indexed-merkle-tree" version = "5.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0824755289075f28de2820fc7d4ec4e6b9e99d404e033c07338b91cce8c71fb8" dependencies = [ "light-bounded-vec", "light-concurrent-merkle-tree", @@ -2799,7 +2723,8 @@ dependencies = [ [[package]] name = "light-macros" version = "2.2.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "179ac51cadc1d0ca047b4d6265a7cc245ca3affc16a20a2749585aa6464d39c2" dependencies = [ "bs58", "proc-macro2", @@ -2810,13 +2735,14 @@ dependencies = [ [[package]] name = "light-merkle-tree-metadata" -version = "0.7.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17d08edcc194eef61b0f499934ce398122d54ac57505d44480e5f079a4220566" dependencies = [ "anchor-lang", "borsh 0.10.4", "bytemuck", - "light-compressed-account", + "light-compressed-account 0.8.0", "solana-msg", "solana-program-error", "solana-sysvar", @@ -2827,7 +2753,8 @@ dependencies = [ [[package]] name = "light-merkle-tree-reference" version = "4.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8d480f62ca32b38a6231bbc5310d693f91d6b5bdcc18bb13c2d9aab7a1c90e8" dependencies = [ "light-hasher", "light-indexed-array", @@ -2882,10 +2809,10 @@ dependencies = [ [[package]] name = "light-program-test" -version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a981dfbc19c529543ab1dd8d100319b89aac053b81415a681d1474c986218307" dependencies = [ - "account-compression", "anchor-lang", "async-trait", "base64 0.13.1", @@ -2893,12 +2820,9 @@ dependencies = [ "bs58", "bytemuck", "chrono", - "light-batched-merkle-tree", "light-client", - "light-compressed-account", - "light-compressed-token", + "light-compressed-account 0.8.0", "light-compressible", - "light-concurrent-merkle-tree", "light-event", "light-hasher", "light-indexed-array", @@ -2906,12 +2830,11 @@ dependencies = [ "light-merkle-tree-metadata", "light-merkle-tree-reference", "light-prover-client", - "light-registry", "light-sdk", "light-sdk-types", + "light-token", "light-token-interface", - "light-token-sdk", - "light-zero-copy", + "light-zero-copy 0.6.0", "litesvm", "log", "num-bigint 0.4.6", @@ -2939,12 +2862,13 @@ dependencies = [ [[package]] name = "light-prover-client" version = "5.0.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75d8c9b8b6e9d445b9ef27467da592ee231e614282c3c0bd2f30f567eb904845" dependencies = [ "ark-bn254 0.5.0", "ark-serialize 0.5.0", "ark-std 0.5.0", - "light-compressed-account", + "light-compressed-account 0.7.0", "light-hasher", "light-indexed-array", "light-sparse-merkle-tree", @@ -2959,48 +2883,23 @@ dependencies = [ "tracing", ] -[[package]] -name = "light-registry" -version = "2.1.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" -dependencies = [ - "account-compression", - "aligned-sized", - "anchor-lang", - "borsh 0.10.4", - "light-account-checks", - "light-batched-merkle-tree", - "light-compressible", - "light-macros", - "light-merkle-tree-metadata", - "light-program-profiler", - "light-system-program-anchor", - "light-token-interface", - "light-zero-copy", - "solana-account-info", - "solana-instruction", - "solana-pubkey", - "solana-sdk", - "solana-security-txt", - "spl-pod", -] - [[package]] name = "light-sdk" -version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6dece106ebd0897bd23a12bad040e0999d93b54447d0473739f91b1f83b1d331" dependencies = [ "anchor-lang", "bincode", "borsh 0.10.4", "light-account-checks", - "light-compressed-account", + "light-compressed-account 0.8.0", "light-compressible", "light-hasher", "light-macros", "light-sdk-macros", "light-sdk-types", - "light-zero-copy", + "light-zero-copy 0.6.0", "num-bigint 0.4.6", "solana-account-info", "solana-clock", @@ -3008,6 +2907,7 @@ dependencies = [ "solana-instruction", "solana-loader-v3-interface", "solana-msg", + "solana-program", "solana-program-error", "solana-pubkey", "solana-system-interface", @@ -3017,8 +2917,9 @@ dependencies = [ [[package]] name = "light-sdk-macros" -version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45d91992fa08093b1a274b3baed1d8368de794cc2645f9942718e5fe47a27dc2" dependencies = [ "darling", "light-hasher", @@ -3029,31 +2930,16 @@ dependencies = [ "syn 2.0.114", ] -[[package]] -name = "light-sdk-pinocchio" -version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" -dependencies = [ - "borsh 0.10.4", - "light-account-checks", - "light-compressed-account", - "light-hasher", - "light-macros", - "light-sdk-macros", - "light-sdk-types", - "pinocchio", - "thiserror 2.0.18", -] - [[package]] name = "light-sdk-types" -version = "0.17.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b765f0a39428a137b8d449fa60ba147194cdbff08aa0add598c6047fff2cb7d2" dependencies = [ "anchor-lang", "borsh 0.10.4", "light-account-checks", - "light-compressed-account", + "light-compressed-account 0.8.0", "light-hasher", "light-macros", "solana-msg", @@ -3063,7 +2949,8 @@ dependencies = [ [[package]] name = "light-sparse-merkle-tree" version = "0.3.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4251e79b6c63f4946572dcfd7623680ad0f9e0efe1a761a944733333c5645063" dependencies = [ "light-hasher", "light-indexed-array", @@ -3073,34 +2960,53 @@ dependencies = [ ] [[package]] -name = "light-system-program-anchor" -version = "2.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +name = "light-token" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62907a12a9801200e5f4c03bb7f2dbdd9aa679223a959167c456a06005291d79" dependencies = [ - "account-compression", - "aligned-sized", "anchor-lang", - "light-compressed-account", - "light-zero-copy", - "zerocopy", + "arrayvec", + "borsh 0.10.4", + "light-account-checks", + "light-batched-merkle-tree", + "light-compressed-account 0.8.0", + "light-compressible", + "light-macros", + "light-program-profiler", + "light-sdk", + "light-sdk-macros", + "light-sdk-types", + "light-token-interface", + "light-token-types", + "light-zero-copy 0.6.0", + "solana-account-info", + "solana-cpi", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-pod", + "thiserror 2.0.18", ] [[package]] name = "light-token-interface" -version = "0.1.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fb19b8e268a0154a8e13b3a8f6f43fa4928643e2de102d98a90b2af21f482ba" dependencies = [ "aligned-sized", "anchor-lang", "borsh 0.10.4", "bytemuck", "light-array-map", - "light-compressed-account", + "light-compressed-account 0.8.0", "light-compressible", "light-hasher", "light-macros", "light-program-profiler", - "light-zero-copy", + "light-zero-copy 0.6.0", "pinocchio", "pinocchio-pubkey", "solana-account-info", @@ -3112,46 +3018,16 @@ dependencies = [ "zerocopy", ] -[[package]] -name = "light-token-sdk" -version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" -dependencies = [ - "anchor-lang", - "anchor-spl", - "arrayvec", - "borsh 0.10.4", - "light-account-checks", - "light-batched-merkle-tree", - "light-compressed-account", - "light-compressible", - "light-macros", - "light-program-profiler", - "light-sdk", - "light-sdk-macros", - "light-sdk-types", - "light-token-interface", - "light-token-types", - "light-zero-copy", - "solana-account-info", - "solana-cpi", - "solana-instruction", - "solana-msg", - "solana-program-error", - "solana-pubkey", - "spl-pod", - "thiserror 2.0.18", -] - [[package]] name = "light-token-types" -version = "0.2.1" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278dddbf18d104f1225c480ca6d7b8710e1f9ff4104f24be70c522ecb6ed1dfc" dependencies = [ "anchor-lang", "borsh 0.10.4", "light-account-checks", - "light-compressed-account", + "light-compressed-account 0.8.0", "light-macros", "light-sdk-types", "solana-msg", @@ -3160,20 +3036,32 @@ dependencies = [ [[package]] name = "light-verifier" -version = "6.0.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f35f47736be493b60d8b56ef0c8e94afd6a99efafebb257f62b0b545e9aacab" dependencies = [ "groth16-solana", - "light-compressed-account", + "light-compressed-account 0.8.0", "thiserror 2.0.18", ] [[package]] name = "light-zero-copy" version = "0.5.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8862f463792fd60ae8f5dc418150c16213e302e19d54fba0694cf8515be5ff" dependencies = [ - "light-zero-copy-derive", + "light-zero-copy-derive 0.5.0", + "zerocopy", +] + +[[package]] +name = "light-zero-copy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5621fb515e14af46148699c0b65334aabe230a1d2cbd06736ccc7a408c8a4af" +dependencies = [ + "light-zero-copy-derive 0.6.0", "solana-program-error", "zerocopy", ] @@ -3181,7 +3069,20 @@ dependencies = [ [[package]] name = "light-zero-copy-derive" version = "0.5.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8af086d52100b3cab1f2993b146adc7a69fa6aaa878ae4c19514c77c50304379" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "light-zero-copy-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c46425e5c7ab5203ff5c86ae2615b169cca55f9283f5f60f5dd74143be6934" dependencies = [ "lazy_static", "proc-macro2", @@ -3658,8 +3559,9 @@ dependencies = [ [[package]] name = "photon-api" -version = "0.53.0" -source = "git+https://github.com/Lightprotocol/light-protocol?rev=5013dbe2f2abc77984a2801e69b5c46453962b31#5013dbe2f2abc77984a2801e69b5c46453962b31" +version = "0.54.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e572dba0c255f5b8176f15b9e849330d915a8927804f7f9702d5bbbc70e4a1ad" dependencies = [ "reqwest 0.12.28", "serde", @@ -3708,12 +3610,6 @@ version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b971851087bc3699b001954ad02389d50c41405ece3548cbcafc88b3e20017a" -[[package]] -name = "pinocchio-log" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd11022408f312e6179ece321c1f7dc0d1b2aa7765fddd39b2a7378d65a899e8" - [[package]] name = "pinocchio-pubkey" version = "0.3.0" @@ -3725,35 +3621,6 @@ dependencies = [ "sha2-const-stable", ] -[[package]] -name = "pinocchio-system" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141ed5eafb4ab04568bb0e224e3dc9a9de13c933de4c004e0d1a553498be3a7c" -dependencies = [ - "pinocchio", - "pinocchio-pubkey", -] - -[[package]] -name = "pinocchio-token-interface" -version = "0.0.0" -source = "git+https://github.com/Lightprotocol/token?rev=9ea04560a039d1a44f0411b5eaa7c0b79ed575ab#9ea04560a039d1a44f0411b5eaa7c0b79ed575ab" -dependencies = [ - "pinocchio", - "pinocchio-pubkey", -] - -[[package]] -name = "pinocchio-token-program" -version = "0.1.0" -source = "git+https://github.com/Lightprotocol/token?rev=9ea04560a039d1a44f0411b5eaa7c0b79ed575ab#9ea04560a039d1a44f0411b5eaa7c0b79ed575ab" -dependencies = [ - "pinocchio", - "pinocchio-log", - "pinocchio-token-interface", -] - [[package]] name = "pkg-config" version = "0.3.32" @@ -4101,10 +3968,12 @@ dependencies = [ "bincode", "blake3", "bytemuck", + "light-anchor-spl", "light-client", + "light-hasher", "light-program-test", "light-sdk", - "light-token-sdk", + "light-token", "proptest", "quickcheck", "rand 0.9.2", @@ -9112,9 +8981,9 @@ dependencies = [ [[package]] name = "zmij" -version = "1.0.15" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94f63c051f4fe3c1509da62131a678643c5b6fbdc9273b2b79d4378ebda003d2" +checksum = "dfcd145825aace48cff44a8844de64bf75feec3080e0aa5cdbde72961ae51a65" [[package]] name = "zstd" diff --git a/programs/cp-swap/Cargo.toml b/programs/cp-swap/Cargo.toml index 7db8b93..7ba71c3 100644 --- a/programs/cp-swap/Cargo.toml +++ b/programs/cp-swap/Cargo.toml @@ -19,7 +19,7 @@ enable-log = [] devnet = [] client = [] anchor-debug = [] -idl-build = ["anchor-lang/idl-build", "light-sdk/idl-build", "light-token-sdk/idl-build"] +idl-build = ["anchor-lang/idl-build", "light-sdk/idl-build", "light-token/idl-build", "light-anchor-spl/idl-build"] test-sbf = [] [dependencies] @@ -32,8 +32,10 @@ bytemuck = { version = "1.4.0", features = ["derive", "min_const_generics"] } arrayref = { version = "0.3.6" } blake3 = { workspace = true } -light-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["anchor", "anchor-discriminator", "v2", "idl-build", "cpi-context"] } -light-token-sdk = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["anchor", "idl-build", "anchor-spl-memo", "anchor-spl-associated-token"] } +light-sdk = { version = "0.18.0", features = ["anchor", "anchor-discriminator", "idl-build", "cpi-context"] } +light-token = { version = "0.3.0", features = ["anchor", "idl-build"] } +light-hasher = "5" +light-anchor-spl = { version = "0.31.1", features = ["idl-build", "memo"] } solana-account-info = "2.3" solana-program = "2.2" solana-pubkey = "2.2" @@ -46,8 +48,8 @@ quickcheck = "1.0.3" proptest = "1.0" rand = "0.9.0" -light-program-test = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["v2", "devenv"] } -light-client = { git = "https://github.com/Lightprotocol/light-protocol", rev = "5013dbe2f2abc77984a2801e69b5c46453962b31", features = ["v2"] } +light-program-test = { version = "0.18.0" } +light-client = { version = "0.18.0" } tokio = { version = "1", features = ["full"] } spl-token = "7.0.0" solana-keypair = { version = "2.2" } diff --git a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs index 390b697..068d806 100644 --- a/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_fund_fee.rs @@ -2,10 +2,10 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; -use light_token_sdk::anchor::anchor_spl::token::Token; -use light_token_sdk::anchor::anchor_spl::token_interface::Mint; -use light_token_sdk::anchor::anchor_spl::token_interface::Token2022; -use light_token_sdk::anchor::anchor_spl::token_interface::TokenAccount; +use light_anchor_spl::token::Token; +use light_anchor_spl::token_interface::Mint; +use light_anchor_spl::token_interface::Token2022; +use light_anchor_spl::token_interface::TokenAccount; #[derive(Accounts)] pub struct CollectFundFee<'info> { /// Only admin or fund_owner can collect fee now diff --git a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs index 8e88178..830be27 100644 --- a/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs +++ b/programs/cp-swap/src/instructions/admin/collect_protocol_fee.rs @@ -2,10 +2,10 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::*; use anchor_lang::prelude::*; -use light_token_sdk::anchor::anchor_spl::token::Token; -use light_token_sdk::anchor::anchor_spl::token_interface::Mint; -use light_token_sdk::anchor::anchor_spl::token_interface::Token2022; -use light_token_sdk::anchor::anchor_spl::token_interface::TokenAccount; +use light_anchor_spl::token::Token; +use light_anchor_spl::token_interface::Mint; +use light_anchor_spl::token_interface::Token2022; +use light_anchor_spl::token_interface::TokenAccount; #[derive(Accounts)] pub struct CollectProtocolFee<'info> { diff --git a/programs/cp-swap/src/instructions/deposit.rs b/programs/cp-swap/src/instructions/deposit.rs index a23e2a2..814038b 100644 --- a/programs/cp-swap/src/instructions/deposit.rs +++ b/programs/cp-swap/src/instructions/deposit.rs @@ -4,10 +4,10 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; -use light_token_sdk::anchor::anchor_spl::token::Token; -use light_token_sdk::anchor::anchor_spl::token_interface::Token2022; -use light_token_sdk::token::MintToCpi; -use light_token_sdk::anchor::anchor_spl::token_interface::{TokenAccount, Mint,TokenInterface}; +use light_anchor_spl::token::Token; +use light_anchor_spl::token_interface::Token2022; +use light_token::instruction::MintToCpi; +use light_anchor_spl::token_interface::{TokenAccount, Mint,TokenInterface}; #[derive(Accounts)] pub struct Deposit<'info> { diff --git a/programs/cp-swap/src/instructions/initialize.rs b/programs/cp-swap/src/instructions/initialize.rs index d042798..111bfbc 100644 --- a/programs/cp-swap/src/instructions/initialize.rs +++ b/programs/cp-swap/src/instructions/initialize.rs @@ -7,16 +7,16 @@ use anchor_lang::{ prelude::*, solana_program::{clock, program::invoke, system_instruction}, }; -use light_token_sdk::anchor::anchor_spl::{ +use light_anchor_spl::{ associated_token::AssociatedToken, token::spl_token, token::Token, token_interface::{Mint, TokenAccount, TokenInterface}, }; use light_sdk::interface::CreateAccountsProof; -use light_token_sdk::anchor::LightAccounts; -use light_token_sdk::{ - token::{ +use light_token::anchor::LightAccounts; +use light_token::{ + instruction::{ CreateTokenAccountCpi, CreateTokenAtaCpi, MintToCpi, COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR as LIGHT_TOKEN_RENT_SPONSOR, }, diff --git a/programs/cp-swap/src/instructions/swap_base_input.rs b/programs/cp-swap/src/instructions/swap_base_input.rs index a45ffde..1c686a0 100644 --- a/programs/cp-swap/src/instructions/swap_base_input.rs +++ b/programs/cp-swap/src/instructions/swap_base_input.rs @@ -5,7 +5,7 @@ use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; use anchor_lang::solana_program; -use light_token_sdk::anchor::anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; +use light_anchor_spl::token_interface::{Mint, TokenAccount, TokenInterface}; #[derive(Accounts)] pub struct Swap<'info> { diff --git a/programs/cp-swap/src/instructions/withdraw.rs b/programs/cp-swap/src/instructions/withdraw.rs index 4fc0733..484d08b 100644 --- a/programs/cp-swap/src/instructions/withdraw.rs +++ b/programs/cp-swap/src/instructions/withdraw.rs @@ -4,12 +4,12 @@ use crate::error::ErrorCode; use crate::states::*; use crate::utils::token::*; use anchor_lang::prelude::*; -use light_token_sdk::anchor::anchor_spl::{ +use light_anchor_spl::{ memo::spl_memo, token::Token, token_interface::{Mint, Token2022, TokenAccount, TokenInterface}, }; -use light_token_sdk::token::BurnCpi; +use light_token::instruction::BurnCpi; #[derive(Accounts)] pub struct Withdraw<'info> { diff --git a/programs/cp-swap/src/lib.rs b/programs/cp-swap/src/lib.rs index 6636db2..2d80571 100644 --- a/programs/cp-swap/src/lib.rs +++ b/programs/cp-swap/src/lib.rs @@ -14,7 +14,7 @@ pub use crate::states::{ }; use anchor_lang::prelude::*; use instructions::*; -use light_token_sdk::anchor::{ +use light_token::anchor::{ derive_light_cpi_signer, derive_light_rent_sponsor_pda, light_program, CpiSigner, }; diff --git a/programs/cp-swap/src/states/oracle.rs b/programs/cp-swap/src/states/oracle.rs index 1d714f0..2b4e798 100644 --- a/programs/cp-swap/src/states/oracle.rs +++ b/programs/cp-swap/src/states/oracle.rs @@ -1,6 +1,6 @@ use anchor_lang::prelude::*; use light_sdk::LightDiscriminator; -use light_token_sdk::anchor::{CompressionInfo, LightAccount}; +use light_token::anchor::{CompressionInfo, LightAccount}; #[cfg(test)] use std::time::{SystemTime, UNIX_EPOCH}; diff --git a/programs/cp-swap/src/states/pool.rs b/programs/cp-swap/src/states/pool.rs index 200be7d..b23db7b 100644 --- a/programs/cp-swap/src/states/pool.rs +++ b/programs/cp-swap/src/states/pool.rs @@ -1,7 +1,7 @@ use anchor_lang::prelude::*; -use light_token_sdk::anchor::anchor_spl::token_interface::Mint; +use light_anchor_spl::token_interface::Mint; use light_sdk::LightDiscriminator; -use light_token_sdk::anchor::{CompressionInfo, LightAccount}; +use light_token::anchor::{CompressionInfo, LightAccount}; use std::ops::{BitAnd, BitOr, BitXor}; pub const POOL_SEED: &str = "pool"; diff --git a/programs/cp-swap/src/utils/token.rs b/programs/cp-swap/src/utils/token.rs index d5fdbb3..1849b79 100644 --- a/programs/cp-swap/src/utils/token.rs +++ b/programs/cp-swap/src/utils/token.rs @@ -1,12 +1,12 @@ use crate::error::ErrorCode; use anchor_lang::{prelude::*, system_program}; -use light_token_sdk::anchor::anchor_spl::{ +use light_anchor_spl::{ token::{Token, TokenAccount}, token_2022, token_interface::{initialize_account3, InitializeAccount3, Mint}, }; use light_sdk::constants::LIGHT_TOKEN_PROGRAM_ID; -use light_token_sdk::token::TransferInterfaceCpi; +use light_token::instruction::TransferInterfaceCpi; use spl_token_2022::{ self, extension::{ diff --git a/programs/cp-swap/tests/helpers.rs b/programs/cp-swap/tests/helpers.rs index 3336708..b0e4b32 100644 --- a/programs/cp-swap/tests/helpers.rs +++ b/programs/cp-swap/tests/helpers.rs @@ -13,9 +13,9 @@ use light_program_test::{ program_test::{setup_mock_program_data, LightProgramTest, TestRpc}, Indexer, ProgramTestConfig, Rpc, }; -use light_token_sdk::{ +use light_token::{ constants::CPI_AUTHORITY_PDA, - token::{ + instruction::{ find_mint_address, get_associated_token_address_and_bump, CreateAssociatedTokenAccount, CreateMint, CreateMintParams, MintTo, COMPRESSIBLE_CONFIG_V1, RENT_SPONSOR as LIGHT_TOKEN_RENT_SPONSOR, @@ -32,7 +32,7 @@ use solana_keypair::Keypair; use solana_pubkey::Pubkey; use solana_signer::Signer; use solana_sdk::{program_pack::Pack, signature::SeedDerivable}; -use light_token_sdk::anchor::anchor_spl::memo::spl_memo; +use light_anchor_spl::memo::spl_memo; use spl_token_2022; @@ -129,7 +129,7 @@ pub async fn setup_create_mint( let address_tree = rpc.get_address_tree_v2(); let output_queue = rpc.get_random_state_tree_info().unwrap().queue; - let compression_address = light_token_sdk::token::derive_mint_compressed_address( + let compression_address = light_token::instruction::derive_mint_compressed_address( &mint_seed.pubkey(), &address_tree.tree, ); @@ -628,7 +628,7 @@ pub fn build_initialize_instruction( token_program: spl_token::id(), token_0_program: light_token_program_id(), token_1_program: light_token_program_id(), - associated_token_program: light_token_sdk::anchor::anchor_spl::associated_token::ID, + associated_token_program: light_anchor_spl::associated_token::ID, system_program: solana_sdk::system_program::ID, rent: solana_sdk::sysvar::rent::ID, compression_config: config_pda, diff --git a/programs/cp-swap/tests/program.rs b/programs/cp-swap/tests/program.rs index 861670b..3af4711 100644 --- a/programs/cp-swap/tests/program.rs +++ b/programs/cp-swap/tests/program.rs @@ -13,7 +13,7 @@ use light_client::interface::{ TokenAccountInterface, }; use light_sdk::LightDiscriminator; -use light_token_sdk::compat::{CTokenData, TokenData}; +use light_token::compat::{CTokenData, TokenData}; use raydium_cp_swap::instructions::initialize::LP_MINT_SIGNER_SEED; use raydium_cp_swap::{ raydium_cp_swap::{LightAccountVariant, TokenAccountVariant}, @@ -203,7 +203,7 @@ impl CpSwapSdk { } else { None }, - state: light_token_sdk::compat::AccountState::Initialized, + state: light_token::compat::AccountState::Initialized, tlv: None, }; From 954f679699dbdfe9711308c8ae9fbd21e69db8aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= Date: Fri, 23 Jan 2026 18:09:44 +0000 Subject: [PATCH 15/15] chore: update readme Updated README to clarify SDK's rent-exemption sponsorship and migration process. --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 8e1aa02..47dfa9a 100644 --- a/README.md +++ b/README.md @@ -6,15 +6,15 @@ Fork of Raydium AMM that creates markets without paying rent-exemption. - no extra CU overhead on hot paths - no UX diff on hot paths -The SDK pays rent-exemption for: +The SDK sponsors rent-exemption on behalf of your users for: - PoolState - Token Vaults +- LP Mint account - User ATAs -- LP Mint - -Migrating to Rent Free accounts is easy because Light-token is a superset of SPL-token. +Upgrading your program accounts to be rent-free is fast and straightforward because Light-token is a superset of SPL-token. See [here](https://www.zkcompression.com/light-token/defi/programs) for a guide. +For hands-on support, join the [Developer Discord](https://discord.com/invite/7cJ8BhAXhu). ## Environment Setup