From 7777018ffa4284f329f896dd9faaf8ee1900d118 Mon Sep 17 00:00:00 2001 From: lispking Date: Wed, 7 Jan 2026 11:48:39 +0800 Subject: [PATCH 1/6] Add mollusk testing framework and refactor imports to nested module syntax - Add mollusk module with ProgramLoader and TestContext - Add helpers module for utility functions - Refactor all stage imports to use nested module syntax - Update dependencies in Cargo.toml --- Cargo.lock | 3064 ++++++++++++++++++++++- Cargo.toml | 19 + src/helpers.rs | 840 +++++++ src/main.rs | 2 + src/mollusk/mod.rs | 99 + src/mollusk/program_loader.rs | 245 ++ src/mollusk/test_context.rs | 253 ++ src/stages/base/at4.rs | 2 +- src/stages/base/be1.rs | 2 +- src/stages/base/cp6.rs | 2 +- src/stages/base/rs2.rs | 2 +- src/stages/base/sm3.rs | 2 +- src/stages/base/st5.rs | 2 +- src/stages/base/tt7.rs | 2 +- src/stages/extensions/cpi/cp1.rs | 2 +- src/stages/extensions/cpi/cp2.rs | 2 +- src/stages/extensions/cpi/cp3.rs | 2 +- src/stages/extensions/cpi/cp4.rs | 2 +- src/stages/extensions/deployment/de1.rs | 2 +- src/stages/extensions/deployment/de2.rs | 2 +- src/stages/extensions/deployment/de3.rs | 2 +- src/stages/extensions/deployment/de4.rs | 2 +- src/stages/extensions/error/er1.rs | 2 +- src/stages/extensions/error/er2.rs | 2 +- src/stages/extensions/error/er3.rs | 2 +- src/stages/extensions/error/er4.rs | 2 +- src/stages/extensions/make_offer/mo1.rs | 2 +- src/stages/extensions/make_offer/mo2.rs | 2 +- src/stages/extensions/make_offer/mo3.rs | 2 +- src/stages/extensions/make_offer/mo4.rs | 2 +- src/stages/extensions/offer/of1.rs | 2 +- src/stages/extensions/offer/of2.rs | 2 +- src/stages/extensions/offer/of3.rs | 2 +- src/stages/extensions/offer/of4.rs | 2 +- src/stages/extensions/pda/pa1.rs | 2 +- src/stages/extensions/pda/pa2.rs | 2 +- src/stages/extensions/pda/pa3.rs | 2 +- src/stages/extensions/pda/pa4.rs | 2 +- src/stages/extensions/security/se1.rs | 2 +- src/stages/extensions/security/se2.rs | 2 +- src/stages/extensions/security/se3.rs | 2 +- src/stages/extensions/security/se4.rs | 2 +- src/stages/extensions/take_offer/to1.rs | 2 +- src/stages/extensions/take_offer/to2.rs | 2 +- src/stages/extensions/take_offer/to3.rs | 2 +- src/stages/extensions/take_offer/to4.rs | 2 +- src/stages/extensions/testing/te1.rs | 2 +- src/stages/extensions/testing/te2.rs | 2 +- src/stages/extensions/testing/te3.rs | 2 +- src/stages/extensions/testing/te4.rs | 2 +- src/stages/extensions/vault/va1.rs | 2 +- src/stages/extensions/vault/va2.rs | 2 +- src/stages/extensions/vault/va3.rs | 2 +- src/stages/extensions/vault/va4.rs | 2 +- 54 files changed, 4524 insertions(+), 92 deletions(-) create mode 100644 src/helpers.rs create mode 100644 src/mollusk/mod.rs create mode 100644 src/mollusk/program_loader.rs create mode 100644 src/mollusk/test_context.rs diff --git a/Cargo.lock b/Cargo.lock index a234d3c..ec52e5f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,95 +2,2858 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "agave-feature-set" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d4a155f30015eab7e4a9ba2bcf9e1078c70707230668dc577e41830d97d0313" +dependencies = [ + "ahash", + "solana-epoch-schedule", + "solana-hash 3.1.0", + "solana-pubkey 3.0.0", + "solana-sha256-hasher", + "solana-svm-feature-set", +] + +[[package]] +name = "agave-syscalls" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c18d9f932913dc5c7a6258b453ce7d42ed465001cd054b2a5f2c8e8d2a5e2bc0" +dependencies = [ + "bincode", + "libsecp256k1", + "num-traits", + "solana-account", + "solana-account-info", + "solana-big-mod-exp", + "solana-blake3-hasher", + "solana-bn254", + "solana-clock", + "solana-cpi", + "solana-curve25519", + "solana-hash 3.1.0", + "solana-instruction", + "solana-keccak-hasher", + "solana-loader-v3-interface", + "solana-poseidon", + "solana-program-entrypoint", + "solana-program-runtime", + "solana-pubkey 3.0.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-secp256k1-recover", + "solana-sha256-hasher", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-type-overrides", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.17", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anstream" +version = "0.6.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "ark-bn254" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-std 0.4.0", +] + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe", + "fnv", + "hashbrown 0.15.5", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive 0.4.2", + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "ascii" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" + +[[package]] +name = "base64" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" + +[[package]] +name = "base64ct" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d809780667f4410e7c41b07f52439b94d2bdf8528eeedc287fa38d3b7f95d82" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitflags" +version = "2.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" + +[[package]] +name = "blake3" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" +dependencies = [ + "feature-probe", + "serde", +] + +[[package]] +name = "bytemuck" +version = "1.24.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.2.51" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" +dependencies = [ + "find-msvc-tools", + "shlex", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "colorchoice" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" + +[[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 = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + +[[package]] +name = "constant_time_eq" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", + "serde", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "der" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +dependencies = [ + "const-oid", + "zeroize", +] + +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "eager" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" + +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "enum-iterator" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" +dependencies = [ + "enum-iterator-derive", +] + +[[package]] +name = "enum-iterator-derive" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "env_filter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + +[[package]] +name = "find-msvc-tools" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + +[[package]] +name = "five8" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" +dependencies = [ + "five8_core 0.1.2", +] + +[[package]] +name = "five8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" +dependencies = [ + "five8_core 1.0.0", +] + +[[package]] +name = "five8_const" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core 1.0.0", +] + +[[package]] +name = "five8_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" + +[[package]] +name = "five8_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +dependencies = [ + "ahash", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "allocator-api2", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "indexmap" +version = "2.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" + +[[package]] +name = "jiff" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.9", + "signature", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.179" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5a2d376baa530d1238d133232d15e239abad80d05838b4b59354e5268af431f" + +[[package]] +name = "libsecp256k1" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" +dependencies = [ + "arrayref", + "base64 0.12.3", + "digest 0.9.0", + "libsecp256k1-core", + "libsecp256k1-gen-ecmult", + "libsecp256k1-gen-genmult", + "rand 0.7.3", + "serde", + "sha2 0.9.9", +] + +[[package]] +name = "libsecp256k1-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" +dependencies = [ + "crunchy", + "digest 0.9.0", + "subtle", +] + +[[package]] +name = "libsecp256k1-gen-ecmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "libsecp256k1-gen-genmult" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" +dependencies = [ + "libsecp256k1-core", +] + +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ff 0.4.2", + "num-bigint 0.4.6", + "thiserror 1.0.69", +] + +[[package]] +name = "light-poseidon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a1ccadd0bb5a32c196da536fd72c59183de24a055f6bf0513bf845fefab862" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ff 0.5.0", + "num-bigint 0.4.6", + "thiserror 1.0.69", +] + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "memchr" +version = "2.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" + +[[package]] +name = "mollusk-svm" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57bd87f57490db674ffc141816c686785645f39c96cbd4416b76ed24f68e7ea3" +dependencies = [ + "agave-feature-set", + "agave-syscalls", + "bincode", + "mollusk-svm-error", + "mollusk-svm-result", + "solana-account", + "solana-bpf-loader-program", + "solana-clock", + "solana-compute-budget", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-hash 3.1.0", + "solana-instruction", + "solana-instruction-error", + "solana-instructions-sysvar", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-logger", + "solana-message", + "solana-precompile-error", + "solana-program-error", + "solana-program-runtime", + "solana-pubkey 4.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-log-collector", + "solana-svm-timings", + "solana-svm-transaction", + "solana-system-program", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "solana-transaction-error", +] + +[[package]] +name = "mollusk-svm-error" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70625b18d5a95041df7d218538da2520bc5a709a755db3885ff5e16baab1d408" +dependencies = [ + "solana-pubkey 4.0.0", + "thiserror 1.0.69", +] + +[[package]] +name = "mollusk-svm-programs-token" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "522e167efd4875c627928d126319bca254e5643366612dea9f42e4d0fe38bfc6" +dependencies = [ + "mollusk-svm", + "solana-account", + "solana-program-pack", + "solana-pubkey 4.0.0", + "solana-rent", + "spl-associated-token-account-interface", + "spl-token-interface", +] + +[[package]] +name = "mollusk-svm-result" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7adc27e15c35ce197850ced1cce6ebbf15dac6e163c575198f68fc060a8c3814" +dependencies = [ + "solana-account", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.0.0", + "solana-rent", + "solana-transaction-error", +] + +[[package]] +name = "num" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" +dependencies = [ + "num-bigint 0.2.6", + "num-complex", + "num-integer", + "num-iter", + "num-rational", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + +[[package]] +name = "num-complex" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "num-integer" +version = "0.1.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" +dependencies = [ + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" +dependencies = [ + "autocfg", + "num-bigint 0.2.6", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opaque-debug" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percentage" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" +dependencies = [ + "num", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "portable-atomic" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" + +[[package]] +name = "portable-atomic-util" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.101" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qualifier_attr" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "quote" +version = "1.0.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core 0.5.1", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.16", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core 0.5.1", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "regex" +version = "1.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rustc-demangle" +version = "0.1.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" + +[[package]] +name = "rustc_version" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_bytes" +version = "0.11.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +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.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "serde_json" +version = "1.0.143" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + +[[package]] +name = "sha2" +version = "0.10.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest 0.10.7", +] + +[[package]] +name = "sha3" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +dependencies = [ + "digest 0.10.7", + "keccak", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "solana-account" +version = "3.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60e0ac2a81ae17e1b3570deb50242ab4cfde50b848b898f57288b6271cc7b71f" +dependencies = [ + "bincode", + "qualifier_attr", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-instruction-error", + "solana-pubkey 4.0.0", + "solana-sdk-ids", + "solana-sysvar", +] + +[[package]] +name = "solana-account-info" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" +dependencies = [ + "solana-address 2.0.0", + "solana-program-error", + "solana-program-memory", +] + +[[package]] +name = "solana-address" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" +dependencies = [ + "solana-address 2.0.0", +] + +[[package]] +name = "solana-address" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37320fd2945c5d654b2c6210624a52d66c3f1f73b653ed211ab91a703b35bdd" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8 1.0.0", + "five8_const", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-sanitize", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-atomic-u64" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a933ff1e50aff72d02173cfcd7511bd8540b027ee720b75f353f594f834216d0" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-bincode" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278a1a5bad62cd9da89ac8d4b7ec444e83caa8ae96aa656dfc27684b28d49a5d" +dependencies = [ + "bincode", + "serde_core", + "solana-instruction-error", +] + +[[package]] +name = "solana-blake3-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7116e1d942a2432ca3f514625104757ab8a56233787e95144c93950029e31176" +dependencies = [ + "blake3", + "solana-define-syscall 4.0.1", + "solana-hash 4.0.1", +] + +[[package]] +name = "solana-bn254" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d08583be08d2d5f19aa21efbb6fbdb968ba7fd0de74562441437a7d776772bf" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "bytemuck", + "solana-define-syscall 3.0.0", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-bpf-loader-program" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7ea871a1450cc7a2b459b18a3bdc0f3db23aab283b19c969a76c225f35d8a69" +dependencies = [ + "agave-syscalls", + "bincode", + "qualifier_attr", + "solana-account", + "solana-bincode", + "solana-clock", + "solana-instruction", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-packet", + "solana-program-entrypoint", + "solana-program-runtime", + "solana-pubkey 3.0.0", + "solana-sbpf", + "solana-sdk-ids", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-type-overrides", + "solana-system-interface", + "solana-transaction-context", +] + +[[package]] +name = "solana-clock" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-compute-budget" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "864dc20438899a9e942e4d5188e615396426c051000842add53c08da2f51d548" +dependencies = [ + "solana-fee-structure", + "solana-program-runtime", +] + +[[package]] +name = "solana-cpi" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-instruction", + "solana-program-error", + "solana-pubkey 4.0.0", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebca352e7716ff1a0877272f87c772c958489c1d568a92d318dc0c75939d2884" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "solana-define-syscall 3.0.0", + "subtle", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-define-syscall" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" + +[[package]] +name = "solana-define-syscall" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" + +[[package]] +name = "solana-epoch-rewards" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-schedule" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5481e72cc4d52c169db73e4c0cd16de8bc943078aac587ec4817a75cc6388f" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a73cc03ca4bed871ca174558108835f8323e85917bb38b9c81c7af2ab853efe" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-structure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2abdb1223eea8ec64136f39cb1ffcf257e00f915c957c35c0dd9e3f4e700b0" + +[[package]] +name = "solana-hash" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" +dependencies = [ + "solana-hash 4.0.1", +] + +[[package]] +name = "solana-hash" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a5d48a6ee7b91fc7b998944ab026ed7b3e2fc8ee3bc58452644a86c2648152f" +dependencies = [ + "borsh", + "bytemuck", + "bytemuck_derive", + "five8 1.0.0", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", +] + +[[package]] +name = "solana-instruction" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee1b699a2c1518028a9982e255e0eca10c44d90006542d9d7f9f40dbce3f7c78" +dependencies = [ + "bincode", + "borsh", + "serde", + "serde_derive", + "solana-define-syscall 4.0.1", + "solana-instruction-error", + "solana-pubkey 4.0.0", +] + +[[package]] +name = "solana-instruction-error" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b04259e03c05faf38a8c24217b5cfe4c90572ae6184ab49cddb1584fdd756d3f" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-program-error", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" +dependencies = [ + "bitflags", + "solana-account-info", + "solana-instruction", + "solana-instruction-error", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" +dependencies = [ + "sha3", + "solana-define-syscall 4.0.1", + "solana-hash 4.0.1", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "6.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dee44c9b1328c5c712c68966fb8de07b47f3e7bac006e74ddd1bb053d3e46e5d" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c948b33ff81fa89699911b207059e493defdba9647eaf18f23abdf3674e0fb" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-logger" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef7421d1092680d72065edbf5c7605856719b021bf5f173656c71febcdd5d003" +dependencies = [ + "env_logger", + "lazy_static", + "libc", + "log", + "signal-hook", +] + +[[package]] +name = "solana-message" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85666605c9fd727f865ed381665db0a8fc29f984a030ecc1e40f43bfb2541623" +dependencies = [ + "lazy_static", + "solana-address 1.1.0", + "solana-hash 3.1.0", + "solana-instruction", + "solana-sanitize", + "solana-sdk-ids", + "solana-transaction-error", +] + +[[package]] +name = "solana-msg" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "264275c556ea7e22b9d3f87d56305546a38d4eee8ec884f3b126236cb7dcbbb4" +dependencies = [ + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-nonce" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abbdc6c8caf1c08db9f36a50967539d0f72b9f1d4aea04fec5430f532e5afadc" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash 3.1.0", + "solana-pubkey 3.0.0", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-nonce-account" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805fd25b29e5a1a0e6c3dd6320c9da80f275fbe4ff6e392617c303a2085c435e" +dependencies = [ + "solana-account", + "solana-hash 3.1.0", + "solana-nonce", + "solana-sdk-ids", +] + +[[package]] +name = "solana-packet" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edf2f25743c95229ac0fdc32f8f5893ef738dbf332c669e9861d33ddb0f469d" +dependencies = [ + "bitflags", +] + +[[package]] +name = "solana-poseidon" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa6f89aa38e3010f343900e154a319a20276713758dad5a732fe52afd04dba87" +dependencies = [ + "ark-bn254 0.4.0", + "ark-bn254 0.5.0", + "light-poseidon 0.2.0", + "light-poseidon 0.4.0", + "solana-define-syscall 3.0.0", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-precompile-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafcd950de74c6c39d55dc8ca108bbb007799842ab370ef26cf45a34453c31e1" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-program-entrypoint" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" +dependencies = [ + "solana-account-info", + "solana-define-syscall 4.0.1", + "solana-program-error", + "solana-pubkey 4.0.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" + +[[package]] +name = "solana-program-memory" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4068648649653c2c50546e9a7fb761791b5ab0cda054c771bb5808d3a4b9eb52" +dependencies = [ + "solana-define-syscall 4.0.1", +] + +[[package]] +name = "solana-program-option" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e7b4ddb464f274deb4a497712664c3b612e3f5f82471d4e47710fc4ab1c3095" + +[[package]] +name = "solana-program-pack" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c169359de21f6034a63ebf96d6b380980307df17a8d371344ff04a883ec4e9d0" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-program-runtime" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8738863de0f78036affb1d1dcc4747bf7783f212dc3a646e19ae827ce8f7245d" +dependencies = [ + "base64 0.22.1", + "bincode", + "itertools 0.12.1", + "log", + "percentage", + "rand 0.8.5", + "serde", + "solana-account", + "solana-account-info", + "solana-clock", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-structure", + "solana-hash 3.1.0", + "solana-instruction", + "solana-last-restart-slot", + "solana-loader-v3-interface", + "solana-program-entrypoint", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", + "solana-slot-hashes", + "solana-stable-layout", + "solana-stake-interface", + "solana-svm-callback", + "solana-svm-feature-set", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-transaction", + "solana-svm-type-overrides", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", + "solana-transaction-context", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "solana-address 1.1.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6f7104d456b58e1418c21a8581e89810278d1190f70f27ece7fc0b2c9282a57" +dependencies = [ + "solana-address 2.0.0", +] + +[[package]] +name = "solana-rent" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sbpf" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b15b079e08471a9dbfe1e48b2c7439c85aa2a055cbd54eddd8bd257b0a7dbb29" +dependencies = [ + "byteorder", + "combine", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "thiserror 2.0.17", + "winapi", +] + +[[package]] +name = "solana-sdk-ids" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" +dependencies = [ + "solana-address 2.0.0", +] + +[[package]] +name = "solana-sdk-macro" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9de18cfdab99eeb940fbedd8c981fa130c0d76252da75d05446f22fae8b51932" +dependencies = [ + "k256", + "solana-define-syscall 4.0.1", + "thiserror 2.0.17", +] [[package]] -name = "memchr" -version = "2.7.5" +name = "solana-serialize-utils" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" +checksum = "56e41dd8feea239516c623a02f0a81c2367f4b604d7965237fed0751aeec33ed" +dependencies = [ + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-sanitize", +] [[package]] -name = "once_cell" -version = "1.21.3" +name = "solana-sha256-hasher" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall 4.0.1", + "solana-hash 4.0.1", +] [[package]] -name = "pin-project-lite" -version = "0.2.16" +name = "solana-signature" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "4bb8057cc0e9f7b5e89883d49de6f407df655bb6f3a71d0b7baf9986a2218fd9" +dependencies = [ + "five8 0.2.1", + "solana-sanitize", +] [[package]] -name = "proc-macro2" -version = "1.0.101" +name = "solana-slot-hashes" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" +checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" dependencies = [ - "unicode-ident", + "serde", + "serde_derive", + "solana-hash 3.1.0", + "solana-sdk-ids", + "solana-sysvar-id", ] [[package]] -name = "quote" -version = "1.0.40" +name = "solana-slot-history" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "f914f6b108f5bba14a280b458d023e3621c9973f27f015a4d755b50e88d89e97" dependencies = [ - "proc-macro2", + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", ] [[package]] -name = "ryu" -version = "1.0.20" +name = "solana-stable-layout" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" +dependencies = [ + "solana-instruction", + "solana-pubkey 3.0.0", +] [[package]] -name = "serde" -version = "1.0.219" +name = "solana-stake-interface" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0e2c6ed6606019b4e29e69dbaba95b11854410e5347d525002456dbbb786b6" +checksum = "b9bc26191b533f9a6e5a14cca05174119819ced680a80febff2f5051a713f0db" dependencies = [ + "num-traits", + "serde", "serde_derive", + "solana-clock", + "solana-cpi", + "solana-instruction", + "solana-program-error", + "solana-pubkey 3.0.0", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", ] [[package]] -name = "serde_derive" -version = "1.0.219" +name = "solana-svm-callback" +version = "3.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b0276cf7f2c73365f7157c8123c21cd9a50fbbd844757af28ca1f5925fc2a00" +checksum = "5ace45d73cb921cc451f497a48df290bd784a65c987570a67a4c9f0d0eb11e56" dependencies = [ - "proc-macro2", - "quote", - "syn", + "solana-account", + "solana-clock", + "solana-precompile-error", + "solana-pubkey 3.0.0", ] [[package]] -name = "serde_json" -version = "1.0.143" +name = "solana-svm-feature-set" +version = "3.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" +checksum = "ca638d19ace892ef2bf31af74897fa8828ebf9d6418b46771c67857e66cf5c97" + +[[package]] +name = "solana-svm-log-collector" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d12ad2fa212fcfec7c3fcf94afc51ebe71ff2e757df6c3148a3f0bd8c79e31e" dependencies = [ - "itoa", - "memchr", - "ryu", - "serde", + "log", +] + +[[package]] +name = "solana-svm-measure" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9eaf2c082f2a54ec06fd3be215dc76329b1441f9bd3e2370ede699b54a554ab" + +[[package]] +name = "solana-svm-timings" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a619a2184b7f8e846a087b2ada41da6c494940f64c12eb6c6b8a869d8959fb" +dependencies = [ + "eager", + "enum-iterator", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-svm-transaction" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "206c4b0b8bae22e6bbcc0aff78069bb2f58804f8d953ca6622bc5a0ee82abc7b" +dependencies = [ + "solana-hash 3.1.0", + "solana-message", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-signature", + "solana-transaction", +] + +[[package]] +name = "solana-svm-type-overrides" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b30f2f7e41312046fb07a7f4de7bff814501b983f64a34805756ea76f08f6263" +dependencies = [ + "rand 0.8.5", ] [[package]] name = "solana-swap-program-tester" version = "0.1.0" dependencies = [ + "mollusk-svm", + "mollusk-svm-programs-token", "serde", "serde_json", + "sha2 0.10.9", + "solana-account", + "solana-instruction", + "solana-instruction-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 4.0.0", + "solana-rent", + "solana-system-program", + "spl-associated-token-account-interface", + "spl-token-interface", "tester", ] +[[package]] +name = "solana-system-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "solana-system-program" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3abee2737a4b1c578c8d4d3c63017350232f40f5826e47be1f9729ac1fd83f" +dependencies = [ + "bincode", + "log", + "serde", + "solana-account", + "solana-bincode", + "solana-fee-calculator", + "solana-instruction", + "solana-nonce", + "solana-nonce-account", + "solana-packet", + "solana-program-runtime", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "solana-svm-log-collector", + "solana-svm-type-overrides", + "solana-system-interface", + "solana-sysvar", + "solana-transaction-context", +] + +[[package]] +name = "solana-sysvar" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6690d3dd88f15c21edff68eb391ef8800df7a1f5cec84ee3e8d1abf05affdf74" +dependencies = [ + "base64 0.22.1", + "bincode", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall 4.0.1", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash 4.0.1", + "solana-instruction", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey 4.0.0", + "solana-rent", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" +dependencies = [ + "solana-address 2.0.0", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ceb2efbf427a91b884709ffac4dac29117752ce1e37e9ae04977e450aa0bb76" +dependencies = [ + "solana-address 2.0.0", + "solana-hash 4.0.1", + "solana-instruction", + "solana-instruction-error", + "solana-message", + "solana-sanitize", + "solana-sdk-ids", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-transaction-context" +version = "3.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "120863f5edd2f70338482e9719c630c88441f9499d796dbfc68f6d0fa92413df" +dependencies = [ + "bincode", + "qualifier_attr", + "serde", + "solana-account", + "solana-instruction", + "solana-instructions-sysvar", + "solana-pubkey 3.0.0", + "solana-rent", + "solana-sbpf", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4222065402340d7e6aec9dc3e54d22992ddcf923d91edcd815443c2bfca3144a" +dependencies = [ + "solana-instruction-error", + "solana-sanitize", +] + +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "spl-associated-token-account-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6433917b60441d68d99a17e121d9db0ea15a9a69c0e5afa34649cf5ba12612f" +dependencies = [ + "solana-instruction", + "solana-pubkey 3.0.0", +] + +[[package]] +name = "spl-token-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c564ac05a7c8d8b12e988a37d82695b5ba4db376d07ea98bc4882c81f96c7f3" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-instruction", + "solana-program-error", + "solana-program-option", + "solana-program-pack", + "solana-pubkey 3.0.0", + "solana-sdk-ids", + "thiserror 2.0.17", +] + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + [[package]] name = "syn" version = "2.0.106" @@ -109,28 +2872,93 @@ source = "git+https://github.com/stackclass/tester.git?tag=v0.4.0#ae5431317f0d39 dependencies = [ "serde", "serde_json", - "thiserror", + "thiserror 2.0.17", "tracing", ] [[package]] name = "thiserror" -version = "2.0.16" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +dependencies = [ + "thiserror-impl 2.0.17", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3467d614147380f2e4e374161426ff399c91084acd2363eaf549172b3d5e60c0" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.106", ] [[package]] name = "thiserror-impl" -version = "2.0.16" +version = "2.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c5e1be1c48b9172ee610da68fd9cd2770e7a4056cb3fc98710ee6906f0c7960" +checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", +] + +[[package]] +name = "tinyvec" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml_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.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "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]] @@ -152,7 +2980,7 @@ checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.106", ] [[package]] @@ -164,8 +2992,154 @@ dependencies = [ "once_cell", ] +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + [[package]] name = "unicode-ident" version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" + +[[package]] +name = "unreachable" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" +dependencies = [ + "void", +] + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.1+wasi-0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "zerocopy" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fabae64378cb18147bb18bca364e63bdbe72a0ffe4adf0addfec8aa166b2c56" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9c2d862265a8bb4471d87e033e730f536e2a285cc7cb05dbce09a2a97075f90" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] + +[[package]] +name = "zeroize" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.106", +] diff --git a/Cargo.toml b/Cargo.toml index 08b5755..7ebd00b 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -7,3 +7,22 @@ edition = "2024" tester = { git = "https://github.com/stackclass/tester.git", tag = "v0.4.0" } serde = { version = "1", features = ["derive"] } serde_json = "1" +sha2 = "0.10" + +# Mollusk dependencies +mollusk-svm = "0.9.0" +mollusk-svm-programs-token = "0.9.0" + +# Solana SDK dependencies +solana-account = "3.2.0" +solana-instruction = "3.0" +solana-instruction-error = "2.0" +solana-program-option = "3.0" +solana-pubkey = "4.0" +solana-program-pack = "3.0" +solana-rent = "3.0" +solana-system-program = "3.1.0" + +# SPL Token dependencies +spl-token-interface = "2.0.0" +spl-associated-token-account-interface = "2.0.0" diff --git a/src/helpers.rs b/src/helpers.rs new file mode 100644 index 0000000..4f64dab --- /dev/null +++ b/src/helpers.rs @@ -0,0 +1,840 @@ +// Copyright (c) The StackClass Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Helper functions for testing the swap program. + +use crate::mollusk::{ProgramLoadError, TestContextError, init_test_context, load_swap_program_id}; +use mollusk_svm::{program::keyed_account_for_system_program, result::Check}; +use mollusk_svm_programs_token::{associated_token, token}; +use sha2::{Digest, Sha256}; +use solana_account::Account; +use solana_instruction::{AccountMeta, Instruction}; +use solana_program_option::COption; +use solana_pubkey::Pubkey; +use spl_associated_token_account_interface::address::get_associated_token_address_with_program_id; +use spl_token_interface::state::{Account as TokenAccount, AccountState, Mint}; +use std::{convert::TryInto, path::Path}; + +/// Get the repository directory from environment variables. +/// +/// This function reads the `STACKCLASS_REPOSITORY_DIR` environment variable +/// and returns it as a Path. +/// +/// # Returns +/// +/// * `Ok(PathBuf)` - The repository directory path +/// * `Err(ProgramLoadError)` - If the environment variable is not set +pub fn get_repo_dir() -> Result { + std::env::var("STACKCLASS_REPOSITORY_DIR") + .map_err(|_| ProgramLoadError::RepoNotFound(std::path::PathBuf::from("Not set"))) + .map(std::path::PathBuf::from) +} + +/// Create a test error message for reporting to the user. +/// +/// # Arguments +/// +/// * `stage_name` - The name of the test stage +/// * `error` - The error that occurred +/// +/// # Returns +/// +/// * `String` - A formatted error message +pub fn format_test_error(stage_name: &str, error: &TestContextError) -> String { + format!("Test '{}' failed: {}", stage_name, error) +} + +/// Create a success message for reporting to the user. +/// +/// # Arguments +/// +/// * `stage_name` - The name of the test stage +/// +/// # Returns +/// +/// * `String` - A formatted success message +pub fn format_test_success(stage_name: &str) -> String { + format!("Test '{}' passed successfully", stage_name) +} + +/// Create a basic system account with lamports. +/// +/// # Arguments +/// +/// * `lamports` - The amount of lamports +/// +/// # Returns +/// +/// * `Account` - A system account +pub fn create_system_account(lamports: u64) -> Account { + Account { lamports, owner: solana_system_program::id(), ..Default::default() } +} + +/// Create a PDA (Program Derived Address) for the swap program. +/// +/// # Arguments +/// +/// * `seeds` - The seeds to derive the PDA from +/// * `program_id` - The program ID used for derivation +/// +/// # Returns +/// +/// * `(Pubkey, u8)` - The PDA public key and bump seed +pub fn create_pda(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address(seeds, program_id) +} + +/// Create a check for successful execution. +/// +/// # Returns +/// +/// * `Check` - A success check +pub fn success_check() -> Check<'static> { + Check::success() +} + +/// Create a check for account lamports. +/// +/// # Arguments +/// +/// * `pubkey` - The account public key +/// * `expected_lamports` - The expected lamports +/// +/// # Returns +/// +/// * `Check` - A lamports check +pub fn lamports_check(pubkey: &Pubkey, expected_lamports: u64) -> Check<'_> { + Check::account(pubkey).lamports(expected_lamports).build() +} + +/// Create a check for account data. +/// +/// # Arguments +/// +/// * `pubkey` - The account public key +/// * `expected_data` - The expected account data +/// +/// # Returns +/// +/// * `Check` - A data check +pub fn data_check<'a>(pubkey: &'a Pubkey, expected_data: &'a [u8]) -> Check<'a> { + Check::account(pubkey).data(expected_data).build() +} + +/// Create a check for account owner. +/// +/// # Arguments +/// +/// * `pubkey` - The account public key +/// * `expected_owner` - The expected owner +/// +/// # Returns +/// +/// * `Check` - An owner check +pub fn owner_check<'a>(pubkey: &'a Pubkey, expected_owner: &'a Pubkey) -> Check<'a> { + Check::account(pubkey).owner(expected_owner).build() +} + +/// Create a check for account executability. +/// +/// # Arguments +/// +/// * `pubkey` - The account public key +/// * `expected_executable` - The expected executability +/// +/// # Returns +/// +/// * `Check` - An executable check +pub fn executable_check(pubkey: &Pubkey, expected_executable: bool) -> Check<'_> { + Check::account(pubkey).executable(expected_executable).build() +} + +/// Convert a TestContextError to a tester::CaseError. +/// +/// # Arguments +/// +/// * `error` - The TestContextError to convert +/// +/// # Returns +/// +/// * `tester::CaseError` - The converted error +pub fn to_case_error(error: TestContextError) -> tester::CaseError { + Box::new(error) as Box +} + +/// Convert a ProgramLoadError to a tester::CaseError. +/// +/// # Arguments +/// +/// * `error` - The ProgramLoadError to convert +/// +/// # Returns +/// +/// * `tester::CaseError` - The converted error +pub fn to_case_error_from_load(error: crate::mollusk::ProgramLoadError) -> tester::CaseError { + Box::new(error) as Box +} + +/// Convert a TestContextError to a tester::CaseError (for use with map_err). +/// +/// This is a helper function for converting errors in a map_err context. +/// +/// # Arguments +/// +/// * `error` - The TestContextError to convert +/// +/// # Returns +/// +/// * `tester::CaseError` - The converted error +pub fn to_case_error_from_context(error: TestContextError) -> tester::CaseError { + Box::new(error) as Box +} + +/// Check if a program is available for testing. +/// +/// # Arguments +/// +/// * `repo_dir` - The repository directory +/// +/// # Returns +/// +/// * `Ok(())` - If the program is available +/// * `Err(tester::CaseError)` - If the program is not available +pub fn check_program_available(repo_dir: &Path) -> Result<(), tester::CaseError> { + use crate::mollusk::load_swap_program; + + match load_swap_program(repo_dir) { + Ok(_) => Ok(()), + Err(e) => Err(Box::new(e) as Box), + } +} + +/// Create a test instruction for the swap program. +/// +/// # Arguments +/// +/// * `program_id` - The swap program ID +/// * `data` - The instruction data +/// * `accounts` - The accounts to pass to the instruction +/// +/// # Returns +/// +/// * `Instruction` - A swap program instruction +pub fn create_swap_instruction( + program_id: Pubkey, + data: Vec, + accounts: Vec, +) -> Instruction { + Instruction::new_with_bytes(program_id, &data, accounts) +} + +const DEFAULT_OFFERED_AMOUNT: u64 = 1_000_000; +const DEFAULT_WANTED_AMOUNT: u64 = 1_000_000; +const DEFAULT_MINT_DECIMALS: u8 = 6; +const OFFER_SEED_PREFIX: &[u8] = b"offer"; + +#[derive(Debug, Clone)] +pub struct OfferData { + pub id: u64, + pub maker: Pubkey, + pub token_mint_a: Pubkey, + pub token_mint_b: Pubkey, + pub token_b_wanted_amount: u64, + pub bump: u8, +} + +pub struct SwapFixture { + context: crate::mollusk::SwapTestContext, + program_id: Pubkey, + pub maker: Pubkey, + pub taker: Pubkey, + pub token_mint_a: Pubkey, + pub token_mint_b: Pubkey, + pub maker_token_account_a: Pubkey, + pub maker_token_account_b: Pubkey, + pub taker_token_account_a: Pubkey, + pub taker_token_account_b: Pubkey, + pub offer_id: u64, + pub offer: Pubkey, + pub vault: Pubkey, + pub token_program: Pubkey, + pub associated_token_program: Pubkey, + pub offered_amount: u64, + pub wanted_amount: u64, + pub decimals_a: u8, +} + +impl SwapFixture { + pub fn new_default(repo_dir: &Path) -> Result { + Self::new_with_amounts( + repo_dir, + DEFAULT_OFFERED_AMOUNT, + DEFAULT_WANTED_AMOUNT, + DEFAULT_OFFERED_AMOUNT, + DEFAULT_WANTED_AMOUNT, + DEFAULT_MINT_DECIMALS, + ) + } + + pub fn new_with_amounts( + repo_dir: &Path, + offered_amount: u64, + wanted_amount: u64, + maker_balance_a: u64, + taker_balance_b: u64, + decimals: u8, + ) -> Result { + let mut context = init_test_context(repo_dir)?; + let program_id = context.program_id(); + + let (system_program_id, system_program_account) = keyed_account_for_system_program(); + context.add_account(system_program_id, system_program_account); + + let (token_program_id, token_program_account) = token::keyed_account(); + context.add_account(token_program_id, token_program_account); + + let (associated_program_id, associated_program_account) = associated_token::keyed_account(); + context.add_account(associated_program_id, associated_program_account); + + let maker = context.create_funded_account(1_000_000_000); + let taker = context.create_funded_account(1_000_000_000); + + let token_mint_a = Pubkey::new_unique(); + let token_mint_b = Pubkey::new_unique(); + + let mint_a = Mint { + mint_authority: COption::Some(maker), + supply: maker_balance_a, + decimals, + is_initialized: true, + freeze_authority: COption::None, + }; + let mint_b = Mint { + mint_authority: COption::Some(taker), + supply: taker_balance_b, + decimals, + is_initialized: true, + freeze_authority: COption::None, + }; + + context.add_account(token_mint_a, token::create_account_for_mint(mint_a)); + context.add_account(token_mint_b, token::create_account_for_mint(mint_b)); + + let maker_token_account_a = + get_associated_token_address_with_program_id(&maker, &token_mint_a, &token_program_id); + let maker_token_account_b = + get_associated_token_address_with_program_id(&maker, &token_mint_b, &token_program_id); + let taker_token_account_a = + get_associated_token_address_with_program_id(&taker, &token_mint_a, &token_program_id); + let taker_token_account_b = + get_associated_token_address_with_program_id(&taker, &token_mint_b, &token_program_id); + + context.add_account( + maker_token_account_a, + token::create_account_for_token_account(TokenAccount { + mint: token_mint_a, + owner: maker, + amount: maker_balance_a, + delegate: COption::None, + state: AccountState::Initialized, + is_native: COption::None, + delegated_amount: 0, + close_authority: COption::None, + }), + ); + + context.add_account( + maker_token_account_b, + token::create_account_for_token_account(TokenAccount { + mint: token_mint_b, + owner: maker, + amount: 0, + delegate: COption::None, + state: AccountState::Initialized, + is_native: COption::None, + delegated_amount: 0, + close_authority: COption::None, + }), + ); + + context.add_account( + taker_token_account_a, + token::create_account_for_token_account(TokenAccount { + mint: token_mint_a, + owner: taker, + amount: 0, + delegate: COption::None, + state: AccountState::Initialized, + is_native: COption::None, + delegated_amount: 0, + close_authority: COption::None, + }), + ); + + context.add_account( + taker_token_account_b, + token::create_account_for_token_account(TokenAccount { + mint: token_mint_b, + owner: taker, + amount: taker_balance_b, + delegate: COption::None, + state: AccountState::Initialized, + is_native: COption::None, + delegated_amount: 0, + close_authority: COption::None, + }), + ); + + let offer_id: i32 = 1; + let (offer, _bump) = Pubkey::find_program_address( + &[OFFER_SEED_PREFIX, maker.as_ref(), &offer_id.to_le_bytes()], + &program_id, + ); + let vault = + get_associated_token_address_with_program_id(&offer, &token_mint_a, &token_program_id); + + context.add_account(offer, empty_system_account()); + context.add_account(vault, empty_system_account()); + + Ok(Self { + context, + program_id, + maker, + taker, + token_mint_a, + token_mint_b, + maker_token_account_a, + maker_token_account_b, + taker_token_account_a, + taker_token_account_b, + offer_id: offer_id.try_into().unwrap(), + offer, + vault, + token_program: token_program_id, + associated_token_program: associated_program_id, + offered_amount, + wanted_amount, + decimals_a: decimals, + }) + } + + pub fn make_offer_instruction(&self) -> Instruction { + let data = build_make_offer_data(self.offer_id, self.offered_amount, self.wanted_amount); + create_swap_instruction( + self.program_id, + data, + vec![ + AccountMeta::new(self.maker, true), + AccountMeta::new_readonly(self.token_mint_a, false), + AccountMeta::new_readonly(self.token_mint_b, false), + AccountMeta::new(self.maker_token_account_a, false), + AccountMeta::new(self.offer, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_program::id(), false), + AccountMeta::new_readonly(self.token_program, false), + AccountMeta::new_readonly(self.associated_token_program, false), + ], + ) + } + + pub fn take_offer_instruction(&self) -> Instruction { + let data = build_take_offer_data(); + create_swap_instruction( + self.program_id, + data, + vec![ + AccountMeta::new(self.taker, true), + AccountMeta::new(self.maker, false), + AccountMeta::new_readonly(self.token_mint_a, false), + AccountMeta::new_readonly(self.token_mint_b, false), + AccountMeta::new(self.taker_token_account_a, false), + AccountMeta::new(self.taker_token_account_b, false), + AccountMeta::new(self.maker_token_account_b, false), + AccountMeta::new(self.offer, false), + AccountMeta::new(self.vault, false), + AccountMeta::new_readonly(solana_system_program::id(), false), + AccountMeta::new_readonly(self.token_program, false), + AccountMeta::new_readonly(self.associated_token_program, false), + ], + ) + } + + pub fn execute_make_offer(&mut self) -> Result<(), TestContextError> { + let instruction = self.make_offer_instruction(); + self.context.execute_instruction(&instruction) + } + + pub fn execute_take_offer(&mut self) -> Result<(), TestContextError> { + let instruction = self.take_offer_instruction(); + self.context.execute_instruction(&instruction) + } + + pub fn get_account(&self, pubkey: &Pubkey) -> Result { + self.context + .get_account(pubkey) + .ok_or_else(|| TestContextError::AccountNotFound(pubkey.to_string())) + } +} + +fn empty_system_account() -> Account { + Account { + lamports: 0, + owner: solana_system_program::id(), + data: Vec::new(), + ..Default::default() + } +} + +fn build_make_offer_data(id: u64, offered_amount: u64, wanted_amount: u64) -> Vec { + let mut data = Vec::with_capacity(32); + data.extend_from_slice(&anchor_discriminator("global:make_offer")); + data.extend_from_slice(&id.to_le_bytes()); + data.extend_from_slice(&offered_amount.to_le_bytes()); + data.extend_from_slice(&wanted_amount.to_le_bytes()); + data +} + +fn build_take_offer_data() -> Vec { + anchor_discriminator("global:take_offer").to_vec() +} + +fn anchor_discriminator(name: &str) -> [u8; 8] { + let mut hasher = Sha256::new(); + hasher.update(name.as_bytes()); + let hash = hasher.finalize(); + let mut out = [0u8; 8]; + out.copy_from_slice(&hash[..8]); + out +} + +fn read_pubkey(data: &[u8]) -> Result { + let bytes: [u8; 32] = data + .try_into() + .map_err(|_| TestContextError::ValidationError("Invalid pubkey bytes".to_string()))?; + Ok(Pubkey::new_from_array(bytes)) +} + +fn read_u64(data: &[u8]) -> Result { + let bytes: [u8; 8] = data + .try_into() + .map_err(|_| TestContextError::ValidationError("Invalid u64 bytes".to_string()))?; + Ok(u64::from_le_bytes(bytes)) +} + +fn token_account_amount(account: &Account) -> Result { + if account.data.len() < 72 { + return Err(TestContextError::ValidationError("Token account data too short".to_string())); + } + read_u64(&account.data[64..72]) +} + +fn token_account_owner(account: &Account) -> Result { + if account.data.len() < 64 { + return Err(TestContextError::ValidationError("Token account data too short".to_string())); + } + read_pubkey(&account.data[32..64]) +} + +fn token_account_mint(account: &Account) -> Result { + if account.data.len() < 32 { + return Err(TestContextError::ValidationError("Token account data too short".to_string())); + } + read_pubkey(&account.data[0..32]) +} + +fn offer_data_from_account(account: &Account) -> Result { + if account.data.len() < 8 + 8 + 32 + 32 + 32 + 8 + 1 { + return Err(TestContextError::ValidationError("Offer account data too short".to_string())); + } + let mut offset = 8; + let id = read_u64(&account.data[offset..offset + 8])?; + offset += 8; + let maker = read_pubkey(&account.data[offset..offset + 32])?; + offset += 32; + let token_mint_a = read_pubkey(&account.data[offset..offset + 32])?; + offset += 32; + let token_mint_b = read_pubkey(&account.data[offset..offset + 32])?; + offset += 32; + let token_b_wanted_amount = read_u64(&account.data[offset..offset + 8])?; + offset += 8; + let bump = account.data[offset]; + + Ok(OfferData { id, maker, token_mint_a, token_mint_b, token_b_wanted_amount, bump }) +} + +fn make_offer_success(fixture: &mut SwapFixture) -> Result<(), TestContextError> { + fixture.execute_make_offer() +} + +fn take_offer_success(fixture: &mut SwapFixture) -> Result<(), TestContextError> { + fixture.execute_take_offer() +} + +pub fn run_env_setup_check() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + if !repo_path.exists() { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::NotFound, + format!("Repository directory not found: {}", repo_path.display()), + )) as Box); + } + check_program_available(&repo_path)?; + run_make_offer_smoke(&repo_path) +} + +pub fn run_rust_basics_check() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + run_make_offer_smoke(&repo_path) +} + +pub fn run_solana_model_check() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + match fixture.execute_make_offer() { + Ok(()) => { + let offer_account = fixture.get_account(&fixture.offer)?; + if offer_account.owner != fixture.program_id { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Offer account owner does not match program id", + )) as Box); + } + Ok(()) + } + Err(TestContextError::ExecutionError(_)) => Ok(()), + Err(err) => Err(to_case_error(err)), + } +} + +pub fn run_anchor_try_check() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let program_id = load_swap_program_id(&repo_path).map_err(to_case_error_from_load)?; + if program_id == Pubkey::default() { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Program ID is still default", + )) as Box); + } + run_make_offer_smoke(&repo_path) +} + +pub fn run_spl_token_basics_check() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + let vault_account = fixture.get_account(&fixture.vault)?; + let vault_mint = token_account_mint(&vault_account).map_err(to_case_error_from_context)?; + if vault_mint != fixture.token_mint_a { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Vault mint mismatch", + )) as Box); + } + Ok(()) +} + +pub fn run_cpi_transfer_check() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + + let vault_account = fixture.get_account(&fixture.vault)?; + let vault_amount = token_account_amount(&vault_account).map_err(to_case_error_from_context)?; + if vault_amount != fixture.offered_amount { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Vault balance does not match offered amount", + )) as Box); + } + Ok(()) +} + +pub fn run_token_transfer_check() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + take_offer_success(&mut fixture).map_err(to_case_error)?; + + let taker_token_a = fixture.get_account(&fixture.taker_token_account_a)?; + let maker_token_b = fixture.get_account(&fixture.maker_token_account_b)?; + let taker_amount = token_account_amount(&taker_token_a).map_err(to_case_error_from_context)?; + let maker_amount = token_account_amount(&maker_token_b).map_err(to_case_error_from_context)?; + + if taker_amount != fixture.offered_amount || maker_amount != fixture.wanted_amount { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Token balances did not transfer as expected", + )) as Box); + } + + Ok(()) +} + +pub fn run_offer_checks() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + let offer_account = fixture.get_account(&fixture.offer)?; + let offer = offer_data_from_account(&offer_account).map_err(to_case_error_from_context)?; + + if offer.id != fixture.offer_id || + offer.maker != fixture.maker || + offer.token_mint_a != fixture.token_mint_a || + offer.token_mint_b != fixture.token_mint_b || + offer.token_b_wanted_amount != fixture.wanted_amount + { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Offer account data mismatch", + )) as Box); + } + + Ok(()) +} + +pub fn run_make_offer_checks() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + + let maker_token_account = fixture.get_account(&fixture.maker_token_account_a)?; + let vault_account = fixture.get_account(&fixture.vault)?; + + let maker_amount = + token_account_amount(&maker_token_account).map_err(to_case_error_from_context)?; + let vault_amount = token_account_amount(&vault_account).map_err(to_case_error_from_context)?; + + if maker_amount != 0 || vault_amount != fixture.offered_amount { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Make offer transfer did not move tokens to vault", + )) as Box); + } + + Ok(()) +} + +pub fn run_take_offer_checks() -> Result<(), tester::CaseError> { + run_token_transfer_check() +} + +pub fn run_pda_checks() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + let offer_account = fixture.get_account(&fixture.offer)?; + let offer = offer_data_from_account(&offer_account).map_err(to_case_error_from_context)?; + + let (expected_offer, bump) = Pubkey::find_program_address( + &[OFFER_SEED_PREFIX, fixture.maker.as_ref(), &fixture.offer_id.to_le_bytes()], + &fixture.program_id, + ); + + if expected_offer != fixture.offer || offer.bump != bump { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Offer PDA derivation mismatch", + )) as Box); + } + + Ok(()) +} + +pub fn run_vault_checks() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + + let vault_account = fixture.get_account(&fixture.vault)?; + let vault_owner = token_account_owner(&vault_account).map_err(to_case_error_from_context)?; + let vault_mint = token_account_mint(&vault_account).map_err(to_case_error_from_context)?; + + if vault_owner != fixture.offer || vault_mint != fixture.token_mint_a { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Vault ATA ownership or mint mismatch", + )) as Box); + } + + Ok(()) +} + +pub fn run_security_checks() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_default(&repo_path).map_err(to_case_error)?; + make_offer_success(&mut fixture).map_err(to_case_error)?; + + let mut bad_instruction = fixture.take_offer_instruction(); + bad_instruction.accounts[1] = AccountMeta::new(fixture.taker, false); + + match fixture.context.execute_instruction(&bad_instruction) { + Ok(()) => Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Security check failed: invalid maker accepted", + )) as Box), + Err(TestContextError::ExecutionError(_)) => Ok(()), + Err(err) => Err(to_case_error(err)), + } +} + +pub fn run_error_checks() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let mut fixture = SwapFixture::new_with_amounts( + &repo_path, + DEFAULT_OFFERED_AMOUNT, + DEFAULT_WANTED_AMOUNT, + 0, + DEFAULT_WANTED_AMOUNT, + DEFAULT_MINT_DECIMALS, + ) + .map_err(to_case_error)?; + + match fixture.execute_make_offer() { + Ok(()) => Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Expected make_offer to fail with insufficient funds", + )) as Box), + Err(TestContextError::ExecutionError(_)) => Ok(()), + Err(err) => Err(to_case_error(err)), + } +} + +pub fn run_cpi_checks() -> Result<(), tester::CaseError> { + run_cpi_transfer_check() +} + +pub fn run_testing_checks() -> Result<(), tester::CaseError> { + run_token_transfer_check() +} + +pub fn run_deployment_checks() -> Result<(), tester::CaseError> { + let repo_path = get_repo_dir().map_err(to_case_error_from_load)?; + let program_id = load_swap_program_id(&repo_path).map_err(to_case_error_from_load)?; + if program_id == Pubkey::default() { + return Err(Box::new(std::io::Error::new( + std::io::ErrorKind::InvalidData, + "Program ID is still default", + )) as Box); + } + run_make_offer_smoke(&repo_path) +} + +fn run_make_offer_smoke(repo_path: &Path) -> Result<(), tester::CaseError> { + let mut fixture = SwapFixture::new_default(repo_path).map_err(to_case_error)?; + match fixture.execute_make_offer() { + Ok(()) => Ok(()), + Err(TestContextError::ExecutionError(_)) => Ok(()), + Err(err) => Err(to_case_error(err)), + } +} diff --git a/src/main.rs b/src/main.rs index c54390d..a19d442 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,6 +13,8 @@ // limitations under the License. mod definition; +mod helpers; +mod mollusk; mod stages; use std::process::ExitCode; diff --git a/src/mollusk/mod.rs b/src/mollusk/mod.rs new file mode 100644 index 0000000..382937f --- /dev/null +++ b/src/mollusk/mod.rs @@ -0,0 +1,99 @@ +// Copyright (c) The StackClass Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Mollusk management module for the swap program tester. +//! +//! This module provides a wrapper around the Mollusk test harness to simplify +//! testing of the swap program. It handles program loading, account setup, +//! and instruction execution. + +pub mod program_loader; +pub mod test_context; + +pub use program_loader::{ProgramLoadError, load_swap_program, load_swap_program_id}; +pub use test_context::{SwapTestContext, TestContextError}; + +use mollusk_svm::Mollusk; +use solana_pubkey::Pubkey; +use std::path::Path; + +/// Create a new Mollusk instance for testing the swap program. +/// +/// This function attempts to load the compiled swap program from the +/// user's repository directory and creates a Mollusk instance configured +/// for testing. +/// +/// # Arguments +/// +/// * `repo_dir` - Path to the user's repository directory +/// * `program_id` - The swap program ID +/// +/// # Returns +/// +/// * `Ok(Mollusk)` - A configured Mollusk instance +/// * `Err(ProgramLoadError)` - If the program cannot be loaded +pub fn create_swap_mollusk( + repo_dir: &Path, + program_id: &Pubkey, +) -> Result { + let program_path = load_swap_program(repo_dir)?; + let program_name = program_path.file_stem().and_then(|stem| stem.to_str()).unwrap_or("swap"); + + let program_dir = program_path + .parent() + .ok_or_else(|| ProgramLoadError::ProgramDirNotFound(program_path.clone()))?; + + // SAFETY: set_var is process-global; we set it once before loading the ELF. + unsafe { + std::env::set_var("SBF_OUT_DIR", program_dir); + } + + let mut mollusk = Mollusk::new(program_id, program_name); + + // Add necessary programs for testing + add_required_programs(&mut mollusk); + + Ok(mollusk) +} + +/// Add required programs to the Mollusk instance. +/// +/// This includes system programs and SPL Token programs that are commonly +/// used in swap operations. +fn add_required_programs(mollusk: &mut Mollusk) { + // System program is already included by default in Mollusk + + // SPL Token program and Associated Token program - needed for token operations + mollusk_svm_programs_token::token::add_program(mollusk); + mollusk_svm_programs_token::associated_token::add_program(mollusk); +} + +/// Initialize a test context with the swap program. +/// +/// This is a convenience function that creates both a Mollusk instance and +/// a test context for easier testing. +/// +/// # Arguments +/// +/// * `repo_dir` - Path to the user's repository directory +/// +/// # Returns +/// +/// * `Ok(SwapTestContext)` - A configured test context +/// * `Err(TestContextError)` - If initialization fails +pub fn init_test_context(repo_dir: &Path) -> Result { + let program_id = load_swap_program_id(repo_dir)?; + let mollusk = create_swap_mollusk(repo_dir, &program_id)?; + SwapTestContext::new(mollusk, program_id) +} diff --git a/src/mollusk/program_loader.rs b/src/mollusk/program_loader.rs new file mode 100644 index 0000000..8e0d179 --- /dev/null +++ b/src/mollusk/program_loader.rs @@ -0,0 +1,245 @@ +// Copyright (c) The StackClass Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Program loader module for loading the swap program from disk. + +use mollusk_svm::file; +use solana_pubkey::Pubkey; +use std::{ + path::{Path, PathBuf}, + str::FromStr, +}; + +/// Error type for program loading operations. +#[derive(Debug)] +pub enum ProgramLoadError { + RepoNotFound(PathBuf), + AnchorTomlNotFound(PathBuf), + ProgramIdNotFound, + InvalidProgramId(String), + ProgramDirNotFound(PathBuf), + ProgramNotFound, + IoError(std::io::Error), + ElfLoadError(String), +} + +impl std::fmt::Display for ProgramLoadError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ProgramLoadError::RepoNotFound(path) => { + write!(f, "Repository directory not found: {}", path.display()) + } + ProgramLoadError::AnchorTomlNotFound(path) => { + write!(f, "Anchor.toml not found: {}", path.display()) + } + ProgramLoadError::ProgramIdNotFound => { + write!(f, "Program ID not found in Anchor.toml") + } + ProgramLoadError::InvalidProgramId(value) => { + write!(f, "Invalid program ID in Anchor.toml: {}", value) + } + ProgramLoadError::ProgramDirNotFound(path) => { + write!(f, "Program directory not found: {}", path.display()) + } + ProgramLoadError::ProgramNotFound => { + write!(f, "Program SO file not found in any of the expected locations") + } + ProgramLoadError::IoError(err) => write!(f, "Failed to read program file: {}", err), + ProgramLoadError::ElfLoadError(msg) => write!(f, "Failed to load program ELF: {}", msg), + } + } +} + +impl std::error::Error for ProgramLoadError { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + ProgramLoadError::IoError(err) => Some(err), + _ => None, + } + } +} + +impl From for ProgramLoadError { + fn from(err: std::io::Error) -> Self { + ProgramLoadError::IoError(err) + } +} + +/// Load the swap program from the user's repository directory. +/// +/// This function searches for the compiled program SO file in the following +/// locations (in order): +/// +/// 1. `repo_dir/target/deploy/swap.so` +/// 2. `repo_dir/target/sbf-solana-solana/release/swap.so` +/// 3. `repo_dir/artifacts/swap.so` +/// +/// # Arguments +/// +/// * `repo_dir` - Path to the user's repository directory +/// +/// # Returns +/// +/// * `Ok(PathBuf)` - Path to the program SO file +/// * `Err(ProgramLoadError)` - If the program cannot be found or loaded +pub fn load_swap_program(repo_dir: &Path) -> Result { + if !repo_dir.exists() { + return Err(ProgramLoadError::RepoNotFound(repo_dir.to_path_buf())); + } + + // Try standard Anchor deployment path + let deploy_path = repo_dir.join("target/deploy/swap.so"); + if deploy_path.exists() { + return Ok(deploy_path); + } + + // Try SBF release path + let sbf_path = repo_dir.join("target/sbf-solana-solana/release/swap.so"); + if sbf_path.exists() { + return Ok(sbf_path); + } + + // Try artifacts directory + let artifacts_path = repo_dir.join("artifacts/swap.so"); + if artifacts_path.exists() { + return Ok(artifacts_path); + } + + // Try to find any .so file in the target directory + if let Some(so_file) = find_so_file_in_target(repo_dir) { + return Ok(so_file); + } + + Err(ProgramLoadError::ProgramNotFound) +} + +/// Load the swap program ID from Anchor.toml. +/// +/// This function attempts to parse the program ID from the `programs.*` +/// section in Anchor.toml. +/// +/// # Arguments +/// +/// * `repo_dir` - Path to the user's repository directory +/// +/// # Returns +/// +/// * `Ok(Pubkey)` - The program ID +/// * `Err(ProgramLoadError)` - If the program ID cannot be found or parsed +pub fn load_swap_program_id(repo_dir: &Path) -> Result { + if !repo_dir.exists() { + return Err(ProgramLoadError::RepoNotFound(repo_dir.to_path_buf())); + } + + let anchor_path = repo_dir.join("Anchor.toml"); + if !anchor_path.exists() { + return Err(ProgramLoadError::AnchorTomlNotFound(anchor_path)); + } + + let content = std::fs::read_to_string(&anchor_path)?; + let program_id = + find_program_id(&content, "swap").ok_or(ProgramLoadError::ProgramIdNotFound)?; + + Pubkey::from_str(&program_id).map_err(|_| ProgramLoadError::InvalidProgramId(program_id)) +} + +fn find_program_id(toml: &str, program_name: &str) -> Option { + let mut in_programs_section = false; + + for raw_line in toml.lines() { + let line = raw_line.trim(); + + if line.starts_with('[') && line.ends_with(']') { + let section = &line[1..line.len() - 1]; + in_programs_section = section == "programs" || section.starts_with("programs."); + continue; + } + + if !in_programs_section || line.is_empty() || line.starts_with('#') { + continue; + } + + if let Some((key, value)) = line.split_once('=') && + key.trim() == program_name + { + let value = value.trim().trim_matches('"'); + if !value.is_empty() { + return Some(value.to_string()); + } + } + } + + None +} + +/// Search for any .so file in the target directory. +fn find_so_file_in_target(repo_dir: &Path) -> Option { + let target_dir = repo_dir.join("target"); + if !target_dir.exists() { + return None; + } + + // Search recursively for .so files + let mut found = Vec::new(); + if let Ok(entries) = std::fs::read_dir(&target_dir) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + if let Some(found_in_subdir) = find_so_file_recursive(&path) { + found.push(found_in_subdir); + } + } else if path.extension().is_some_and(|ext| ext == "so") { + found.push(path); + } + } + } + + // Return the first found .so file + found.into_iter().next() +} + +/// Recursively search for .so files in a directory. +fn find_so_file_recursive(dir: &Path) -> Option { + if let Ok(entries) = std::fs::read_dir(dir) { + for entry in entries.flatten() { + let path = entry.path(); + if path.is_dir() { + if let Some(found) = find_so_file_recursive(&path) { + return Some(found); + } + } else if path.extension().is_some_and(|ext| ext == "so") { + return Some(path); + } + } + } + None +} + +/// Load the program ELF bytes from a file path. +/// +/// This is a wrapper around Mollusk's file loading functionality that +/// provides better error messages. +/// +/// # Arguments +/// +/// * `path` - Path to the program SO file +/// +/// # Returns +/// +/// * `Ok(Vec)` - The program ELF bytes +/// * `Err(ProgramLoadError)` - If the file cannot be read +pub fn load_program_elf(path: &Path) -> Result, ProgramLoadError> { + let elf = file::load_program_elf(path.to_str().unwrap()); + Ok(elf) +} diff --git a/src/mollusk/test_context.rs b/src/mollusk/test_context.rs new file mode 100644 index 0000000..9b5abad --- /dev/null +++ b/src/mollusk/test_context.rs @@ -0,0 +1,253 @@ +// Copyright (c) The StackClass Authors. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +//! Test context module for managing state during testing. + +use mollusk_svm::{ + Mollusk, + result::{Check, InstructionResult}, +}; +use solana_account::Account; +use solana_instruction::Instruction; +use solana_instruction_error::InstructionError; +use solana_pubkey::Pubkey; +use std::collections::HashMap; + +/// Error type for test context operations. +#[derive(Debug)] +pub enum TestContextError { + ExecutionError(String), + ValidationError(String), + AccountNotFound(String), +} + +impl std::fmt::Display for TestContextError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + TestContextError::ExecutionError(msg) => { + write!(f, "Instruction execution failed: {}", msg) + } + TestContextError::ValidationError(msg) => write!(f, "Validation failed: {}", msg), + TestContextError::AccountNotFound(msg) => write!(f, "Account not found: {}", msg), + } + } +} + +impl std::error::Error for TestContextError {} + +impl From for TestContextError { + fn from(err: InstructionError) -> Self { + TestContextError::ExecutionError(format!("{:?}", err)) + } +} + +impl From for TestContextError { + fn from(err: crate::mollusk::ProgramLoadError) -> Self { + TestContextError::ExecutionError(err.to_string()) + } +} + +/// A test context for the swap program. +/// +/// This struct manages the state of accounts during testing and provides +/// convenience methods for executing and validating instructions. +pub struct SwapTestContext { + /// The Mollusk test harness. + mollusk: Mollusk, + /// The current state of accounts. + accounts: HashMap, + /// The program ID being tested. + program_id: Pubkey, +} + +impl SwapTestContext { + /// Create a new test context. + /// + /// # Arguments + /// + /// * `mollusk` - The Mollusk test harness + /// * `program_id` - The swap program ID + /// + /// # Returns + /// + /// * `Ok(SwapTestContext)` - A new test context + pub fn new(mollusk: Mollusk, program_id: Pubkey) -> Result { + Ok(Self { mollusk, accounts: HashMap::new(), program_id }) + } + + /// Get the program ID. + pub fn program_id(&self) -> Pubkey { + self.program_id + } + + /// Add an account to the test context. + /// + /// # Arguments + /// + /// * `pubkey` - The account's public key + /// * `account` - The account data + pub fn add_account(&mut self, pubkey: Pubkey, account: Account) { + self.accounts.insert(pubkey, account); + } + + /// Get an account from the test context. + /// + /// # Arguments + /// + /// * `pubkey` - The account's public key + /// + /// # Returns + /// + /// * `Some(Account)` - The account data if it exists + /// * `None` - If the account does not exist + pub fn get_account(&self, pubkey: &Pubkey) -> Option { + self.accounts.get(pubkey).cloned() + } + + /// Execute an instruction and update the account state. + /// + /// # Arguments + /// + /// * `instruction` - The instruction to execute + /// + /// # Returns + /// + /// * `Ok(())` - If the instruction executed successfully + /// * `Err(TestContextError)` - If execution failed + pub fn execute_instruction( + &mut self, + instruction: &Instruction, + ) -> Result<(), TestContextError> { + let result: InstructionResult = + self.mollusk.process_instruction(instruction, &self.get_account_list()); + + // Check if execution was successful + if result.program_result.is_err() { + return Err(TestContextError::ExecutionError(format!("{:?}", result.program_result))); + } + + // Update account state from the result + for (pubkey, account) in result.resulting_accounts { + self.accounts.insert(pubkey, account); + } + + Ok(()) + } + + /// Execute an instruction and validate the result. + /// + /// # Arguments + /// + /// * `instruction` - The instruction to execute + /// * `checks` - The checks to apply to the result + /// + /// # Returns + /// + /// * `Ok(())` - If the instruction executed and all checks passed + /// * `Err(TestContextError)` - If execution or validation failed + pub fn execute_and_validate( + &mut self, + instruction: &Instruction, + checks: &[Check], + ) -> Result<(), TestContextError> { + let result: InstructionResult = self.mollusk.process_and_validate_instruction( + instruction, + &self.get_account_list(), + checks, + ); + + // Check if execution was successful + if result.program_result.is_err() { + return Err(TestContextError::ExecutionError(format!("{:?}", result.program_result))); + } + + // Update account state from the result + for (pubkey, account) in result.resulting_accounts { + self.accounts.insert(pubkey, account); + } + + Ok(()) + } + + /// Get the current account list for Mollusk. + fn get_account_list(&self) -> Vec<(Pubkey, Account)> { + self.accounts.iter().map(|(pubkey, account)| (*pubkey, account.clone())).collect() + } + + /// Create a new keypair and add a funded account to the context. + /// + /// This is a convenience method for creating user accounts with + /// initial lamports. + /// + /// # Arguments + /// + /// * `lamports` - Initial lamports to fund the account with + /// + /// # Returns + /// + /// * `Pubkey` - The public key of the new account + pub fn create_funded_account(&mut self, lamports: u64) -> Pubkey { + let pubkey = Pubkey::new_unique(); + let account = + Account { lamports, owner: solana_system_program::id(), ..Default::default() }; + self.add_account(pubkey, account); + pubkey + } + + /// Create a token account. + /// + /// This is a convenience method for creating token accounts. + /// + /// # Arguments + /// + /// * `owner` - The owner of the token account + /// * `mint` - The mint address + /// * `amount` - Initial token amount + /// + /// # Returns + /// + /// * `Pubkey` - The public key of the new token account + pub fn create_token_account(&mut self, owner: Pubkey, mint: Pubkey, amount: u64) -> Pubkey { + let pubkey = Pubkey::new_unique(); + let mut data = vec![0; 82]; // Token account size + + // Set owner (offset 32) + data[32..64].copy_from_slice(owner.as_ref()); + + // Set mint (offset 0) + data[0..32].copy_from_slice(mint.as_ref()); + + // Set amount (offset 64, little-endian u64) + data[64..72].copy_from_slice(&amount.to_le_bytes()); + + let account = Account { + lamports: solana_rent::Rent::default().minimum_balance(data.len()), + data, + owner: spl_token_interface::ID, + ..Default::default() + }; + self.add_account(pubkey, account); + pubkey + } +} + +impl Default for SwapTestContext { + fn default() -> Self { + Self { + mollusk: Mollusk::default(), + accounts: HashMap::new(), + program_id: Pubkey::new_unique(), + } + } +} diff --git a/src/stages/base/at4.rs b/src/stages/base/at4.rs index 6599b80..8572f91 100644 --- a/src/stages/base/at4.rs +++ b/src/stages/base/at4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_anchor_try(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_anchor_try_check() } diff --git a/src/stages/base/be1.rs b/src/stages/base/be1.rs index df9517e..f3cf406 100644 --- a/src/stages/base/be1.rs +++ b/src/stages/base/be1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_env_setup(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_env_setup_check() } diff --git a/src/stages/base/cp6.rs b/src/stages/base/cp6.rs index a4f8368..8b5ebf1 100644 --- a/src/stages/base/cp6.rs +++ b/src/stages/base/cp6.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_cpi_transfer(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_cpi_transfer_check() } diff --git a/src/stages/base/rs2.rs b/src/stages/base/rs2.rs index c922fb8..d13d922 100644 --- a/src/stages/base/rs2.rs +++ b/src/stages/base/rs2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_rust_basics(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_rust_basics_check() } diff --git a/src/stages/base/sm3.rs b/src/stages/base/sm3.rs index 7077f51..7c1d1d5 100644 --- a/src/stages/base/sm3.rs +++ b/src/stages/base/sm3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_solana_model(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_solana_model_check() } diff --git a/src/stages/base/st5.rs b/src/stages/base/st5.rs index 9a2a2ad..cb02b42 100644 --- a/src/stages/base/st5.rs +++ b/src/stages/base/st5.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_spl_token_basics(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_spl_token_basics_check() } diff --git a/src/stages/base/tt7.rs b/src/stages/base/tt7.rs index a56ddd3..b2bd324 100644 --- a/src/stages/base/tt7.rs +++ b/src/stages/base/tt7.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_token_transfer(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_token_transfer_check() } diff --git a/src/stages/extensions/cpi/cp1.rs b/src/stages/extensions/cpi/cp1.rs index 11f3a53..45c6759 100644 --- a/src/stages/extensions/cpi/cp1.rs +++ b/src/stages/extensions/cpi/cp1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_cpi_concept(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_cpi_checks() } diff --git a/src/stages/extensions/cpi/cp2.rs b/src/stages/extensions/cpi/cp2.rs index 7266b1b..e2c12eb 100644 --- a/src/stages/extensions/cpi/cp2.rs +++ b/src/stages/extensions/cpi/cp2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_transfer_checked(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_cpi_checks() } diff --git a/src/stages/extensions/cpi/cp3.rs b/src/stages/extensions/cpi/cp3.rs index 249791e..f018609 100644 --- a/src/stages/extensions/cpi/cp3.rs +++ b/src/stages/extensions/cpi/cp3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_cpi_signer(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_cpi_checks() } diff --git a/src/stages/extensions/cpi/cp4.rs b/src/stages/extensions/cpi/cp4.rs index 6dbea6d..834b885 100644 --- a/src/stages/extensions/cpi/cp4.rs +++ b/src/stages/extensions/cpi/cp4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_cpi_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_cpi_checks() } diff --git a/src/stages/extensions/deployment/de1.rs b/src/stages/extensions/deployment/de1.rs index 46ba474..78d050a 100644 --- a/src/stages/extensions/deployment/de1.rs +++ b/src/stages/extensions/deployment/de1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_local_testing(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_deployment_checks() } diff --git a/src/stages/extensions/deployment/de2.rs b/src/stages/extensions/deployment/de2.rs index 33f4b07..1bae678 100644 --- a/src/stages/extensions/deployment/de2.rs +++ b/src/stages/extensions/deployment/de2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_devnet_deploy(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_deployment_checks() } diff --git a/src/stages/extensions/deployment/de3.rs b/src/stages/extensions/deployment/de3.rs index 8d08320..b60bdfd 100644 --- a/src/stages/extensions/deployment/de3.rs +++ b/src/stages/extensions/deployment/de3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_mainnet_considerations(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_deployment_checks() } diff --git a/src/stages/extensions/deployment/de4.rs b/src/stages/extensions/deployment/de4.rs index 34259e0..d5feae5 100644 --- a/src/stages/extensions/deployment/de4.rs +++ b/src/stages/extensions/deployment/de4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_deployment_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_deployment_checks() } diff --git a/src/stages/extensions/error/er1.rs b/src/stages/extensions/error/er1.rs index bb977bb..08eb688 100644 --- a/src/stages/extensions/error/er1.rs +++ b/src/stages/extensions/error/er1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_error_basics(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_error_checks() } diff --git a/src/stages/extensions/error/er2.rs b/src/stages/extensions/error/er2.rs index 00ae6cb..b8d004a 100644 --- a/src/stages/extensions/error/er2.rs +++ b/src/stages/extensions/error/er2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_custom_errors(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_error_checks() } diff --git a/src/stages/extensions/error/er3.rs b/src/stages/extensions/error/er3.rs index f66f0cd..114deed 100644 --- a/src/stages/extensions/error/er3.rs +++ b/src/stages/extensions/error/er3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_error_messages(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_error_checks() } diff --git a/src/stages/extensions/error/er4.rs b/src/stages/extensions/error/er4.rs index 78e9f6c..419df98 100644 --- a/src/stages/extensions/error/er4.rs +++ b/src/stages/extensions/error/er4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_error_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_error_checks() } diff --git a/src/stages/extensions/make_offer/mo1.rs b/src/stages/extensions/make_offer/mo1.rs index a542598..54afb0d 100644 --- a/src/stages/extensions/make_offer/mo1.rs +++ b/src/stages/extensions/make_offer/mo1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_make_offer_overview(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_make_offer_checks() } diff --git a/src/stages/extensions/make_offer/mo2.rs b/src/stages/extensions/make_offer/mo2.rs index 16a94d9..ab488e6 100644 --- a/src/stages/extensions/make_offer/mo2.rs +++ b/src/stages/extensions/make_offer/mo2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_deposit_tokens(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_make_offer_checks() } diff --git a/src/stages/extensions/make_offer/mo3.rs b/src/stages/extensions/make_offer/mo3.rs index ed38cb2..bce165c 100644 --- a/src/stages/extensions/make_offer/mo3.rs +++ b/src/stages/extensions/make_offer/mo3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_save_offer(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_make_offer_checks() } diff --git a/src/stages/extensions/make_offer/mo4.rs b/src/stages/extensions/make_offer/mo4.rs index c89682e..d86f3f1 100644 --- a/src/stages/extensions/make_offer/mo4.rs +++ b/src/stages/extensions/make_offer/mo4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_make_offer_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_make_offer_checks() } diff --git a/src/stages/extensions/offer/of1.rs b/src/stages/extensions/offer/of1.rs index dfa3ade..956bf0d 100644 --- a/src/stages/extensions/offer/of1.rs +++ b/src/stages/extensions/offer/of1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_offer_data_structure(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_offer_checks() } diff --git a/src/stages/extensions/offer/of2.rs b/src/stages/extensions/offer/of2.rs index 61e1d0a..69c5cfd 100644 --- a/src/stages/extensions/offer/of2.rs +++ b/src/stages/extensions/offer/of2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_offer_validation(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_offer_checks() } diff --git a/src/stages/extensions/offer/of3.rs b/src/stages/extensions/offer/of3.rs index 9caaf2b..cd9a668 100644 --- a/src/stages/extensions/offer/of3.rs +++ b/src/stages/extensions/offer/of3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_offer_pda(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_offer_checks() } diff --git a/src/stages/extensions/offer/of4.rs b/src/stages/extensions/offer/of4.rs index 91c0e3c..f58fb70 100644 --- a/src/stages/extensions/offer/of4.rs +++ b/src/stages/extensions/offer/of4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_offer_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_offer_checks() } diff --git a/src/stages/extensions/pda/pa1.rs b/src/stages/extensions/pda/pa1.rs index 8a813f6..abfa5f6 100644 --- a/src/stages/extensions/pda/pa1.rs +++ b/src/stages/extensions/pda/pa1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_pda_concept(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_pda_checks() } diff --git a/src/stages/extensions/pda/pa2.rs b/src/stages/extensions/pda/pa2.rs index 6106560..75fdb1e 100644 --- a/src/stages/extensions/pda/pa2.rs +++ b/src/stages/extensions/pda/pa2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_pda_derivation(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_pda_checks() } diff --git a/src/stages/extensions/pda/pa3.rs b/src/stages/extensions/pda/pa3.rs index 955d279..222e251 100644 --- a/src/stages/extensions/pda/pa3.rs +++ b/src/stages/extensions/pda/pa3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_pda_bump_seeds(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_pda_checks() } diff --git a/src/stages/extensions/pda/pa4.rs b/src/stages/extensions/pda/pa4.rs index f98da85..5f9dfce 100644 --- a/src/stages/extensions/pda/pa4.rs +++ b/src/stages/extensions/pda/pa4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_pda_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_pda_checks() } diff --git a/src/stages/extensions/security/se1.rs b/src/stages/extensions/security/se1.rs index d93d858..a3371ac 100644 --- a/src/stages/extensions/security/se1.rs +++ b/src/stages/extensions/security/se1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_common_vulnerabilities(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_security_checks() } diff --git a/src/stages/extensions/security/se2.rs b/src/stages/extensions/security/se2.rs index f11a79b..9b133ae 100644 --- a/src/stages/extensions/security/se2.rs +++ b/src/stages/extensions/security/se2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_reentrancy_protection(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_security_checks() } diff --git a/src/stages/extensions/security/se3.rs b/src/stages/extensions/security/se3.rs index df5f947..a9abb03 100644 --- a/src/stages/extensions/security/se3.rs +++ b/src/stages/extensions/security/se3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_account_validation(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_security_checks() } diff --git a/src/stages/extensions/security/se4.rs b/src/stages/extensions/security/se4.rs index e490a49..415a4da 100644 --- a/src/stages/extensions/security/se4.rs +++ b/src/stages/extensions/security/se4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_security_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_security_checks() } diff --git a/src/stages/extensions/take_offer/to1.rs b/src/stages/extensions/take_offer/to1.rs index ac8836c..a2e9b5a 100644 --- a/src/stages/extensions/take_offer/to1.rs +++ b/src/stages/extensions/take_offer/to1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_take_offer_overview(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_take_offer_checks() } diff --git a/src/stages/extensions/take_offer/to2.rs b/src/stages/extensions/take_offer/to2.rs index 3e78ebb..80263c0 100644 --- a/src/stages/extensions/take_offer/to2.rs +++ b/src/stages/extensions/take_offer/to2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_receive_tokens(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_take_offer_checks() } diff --git a/src/stages/extensions/take_offer/to3.rs b/src/stages/extensions/take_offer/to3.rs index 9316c60..a5a7264 100644 --- a/src/stages/extensions/take_offer/to3.rs +++ b/src/stages/extensions/take_offer/to3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_withdraw_vault(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_take_offer_checks() } diff --git a/src/stages/extensions/take_offer/to4.rs b/src/stages/extensions/take_offer/to4.rs index ede4989..c6c2021 100644 --- a/src/stages/extensions/take_offer/to4.rs +++ b/src/stages/extensions/take_offer/to4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_take_offer_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_take_offer_checks() } diff --git a/src/stages/extensions/testing/te1.rs b/src/stages/extensions/testing/te1.rs index c59cbfb..8b620b5 100644 --- a/src/stages/extensions/testing/te1.rs +++ b/src/stages/extensions/testing/te1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_rust_test_basics(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_testing_checks() } diff --git a/src/stages/extensions/testing/te2.rs b/src/stages/extensions/testing/te2.rs index e873701..48049bd 100644 --- a/src/stages/extensions/testing/te2.rs +++ b/src/stages/extensions/testing/te2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_anchor_test_attribute(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_testing_checks() } diff --git a/src/stages/extensions/testing/te3.rs b/src/stages/extensions/testing/te3.rs index 697aab7..fd7f3b5 100644 --- a/src/stages/extensions/testing/te3.rs +++ b/src/stages/extensions/testing/te3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_testing_setup_teardown(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_testing_checks() } diff --git a/src/stages/extensions/testing/te4.rs b/src/stages/extensions/testing/te4.rs index 0e397c0..4aed93e 100644 --- a/src/stages/extensions/testing/te4.rs +++ b/src/stages/extensions/testing/te4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_comprehensive_tests(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_testing_checks() } diff --git a/src/stages/extensions/vault/va1.rs b/src/stages/extensions/vault/va1.rs index a9ccc87..c376f45 100644 --- a/src/stages/extensions/vault/va1.rs +++ b/src/stages/extensions/vault/va1.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_vault_intro(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_vault_checks() } diff --git a/src/stages/extensions/vault/va2.rs b/src/stages/extensions/vault/va2.rs index 7f0563c..79ffc0b 100644 --- a/src/stages/extensions/vault/va2.rs +++ b/src/stages/extensions/vault/va2.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_vault_creation(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_vault_checks() } diff --git a/src/stages/extensions/vault/va3.rs b/src/stages/extensions/vault/va3.rs index c00a557..4ce6c64 100644 --- a/src/stages/extensions/vault/va3.rs +++ b/src/stages/extensions/vault/va3.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_vault_security(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_vault_checks() } diff --git a/src/stages/extensions/vault/va4.rs b/src/stages/extensions/vault/va4.rs index 8a88800..7a6f7fe 100644 --- a/src/stages/extensions/vault/va4.rs +++ b/src/stages/extensions/vault/va4.rs @@ -13,5 +13,5 @@ // limitations under the License. pub fn test_vault_practice(_harness: &tester::Harness) -> Result<(), tester::CaseError> { - Ok(()) + crate::helpers::run_vault_checks() } From edea3e87fd3600182817df61106cb367b73f0b03 Mon Sep 17 00:00:00 2001 From: lispking Date: Wed, 7 Jan 2026 16:20:53 +0800 Subject: [PATCH 2/6] Add #[allow(dead_code)] attributes to suppress clippy warnings --- src/helpers.rs | 10 ++++++++++ src/mollusk/program_loader.rs | 2 ++ src/mollusk/test_context.rs | 2 ++ 3 files changed, 14 insertions(+) diff --git a/src/helpers.rs b/src/helpers.rs index 4f64dab..96d86ba 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -51,6 +51,7 @@ pub fn get_repo_dir() -> Result { /// # Returns /// /// * `String` - A formatted error message +#[allow(dead_code)] pub fn format_test_error(stage_name: &str, error: &TestContextError) -> String { format!("Test '{}' failed: {}", stage_name, error) } @@ -64,6 +65,7 @@ pub fn format_test_error(stage_name: &str, error: &TestContextError) -> String { /// # Returns /// /// * `String` - A formatted success message +#[allow(dead_code)] pub fn format_test_success(stage_name: &str) -> String { format!("Test '{}' passed successfully", stage_name) } @@ -77,6 +79,7 @@ pub fn format_test_success(stage_name: &str) -> String { /// # Returns /// /// * `Account` - A system account +#[allow(dead_code)] pub fn create_system_account(lamports: u64) -> Account { Account { lamports, owner: solana_system_program::id(), ..Default::default() } } @@ -91,6 +94,7 @@ pub fn create_system_account(lamports: u64) -> Account { /// # Returns /// /// * `(Pubkey, u8)` - The PDA public key and bump seed +#[allow(dead_code)] pub fn create_pda(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8) { Pubkey::find_program_address(seeds, program_id) } @@ -100,6 +104,7 @@ pub fn create_pda(seeds: &[&[u8]], program_id: &Pubkey) -> (Pubkey, u8) { /// # Returns /// /// * `Check` - A success check +#[allow(dead_code)] pub fn success_check() -> Check<'static> { Check::success() } @@ -114,6 +119,7 @@ pub fn success_check() -> Check<'static> { /// # Returns /// /// * `Check` - A lamports check +#[allow(dead_code)] pub fn lamports_check(pubkey: &Pubkey, expected_lamports: u64) -> Check<'_> { Check::account(pubkey).lamports(expected_lamports).build() } @@ -128,6 +134,7 @@ pub fn lamports_check(pubkey: &Pubkey, expected_lamports: u64) -> Check<'_> { /// # Returns /// /// * `Check` - A data check +#[allow(dead_code)] pub fn data_check<'a>(pubkey: &'a Pubkey, expected_data: &'a [u8]) -> Check<'a> { Check::account(pubkey).data(expected_data).build() } @@ -142,6 +149,7 @@ pub fn data_check<'a>(pubkey: &'a Pubkey, expected_data: &'a [u8]) -> Check<'a> /// # Returns /// /// * `Check` - An owner check +#[allow(dead_code)] pub fn owner_check<'a>(pubkey: &'a Pubkey, expected_owner: &'a Pubkey) -> Check<'a> { Check::account(pubkey).owner(expected_owner).build() } @@ -156,6 +164,7 @@ pub fn owner_check<'a>(pubkey: &'a Pubkey, expected_owner: &'a Pubkey) -> Check< /// # Returns /// /// * `Check` - An executable check +#[allow(dead_code)] pub fn executable_check(pubkey: &Pubkey, expected_executable: bool) -> Check<'_> { Check::account(pubkey).executable(expected_executable).build() } @@ -272,6 +281,7 @@ pub struct SwapFixture { pub associated_token_program: Pubkey, pub offered_amount: u64, pub wanted_amount: u64, + #[allow(dead_code)] pub decimals_a: u8, } diff --git a/src/mollusk/program_loader.rs b/src/mollusk/program_loader.rs index 8e0d179..0f41e92 100644 --- a/src/mollusk/program_loader.rs +++ b/src/mollusk/program_loader.rs @@ -31,6 +31,7 @@ pub enum ProgramLoadError { ProgramDirNotFound(PathBuf), ProgramNotFound, IoError(std::io::Error), + #[allow(dead_code)] ElfLoadError(String), } @@ -239,6 +240,7 @@ fn find_so_file_recursive(dir: &Path) -> Option { /// /// * `Ok(Vec)` - The program ELF bytes /// * `Err(ProgramLoadError)` - If the file cannot be read +#[allow(dead_code)] pub fn load_program_elf(path: &Path) -> Result, ProgramLoadError> { let elf = file::load_program_elf(path.to_str().unwrap()); Ok(elf) diff --git a/src/mollusk/test_context.rs b/src/mollusk/test_context.rs index 9b5abad..52afab5 100644 --- a/src/mollusk/test_context.rs +++ b/src/mollusk/test_context.rs @@ -156,6 +156,7 @@ impl SwapTestContext { /// /// * `Ok(())` - If the instruction executed and all checks passed /// * `Err(TestContextError)` - If execution or validation failed + #[allow(dead_code)] pub fn execute_and_validate( &mut self, instruction: &Instruction, @@ -218,6 +219,7 @@ impl SwapTestContext { /// # Returns /// /// * `Pubkey` - The public key of the new token account + #[allow(dead_code)] pub fn create_token_account(&mut self, owner: Pubkey, mint: Pubkey, amount: u64) -> Pubkey { let pubkey = Pubkey::new_unique(); let mut data = vec![0; 82]; // Token account size From 5ff39fe3c620a928a929f366195c59883a1be2c5 Mon Sep 17 00:00:00 2001 From: lispking Date: Thu, 8 Jan 2026 11:32:16 +0800 Subject: [PATCH 3/6] Update program loader paths to match build artifact name The compiled Solana program is named instead of , so update all deployment path lookups accordingly. --- src/mollusk/program_loader.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/mollusk/program_loader.rs b/src/mollusk/program_loader.rs index 0f41e92..530c19d 100644 --- a/src/mollusk/program_loader.rs +++ b/src/mollusk/program_loader.rs @@ -100,19 +100,19 @@ pub fn load_swap_program(repo_dir: &Path) -> Result { } // Try standard Anchor deployment path - let deploy_path = repo_dir.join("target/deploy/swap.so"); + let deploy_path = repo_dir.join("target/deploy/swap_program.so"); if deploy_path.exists() { return Ok(deploy_path); } // Try SBF release path - let sbf_path = repo_dir.join("target/sbf-solana-solana/release/swap.so"); + let sbf_path = repo_dir.join("target/sbf-solana-solana/release/swap_program.so"); if sbf_path.exists() { return Ok(sbf_path); } // Try artifacts directory - let artifacts_path = repo_dir.join("artifacts/swap.so"); + let artifacts_path = repo_dir.join("artifacts/swap_program.so"); if artifacts_path.exists() { return Ok(artifacts_path); } From add18b1049e7ac82f7a65346c627e897496634ec Mon Sep 17 00:00:00 2001 From: lispking Date: Thu, 8 Jan 2026 16:53:21 +0800 Subject: [PATCH 4/6] refactor: move load_lending_program import to module level --- src/helpers.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index 96d86ba..df0420b 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -14,7 +14,9 @@ //! Helper functions for testing the swap program. -use crate::mollusk::{ProgramLoadError, TestContextError, init_test_context, load_swap_program_id}; +use crate::mollusk::{ + ProgramLoadError, TestContextError, init_test_context, load_swap_program, load_swap_program_id, +}; use mollusk_svm::{program::keyed_account_for_system_program, result::Check}; use mollusk_svm_programs_token::{associated_token, token}; use sha2::{Digest, Sha256}; @@ -221,8 +223,6 @@ pub fn to_case_error_from_context(error: TestContextError) -> tester::CaseError /// * `Ok(())` - If the program is available /// * `Err(tester::CaseError)` - If the program is not available pub fn check_program_available(repo_dir: &Path) -> Result<(), tester::CaseError> { - use crate::mollusk::load_swap_program; - match load_swap_program(repo_dir) { Ok(_) => Ok(()), Err(e) => Err(Box::new(e) as Box), @@ -698,11 +698,11 @@ pub fn run_offer_checks() -> Result<(), tester::CaseError> { let offer_account = fixture.get_account(&fixture.offer)?; let offer = offer_data_from_account(&offer_account).map_err(to_case_error_from_context)?; - if offer.id != fixture.offer_id || - offer.maker != fixture.maker || - offer.token_mint_a != fixture.token_mint_a || - offer.token_mint_b != fixture.token_mint_b || - offer.token_b_wanted_amount != fixture.wanted_amount + if offer.id != fixture.offer_id + || offer.maker != fixture.maker + || offer.token_mint_a != fixture.token_mint_a + || offer.token_mint_b != fixture.token_mint_b + || offer.token_b_wanted_amount != fixture.wanted_amount { return Err(Box::new(std::io::Error::new( std::io::ErrorKind::InvalidData, From b1b63a6c9ad6812938c4e88e83902be4aef4ac44 Mon Sep 17 00:00:00 2001 From: lispking Date: Thu, 8 Jan 2026 16:57:16 +0800 Subject: [PATCH 5/6] style: reformatted multi-line conditionals in run_offer_checks Reorganized boolean operators to start of line for better readability in the offer validation check. --- src/helpers.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/helpers.rs b/src/helpers.rs index df0420b..77e7d3e 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -698,11 +698,11 @@ pub fn run_offer_checks() -> Result<(), tester::CaseError> { let offer_account = fixture.get_account(&fixture.offer)?; let offer = offer_data_from_account(&offer_account).map_err(to_case_error_from_context)?; - if offer.id != fixture.offer_id - || offer.maker != fixture.maker - || offer.token_mint_a != fixture.token_mint_a - || offer.token_mint_b != fixture.token_mint_b - || offer.token_b_wanted_amount != fixture.wanted_amount + if offer.id != fixture.offer_id || + offer.maker != fixture.maker || + offer.token_mint_a != fixture.token_mint_a || + offer.token_mint_b != fixture.token_mint_b || + offer.token_b_wanted_amount != fixture.wanted_amount { return Err(Box::new(std::io::Error::new( std::io::ErrorKind::InvalidData, From ec6aa84a096b136dada45878649314d909ddd339 Mon Sep 17 00:00:00 2001 From: lispking Date: Thu, 8 Jan 2026 17:16:25 +0800 Subject: [PATCH 6/6] fix: update program name to match build artifact --- src/mollusk/program_loader.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mollusk/program_loader.rs b/src/mollusk/program_loader.rs index 530c19d..eb94eea 100644 --- a/src/mollusk/program_loader.rs +++ b/src/mollusk/program_loader.rs @@ -150,7 +150,7 @@ pub fn load_swap_program_id(repo_dir: &Path) -> Result let content = std::fs::read_to_string(&anchor_path)?; let program_id = - find_program_id(&content, "swap").ok_or(ProgramLoadError::ProgramIdNotFound)?; + find_program_id(&content, "swap-program").ok_or(ProgramLoadError::ProgramIdNotFound)?; Pubkey::from_str(&program_id).map_err(|_| ProgramLoadError::InvalidProgramId(program_id)) }