diff --git a/Cargo.lock b/Cargo.lock index 7b1d9aea..7dc233f7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3469,8 +3469,6 @@ dependencies = [ [[package]] name = "light-event" version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae607b61749246439e9e302a75dc565c98d6b9a81efcb1c6dd5e755a24b427ab" dependencies = [ "borsh 0.10.4", "light-compressed-account", diff --git a/Cargo.toml b/Cargo.toml index 22e8fa03..c6837d03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -155,3 +155,6 @@ debug = 0 # Some standard library files already come precompiled with debuginfo. We strip it for faster linking # and smaller binaries. strip = "debuginfo" + +[patch.crates-io] +light-event = { path = "light-event-patched" } diff --git a/light-event-patched/.cargo-ok b/light-event-patched/.cargo-ok new file mode 100644 index 00000000..5f8b7958 --- /dev/null +++ b/light-event-patched/.cargo-ok @@ -0,0 +1 @@ +{"v":1} \ No newline at end of file diff --git a/light-event-patched/.cargo-rdme.toml b/light-event-patched/.cargo-rdme.toml new file mode 100644 index 00000000..c00ab92c --- /dev/null +++ b/light-event-patched/.cargo-rdme.toml @@ -0,0 +1,2 @@ +workspace-project = "light-event" +heading-base-level = 0 diff --git a/light-event-patched/.cargo_vcs_info.json b/light-event-patched/.cargo_vcs_info.json new file mode 100644 index 00000000..d0bc8b63 --- /dev/null +++ b/light-event-patched/.cargo_vcs_info.json @@ -0,0 +1,6 @@ +{ + "git": { + "sha1": "1509f5202200980f18ef58143231d4f6f61d3889" + }, + "path_in_vcs": "sdk-libs/event" +} \ No newline at end of file diff --git a/light-event-patched/Cargo.lock b/light-event-patched/Cargo.lock new file mode 100644 index 00000000..0568a57b --- /dev/null +++ b/light-event-patched/Cargo.lock @@ -0,0 +1,2941 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aead" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" +dependencies = [ + "crypto-common", + "generic-array", +] + +[[package]] +name = "aes" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" +dependencies = [ + "cfg-if", + "cipher", + "cpufeatures", +] + +[[package]] +name = "aes-gcm-siv" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" +dependencies = [ + "aead", + "aes", + "cipher", + "ctr", + "polyval", + "subtle", + "zeroize", +] + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aligned-sized" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48a526ec4434d531d488af59fe866f36b310fe8906691c75dffa664450a3800a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "ark-bn254" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash", + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint", + "num-integer", + "num-traits", + "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", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "arrayvec", + "digest 0.10.7", + "educe", + "itertools 0.13.0", + "num-bigint", + "num-traits", + "paste", + "zeroize", +] + +[[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.114", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash", + "ark-ff", + "ark-serialize", + "ark-std", + "educe", + "fnv", + "hashbrown 0.15.2", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "arrayvec", + "digest 0.10.7", + "num-bigint", +] + +[[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.114", +] + +[[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 = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[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 = "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", + "digest 0.10.7", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "borsh" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" +dependencies = [ + "borsh-derive 0.10.4", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" +dependencies = [ + "borsh-derive 1.6.0", + "cfg_aliases", +] + +[[package]] +name = "borsh-derive" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" +dependencies = [ + "borsh-derive-internal", + "borsh-schema-derive-internal", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" +dependencies = [ + "once_cell", + "proc-macro-crate 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "borsh-schema-derive-internal" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "bumpalo" +version = "3.19.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5dd9dc738b7a8311c7ade152424974d8115f2cdad61e8dab8dac9f2362298510" + +[[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.114", +] + +[[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.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90583009037521a116abf44494efecd645ba48b6622457080f080b85544e2215" +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 = "cipher" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "console_error_panic_hook" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc" +dependencies = [ + "cfg-if", + "wasm-bindgen", +] + +[[package]] +name = "console_log" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" +dependencies = [ + "log", + "web-sys", +] + +[[package]] +name = "constant_time_eq" +version = "0.3.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-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "typenum", +] + +[[package]] +name = "ctr" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" +dependencies = [ + "cipher", +] + +[[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.114", +] + +[[package]] +name = "derivation-path" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer 0.10.4", + "crypto-common", + "subtle", +] + +[[package]] +name = "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.114", +] + +[[package]] +name = "either" +version = "1.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" + +[[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.114", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "feature-probe" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" + +[[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.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" + +[[package]] +name = "five8" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_const" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" +dependencies = [ + "five8_core", +] + +[[package]] +name = "five8_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "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", + "js-sys", + "libc", + "wasi 0.11.1+wasi-snapshot-preview1", + "wasm-bindgen", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" +dependencies = [ + "allocator-api2", + "equivalent", + "foldhash", +] + +[[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.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[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" + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "keccak" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.178" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37c93d8daa9d8a012fd8ab92f088405fb202ea0b6ab73ee2482ae66af4f42091" + +[[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-account-checks" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34d74dd13535c6014abb4cac694e14083b206a7f6cf1bbbc9611aa5c2e11cdd1" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "light-array-map" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bdd13b18028ac9d80d0a987551c0dad7fe81be8140e87cc9d568b80f3728203" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "light-compressed-account" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adab5a8dddd9675306b0a808900578ed60b40b5c5457e330e28c9cb51361118d" +dependencies = [ + "borsh 0.10.4", + "light-hasher", + "light-macros", + "light-program-profiler", + "light-zero-copy", + "thiserror 2.0.18", + "tinyvec", + "zerocopy", +] + +[[package]] +name = "light-compressible" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0905b52848daea4cb7edbc9ddca0a8d5c4f1d864e89eff0aca3b6fc2a9edbb2" +dependencies = [ + "aligned-sized", + "borsh 0.10.4", + "bytemuck", + "light-account-checks", + "light-compressed-account", + "light-hasher", + "light-macros", + "light-program-profiler", + "light-zero-copy", + "pinocchio-pubkey", + "solana-pubkey", + "solana-rent", + "thiserror 2.0.18", + "zerocopy", +] + +[[package]] +name = "light-event" +version = "0.21.0" +dependencies = [ + "borsh 0.10.4", + "light-compressed-account", + "light-hasher", + "light-token-interface", + "light-zero-copy", + "rand 0.8.5", + "thiserror 2.0.18", +] + +[[package]] +name = "light-hasher" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c822662e6e109bac0e132a43fd52a4ef684811245a794e048cf9cda001e934c8" +dependencies = [ + "ark-bn254", + "ark-ff", + "borsh 0.10.4", + "light-poseidon", + "num-bigint", + "thiserror 2.0.18", + "tinyvec", +] + +[[package]] +name = "light-macros" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "179ac51cadc1d0ca047b4d6265a7cc245ca3affc16a20a2749585aa6464d39c2" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "solana-pubkey", + "syn 2.0.114", +] + +[[package]] +name = "light-poseidon" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3d87542063daaccbfecd78b60f988079b6ec4e089249658b9455075c78d42" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint", + "thiserror 1.0.69", +] + +[[package]] +name = "light-profiler-macro" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a8be18fe4de58a6f754caa74a3fbc6d8a758a26f1f3c24d5b0f5b55df5f5408" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "light-program-profiler" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1d345871581aebd8825868a3f08410290aa1cdddcb189ca7f7e588f61d79fcf" +dependencies = [ + "light-profiler-macro", +] + +[[package]] +name = "light-token-interface" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a457179188d9b6b7208a8a63a1fea851f818adfde3faaa262474bdcd3e3c7d" +dependencies = [ + "aligned-sized", + "borsh 0.10.4", + "bytemuck", + "light-array-map", + "light-compressed-account", + "light-compressible", + "light-hasher", + "light-macros", + "light-program-profiler", + "light-zero-copy", + "pinocchio", + "pinocchio-pubkey", + "solana-account-info", + "solana-pubkey", + "spl-pod", + "spl-token-2022", + "thiserror 2.0.18", + "tinyvec", + "zerocopy", +] + +[[package]] +name = "light-zero-copy" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5621fb515e14af46148699c0b65334aabe230a1d2cbd06736ccc7a408c8a4af" +dependencies = [ + "light-zero-copy-derive", + "zerocopy", +] + +[[package]] +name = "light-zero-copy-derive" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41c46425e5c7ab5203ff5c86ae2615b169cca55f9283f5f60f5dd74143be6934" +dependencies = [ + "lazy_static", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[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.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "merlin" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" +dependencies = [ + "byteorder", + "keccak", + "rand_core 0.6.4", + "zeroize", +] + +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "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.114", +] + +[[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-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 3.4.0", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[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 = "pbkdf2" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" +dependencies = [ + "digest 0.10.7", +] + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pinocchio" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b971851087bc3699b001954ad02389d50c41405ece3548cbcafc88b3e20017a" + +[[package]] +name = "pinocchio-pubkey" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb0225638cadcbebae8932cb7f49cb5da7c15c21beb19f048f05a5ca7d93f065" +dependencies = [ + "five8_const", + "pinocchio", + "sha2-const-stable", +] + +[[package]] +name = "polyval" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" +dependencies = [ + "cfg-if", + "cpufeatures", + "opaque-debug", + "universal-hash", +] + +[[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 = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +dependencies = [ + "toml", +] + +[[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.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "qstring" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom 0.1.16", + "libc", + "rand_chacha 0.2.2", + "rand_core 0.5.1", + "rand_hc", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "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 = "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 = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[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.114", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[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 = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + +[[package]] +name = "sha3" +version = "0.10.8" +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 = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "solana-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +dependencies = [ + "solana-account-info", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-account-info" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8f5152a288ef1912300fc6efa6c2d1f9bb55d9398eb6c72326360b8063987da" +dependencies = [ + "bincode", + "serde", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-slot-hashes", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint", + "num-traits", + "solana-define-syscall", +] + +[[package]] +name = "solana-bincode" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +dependencies = [ + "bincode", + "serde", + "solana-instruction", +] + +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-borsh" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +dependencies = [ + "borsh 0.10.4", + "borsh 1.6.0", +] + +[[package]] +name = "solana-clock" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bb482ab70fced82ad3d7d3d87be33d466a3498eb8aa856434ff3c0dfc2e2e31" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info", + "solana-define-syscall", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-stable-layout", +] + +[[package]] +name = "solana-curve25519" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae4261b9a8613d10e77ac831a8fa60b6fa52b9b103df46d641deff9f9812a23" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "solana-define-syscall", + "subtle", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-decode-error" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c781686a18db2f942e70913f7ca15dc120ec38dcab42ff7557db2c70c625a35" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" + +[[package]] +name = "solana-derivation-path" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "939756d798b25c5ec3cca10e06212bdca3b1443cb9bb740a38124f58b258737b" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface", + "solana-clock", + "solana-hash", + "solana-instruction", + "solana-keccak-hasher", + "solana-message", + "solana-nonce", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f5c5382b449e8e4e3016fb05e418c53d57782d8b5c30aa372fc265654b956d" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" +dependencies = [ + "borsh 1.6.0", + "bytemuck", + "bytemuck_derive", + "five8", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-sanitize", + "wasm-bindgen", +] + +[[package]] +name = "solana-instruction" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab5682934bd1f65f8d2c16f21cb532526fcc1a09f796e2cacdb091eee5774ad" +dependencies = [ + "bincode", + "borsh 1.6.0", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "serde_json", + "solana-define-syscall", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" +dependencies = [ + "bitflags", + "solana-account-info", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-serialize-utils", + "solana-sysvar-id", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall", + "solana-hash", + "solana-sanitize", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f7162a05b8b0773156b443bccd674ea78bb9aa406325b467ea78c06c99a63a2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-system-interface", +] + +[[package]] +name = "solana-message" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1796aabce376ff74bf89b78d268fa5e683d7d7a96a0a4e4813ec34de49d5314b" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-sanitize", + "solana-sdk-ids", + "solana-short-vec", + "solana-system-interface", + "solana-transaction-error", + "wasm-bindgen", +] + +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-native-token" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61515b880c36974053dd499c0510066783f0cc6ac17def0c7ef2a244874cf4a9" + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator", + "solana-hash", + "solana-pubkey", + "solana-sha256-hasher", +] + +[[package]] +name = "solana-program" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98eca145bd3545e2fbb07166e895370576e47a00a7d824e325390d33bf467210" +dependencies = [ + "bincode", + "blake3", + "borsh 0.10.4", + "borsh 1.6.0", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.16", + "lazy_static", + "log", + "memoffset", + "num-bigint", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info", + "solana-address-lookup-table-interface", + "solana-atomic-u64", + "solana-big-mod-exp", + "solana-bincode", + "solana-blake3-hasher", + "solana-borsh", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-example-mocks", + "solana-feature-gate-interface", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-keccak-hasher", + "solana-last-restart-slot", + "solana-loader-v2-interface", + "solana-loader-v3-interface", + "solana-loader-v4-interface", + "solana-message", + "solana-msg", + "solana-native-token", + "solana-nonce", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-program-option", + "solana-program-pack", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-secp256k1-recover", + "solana-serde-varint", + "solana-serialize-utils", + "solana-sha256-hasher", + "solana-short-vec", + "solana-slot-hashes", + "solana-slot-history", + "solana-stable-layout", + "solana-stake-interface", + "solana-system-interface", + "solana-sysvar", + "solana-sysvar-id", + "solana-vote-interface", + "thiserror 2.0.18", + "wasm-bindgen", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ce041b1a0ed275290a5008ee1a4a6c48f5054c8a3d78d313c08958a06aedbd" +dependencies = [ + "solana-account-info", + "solana-msg", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "solana-program-error" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" +dependencies = [ + "borsh 1.6.0", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-pubkey", +] + +[[package]] +name = "solana-program-memory" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5426090c6f3fd6cfdc10685322fede9ca8e5af43cd6a59e98bfe4e91671712" +dependencies = [ + "solana-define-syscall", +] + +[[package]] +name = "solana-program-option" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" + +[[package]] +name = "solana-program-pack" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +dependencies = [ + "solana-program-error", +] + +[[package]] +name = "solana-pubkey" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" +dependencies = [ + "borsh 0.10.4", + "borsh 1.6.0", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "five8", + "five8_const", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-atomic-u64", + "solana-decode-error", + "solana-define-syscall", + "solana-sanitize", + "solana-sha256-hasher", + "wasm-bindgen", +] + +[[package]] +name = "solana-rent" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sanitize" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" + +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +dependencies = [ + "libsecp256k1", + "solana-define-syscall", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156bb61a96c605fa124e052d630dba2f6fb57e08c7d15b757e1e958b3ed7b3fe" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "solana-seed-derivable" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beb82b5adb266c6ea90e5cf3967235644848eac476c5a1f2f9283a143b7c97f" +dependencies = [ + "solana-derivation-path", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" +dependencies = [ + "hmac", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-serde-varint" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7e155eba458ecfb0107b98236088c3764a09ddf0201ec29e52a0be40857113" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +dependencies = [ + "solana-instruction", + "solana-pubkey", + "solana-sanitize", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa3feb32c28765f6aa1ce8f3feac30936f16c5c3f7eb73d63a5b8f6f8ecdc44" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall", + "solana-hash", +] + +[[package]] +name = "solana-short-vec" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-signature" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c8ec8e657aecfc187522fc67495142c12f35e55ddeca8698edbb738b8dbd8c" +dependencies = [ + "five8", + "solana-sanitize", +] + +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey", + "solana-signature", + "solana-transaction-error", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +dependencies = [ + "serde", + "serde_derive", + "solana-hash", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids", + "solana-sysvar-id", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction", + "solana-pubkey", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.6.0", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-program-error", + "solana-pubkey", + "solana-system-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" +dependencies = [ + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction", + "solana-pubkey", + "wasm-bindgen", +] + +[[package]] +name = "solana-sysvar" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c3595f95069f3d90f275bb9bd235a1973c4d059028b0a7f81baca2703815db" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info", + "solana-clock", + "solana-define-syscall", + "solana-epoch-rewards", + "solana-epoch-schedule", + "solana-fee-calculator", + "solana-hash", + "solana-instruction", + "solana-instructions-sysvar", + "solana-last-restart-slot", + "solana-program-entrypoint", + "solana-program-error", + "solana-program-memory", + "solana-pubkey", + "solana-rent", + "solana-sanitize", + "solana-sdk-ids", + "solana-sdk-macro", + "solana-slot-hashes", + "solana-slot-history", + "solana-stake-interface", + "solana-sysvar-id", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +dependencies = [ + "solana-pubkey", + "solana-sdk-ids", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +dependencies = [ + "solana-instruction", + "solana-sanitize", +] + +[[package]] +name = "solana-vote-interface" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b80d57478d6599d30acc31cc5ae7f93ec2361a06aefe8ea79bc81739a08af4c3" +dependencies = [ + "bincode", + "num-derive", + "num-traits", + "serde", + "serde_derive", + "solana-clock", + "solana-decode-error", + "solana-hash", + "solana-instruction", + "solana-pubkey", + "solana-rent", + "solana-sdk-ids", + "solana-serde-varint", + "solana-serialize-utils", + "solana-short-vec", + "solana-system-interface", +] + +[[package]] +name = "solana-zk-sdk" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b9fc6ec37d16d0dccff708ed1dd6ea9ba61796700c3bb7c3b401973f10f63b" +dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek", + "itertools 0.12.1", + "js-sys", + "merlin", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "serde_json", + "sha3", + "solana-derivation-path", + "solana-instruction", + "solana-pubkey", + "solana-sdk-ids", + "solana-seed-derivable", + "solana-seed-phrase", + "solana-signature", + "solana-signer", + "subtle", + "thiserror 2.0.18", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "spl-discriminator" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7398da23554a31660f17718164e31d31900956054f54f52d5ec1be51cb4f4b3" +dependencies = [ + "bytemuck", + "solana-program-error", + "solana-sha256-hasher", + "spl-discriminator-derive", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn", + "syn 2.0.114", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.9", + "syn 2.0.114", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0f668975d2b0536e8a8fd60e56a05c467f06021dae037f1d0cfed0de2e231d" +dependencies = [ + "bytemuck", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", +] + +[[package]] +name = "spl-memo" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" +dependencies = [ + "solana-account-info", + "solana-instruction", + "solana-msg", + "solana-program-entrypoint", + "solana-program-error", + "solana-pubkey", +] + +[[package]] +name = "spl-pod" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" +dependencies = [ + "borsh 1.6.0", + "bytemuck", + "bytemuck_derive", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "solana-program-option", + "solana-pubkey", + "solana-zk-sdk", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-program-error" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" +dependencies = [ + "num-derive", + "num-traits", + "solana-program", + "spl-program-error-derive", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-program-error-derive" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.9", + "syn 2.0.114", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-2022" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9048b26b0df0290f929ff91317c83db28b3ef99af2b3493dd35baa146774924c" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "num_enum", + "solana-program", + "solana-security-txt", + "solana-zk-sdk", + "spl-elgamal-registry", + "spl-memo", + "spl-pod", + "spl-token", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", + "spl-token-metadata-interface", + "spl-transfer-hook-interface", + "spl-type-length-value", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" +dependencies = [ + "base64 0.22.1", + "bytemuck", + "solana-curve25519", + "solana-zk-sdk", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" +dependencies = [ + "bytemuck", + "solana-curve25519", + "solana-program", + "solana-zk-sdk", + "spl-pod", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-confidential-transfer-proof-generation" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e3597628b0d2fe94e7900fd17cdb4cfbb31ee35c66f82809d27d86e44b2848b" +dependencies = [ + "curve25519-dalek", + "solana-zk-sdk", + "thiserror 2.0.18", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" +dependencies = [ + "borsh 1.6.0", + "num-derive", + "num-traits", + "solana-borsh", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-cpi", + "solana-decode-error", + "solana-instruction", + "solana-msg", + "solana-program-error", + "solana-pubkey", + "spl-discriminator", + "spl-pod", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-type-length-value" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" +dependencies = [ + "bytemuck", + "num-derive", + "num-traits", + "solana-account-info", + "solana-decode-error", + "solana-msg", + "solana-program-error", + "spl-discriminator", + "spl-pod", + "thiserror 1.0.69", +] + +[[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.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +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.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[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" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_datetime" +version = "0.7.4+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe3cea6b2aa3b910092f6abd4053ea464fab5f9c170ba5e9a6aead16ec4af2b6" +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.5+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c03bee5ce3696f31250db0bbaff18bc43301ce0e8db2ed1f07cbb2acf89984c" +dependencies = [ + "winnow", +] + +[[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.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "universal-hash" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" +dependencies = [ + "crypto-common", + "subtle", +] + +[[package]] +name = "uriparse" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" +dependencies = [ + "fnv", + "lazy_static", +] + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[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 = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn 2.0.114", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd74ec98b9250adb3ca554bdde269adf631549f51d8a8f8f0a10b50f1cb298c3" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8a8d209fdf45cf5138cbb5a506f6b52522a25afccc534d1475dad8e31105c6a" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[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.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.114", +] + +[[package]] +name = "zmij" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ff05f8caa9038894637571ae6b9e29466c1f4f829d26c9b28f869a29cbe3445" diff --git a/light-event-patched/Cargo.toml b/light-event-patched/Cargo.toml new file mode 100644 index 00000000..158efa53 --- /dev/null +++ b/light-event-patched/Cargo.toml @@ -0,0 +1,60 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies. +# +# If you are reading this file be aware that the original Cargo.toml +# will likely look very different (and much more reasonable). +# See Cargo.toml.orig for the original contents. + +[package] +edition = "2021" +name = "light-event" +version = "0.21.0" +build = false +autolib = false +autobins = false +autoexamples = false +autotests = false +autobenches = false +description = "Event types and utilities for Light Protocol" +readme = "README.md" +license = "Apache-2.0" +repository = "https://github.com/Lightprotocol/light-protocol" + +[lib] +name = "light_event" +path = "src/lib.rs" + +[[test]] +name = "parse_test" +path = "tests/parse_test.rs" + +[dependencies.borsh] +version = "0.10.4" +default-features = false + +[dependencies.light-compressed-account] +version = "0.10.1" +features = ["std"] +default-features = false + +[dependencies.light-hasher] +version = "5.0.0" +features = ["poseidon"] +default-features = false + +[dependencies.light-token-interface] +version = "0.4.0" + +[dependencies.light-zero-copy] +version = "0.6.0" +default-features = false + +[dependencies.thiserror] +version = "2.0" + +[dev-dependencies.rand] +version = "0.8.5" diff --git a/light-event-patched/Cargo.toml.orig b/light-event-patched/Cargo.toml.orig new file mode 100644 index 00000000..ab6a3256 --- /dev/null +++ b/light-event-patched/Cargo.toml.orig @@ -0,0 +1,18 @@ +[package] +name = "light-event" +version = "0.21.0" +description = "Event types and utilities for Light Protocol" +repository = "https://github.com/Lightprotocol/light-protocol" +license = "Apache-2.0" +edition = "2021" + +[dependencies] +borsh = { workspace = true } +light-compressed-account = { workspace = true, features = ["std"] } +light-hasher = { workspace = true, features = ["poseidon"] } +light-token-interface = { workspace = true } +light-zero-copy = { workspace = true } +thiserror = { workspace = true } + +[dev-dependencies] +rand = { workspace = true } diff --git a/light-event-patched/README.md b/light-event-patched/README.md new file mode 100644 index 00000000..e5159795 --- /dev/null +++ b/light-event-patched/README.md @@ -0,0 +1,13 @@ + + +# light-event + +Event types and parsing for Light Protocol transactions. + +| Type | Description | +|------|-------------| +| [`PublicTransactionEvent`](event::PublicTransactionEvent) | Transaction event with input/output compressed account hashes | +| [`BatchPublicTransactionEvent`](event::BatchPublicTransactionEvent) | Batched event with accounts, addresses, and sequence numbers | +| [`event_from_light_transaction`](parse::event_from_light_transaction) | Parse transaction instructions into a batch event | + + diff --git a/light-event-patched/src/error.rs b/light-event-patched/src/error.rs new file mode 100644 index 00000000..cfd0c8f1 --- /dev/null +++ b/light-event-patched/src/error.rs @@ -0,0 +1,22 @@ +use borsh::maybestd::io::Error as BorshError; +use light_compressed_account::CompressedAccountError; +use light_zero_copy::errors::ZeroCopyError; +use thiserror::Error; + +#[derive(Debug, Error)] +pub enum ParseIndexerEventError { + #[error("Deserialize light system program instruction error")] + DeserializeSystemInstructionError, + #[error("Deserialize account compression program instruction error")] + DeserializeAccountLightSystemCpiInputsError, + #[error("Instruction data too small {0} expected {1}")] + InstructionDataTooSmall(usize, usize), + #[error("Zero copy error {0}")] + ZeroCopyError(#[from] ZeroCopyError), + #[error("Borsh error {0}")] + BorshError(#[from] BorshError), + #[error("Compressed account error {0}")] + CompressedAccountError(#[from] CompressedAccountError), + #[error("Hasher error {0}")] + HasherError(#[from] light_hasher::HasherError), +} diff --git a/light-event-patched/src/event.rs b/light-event-patched/src/event.rs new file mode 100644 index 00000000..f9b87207 --- /dev/null +++ b/light-event-patched/src/event.rs @@ -0,0 +1,91 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use light_compressed_account::{ + instruction_data::{ + data::OutputCompressedAccountWithPackedContext, + insert_into_queues::MerkleTreeSequenceNumber as InstructionDataSequenceNumber, + }, + Pubkey, +}; + +#[derive(Debug, Clone, Default, PartialEq)] +pub struct BatchPublicTransactionEvent { + pub event: PublicTransactionEvent, + pub new_addresses: Vec, + pub input_sequence_numbers: Vec, + pub address_sequence_numbers: Vec, + pub tx_hash: [u8; 32], + pub batch_input_accounts: Vec, +} + +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, Default, PartialEq)] +pub struct PublicTransactionEvent { + pub input_compressed_account_hashes: Vec<[u8; 32]>, + pub output_compressed_account_hashes: Vec<[u8; 32]>, + pub output_compressed_accounts: Vec, + pub output_leaf_indices: Vec, + pub sequence_numbers: Vec, + pub relay_fee: Option, + pub is_compress: bool, + pub compress_or_decompress_lamports: Option, + pub pubkey_array: Vec, + pub message: Option>, + /// ATA owner info for compressed ATAs (output_index -> wallet_owner_pubkey). + /// Only populated for compress_and_close operations where is_ata=true. + pub ata_owners: Vec, +} + +/// ATA owner info extracted from compress_and_close operations. +#[derive(Debug, Clone, Copy, BorshSerialize, BorshDeserialize, Default, PartialEq, Eq)] +pub struct AssociatedTokenAccountOwnerInfo { + /// Index into output_compressed_accounts + pub output_index: u8, + /// The wallet owner pubkey that the ATA is derived from + pub wallet_owner: Pubkey, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct NewAddress { + pub address: [u8; 32], + pub mt_pubkey: Pubkey, + pub queue_index: u64, +} + +#[derive(Default, Debug, Clone, PartialEq, Eq)] +pub struct BatchNullifyContext { + pub tx_hash: [u8; 32], + pub account_hash: [u8; 32], + pub nullifier: [u8; 32], + pub nullifier_queue_index: u64, +} + +// Separate type because zerocopy::U64 doesn't implement BorshSerialize. +#[derive(Debug, Clone, Copy, BorshSerialize, BorshDeserialize, Default, PartialEq)] +pub struct MerkleTreeSequenceNumber { + pub tree_pubkey: Pubkey, + pub queue_pubkey: Pubkey, + pub tree_type: u64, + pub seq: u64, +} + +#[derive(Debug, Clone, Copy, BorshSerialize, BorshDeserialize, Default, PartialEq)] +pub struct MerkleTreeSequenceNumberV1 { + pub tree_pubkey: Pubkey, + pub seq: u64, +} + +impl MerkleTreeSequenceNumber { + pub fn is_empty(&self) -> bool { + self.tree_pubkey == Pubkey::default() + } +} + +impl From<&InstructionDataSequenceNumber> for MerkleTreeSequenceNumber { + fn from(seq: &InstructionDataSequenceNumber) -> Self { + Self { + tree_pubkey: seq.tree_pubkey, + queue_pubkey: seq.queue_pubkey, + tree_type: seq.tree_type.into(), + seq: seq.seq.into(), + } + } +} diff --git a/light-event-patched/src/lib.rs b/light-event-patched/src/lib.rs new file mode 100644 index 00000000..6a78baff --- /dev/null +++ b/light-event-patched/src/lib.rs @@ -0,0 +1,13 @@ +//! # light-event +//! +//! Event types and parsing for Light Protocol transactions. +//! +//! | Type | Description | +//! |------|-------------| +//! | [`PublicTransactionEvent`](event::PublicTransactionEvent) | Transaction event with input/output compressed account hashes | +//! | [`BatchPublicTransactionEvent`](event::BatchPublicTransactionEvent) | Batched event with accounts, addresses, and sequence numbers | +//! | [`event_from_light_transaction`](parse::event_from_light_transaction) | Parse transaction instructions into a batch event | + +pub mod error; +pub mod event; +pub mod parse; diff --git a/light-event-patched/src/mod.rs b/light-event-patched/src/mod.rs new file mode 100644 index 00000000..0191e725 --- /dev/null +++ b/light-event-patched/src/mod.rs @@ -0,0 +1,3 @@ +pub mod error; +pub mod event; +pub mod parse; diff --git a/light-event-patched/src/parse.rs b/light-event-patched/src/parse.rs new file mode 100644 index 00000000..03a76867 --- /dev/null +++ b/light-event-patched/src/parse.rs @@ -0,0 +1,785 @@ +use borsh::BorshDeserialize; +use light_compressed_account::{ + compressed_account::{ + CompressedAccount, CompressedAccountData, PackedCompressedAccountWithMerkleContext, + }, + constants::{ + ACCOUNT_COMPRESSION_PROGRAM_ID, CREATE_CPI_CONTEXT_ACCOUNT, LIGHT_REGISTRY_PROGRAM_ID, + LIGHT_SYSTEM_PROGRAM_ID, REGISTERED_PROGRAM_PDA, + }, + discriminators::*, + instruction_data::{ + data::{InstructionDataInvoke, OutputCompressedAccountWithPackedContext}, + insert_into_queues::InsertIntoQueuesInstructionData, + with_account_info::InstructionDataInvokeCpiWithAccountInfo, + with_readonly::InstructionDataInvokeCpiWithReadOnly, + }, + nullifier::create_nullifier, + Pubkey, +}; +use light_token_interface::{ + instructions::{ + extensions::ExtensionInstructionData, transfer2::CompressedTokenInstructionDataTransfer2, + }, + LIGHT_TOKEN_PROGRAM_ID, TRANSFER2, +}; +use light_zero_copy::traits::ZeroCopyAt; + +use super::{ + error::ParseIndexerEventError, + event::{ + AssociatedTokenAccountOwnerInfo, BatchNullifyContext, BatchPublicTransactionEvent, + MerkleTreeSequenceNumber, MerkleTreeSequenceNumberV1, NewAddress, PublicTransactionEvent, + }, +}; + +#[derive(Debug, Clone, PartialEq)] +struct ExecutingSystemInstruction<'a> { + output_compressed_accounts: Vec, + input_compressed_accounts: Vec, + is_compress: bool, + relay_fee: Option, + compress_or_decompress_lamports: Option, + execute_cpi_context: bool, + accounts: &'a [Pubkey], +} + +#[derive(Debug, Clone, PartialEq, Default)] +pub struct Indices { + pub system: usize, + pub cpi: Vec, + pub insert_into_queues: usize, + pub found_solana_system_program_instruction: bool, + pub found_system: bool, + /// Index of the token program instruction (if present, only when called from registry) + pub token: Option, + /// Whether registry program was found in the CPI chain (required for token instruction tracking) + pub found_registry: bool, +} + +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ProgramId { + LightSystem, + AccountCompression, + SolanaSystem, + LightToken, + Registry, + Unknown, +} + +#[derive(Debug, Clone, PartialEq)] +struct AssociatedInstructions<'a> { + pub executing_system_instruction: ExecutingSystemInstruction<'a>, + pub cpi_context_outputs: Vec, + pub insert_into_queues_instruction: InsertIntoQueuesInstructionData<'a>, + pub accounts: &'a [Pubkey], + /// Token instruction data and accounts for ATA owner extraction + pub token_instruction: Option>, +} + +/// Parsed token instruction data for extracting ATA owner info +#[derive(Debug, Clone, PartialEq)] +pub struct TokenInstructionData<'a> { + /// Raw instruction data + pub data: &'a [u8], + /// Accounts for this instruction + pub accounts: &'a [Pubkey], +} + +/// We piece the event together from 2 instructions: +/// 1. light_system_program::{Invoke, InvokeCpi, InvokeCpiReadOnly} (one of the 3) +/// 2. account_compression::InsertIntoQueues +/// - We return new addresses in batched trees separately +/// because from the PublicTransactionEvent there +/// is no way to know which addresses are new and +/// for batched address trees we need to index the queue of new addresses +/// the tree&queue account only contains bloomfilters, roots and metadata. +/// +/// Steps: +/// 0. Wrap program ids of instructions to filter but not change the pattern +/// system program cpi context creation ixs +/// insert into queue ixs not by the system program +/// instructions with less than 12 bytes ix data +/// 1. Find associated instructions by cpi pattern. +/// 2. Deserialize associated instructions. +/// 3. Create batched transaction events. +pub fn event_from_light_transaction( + program_ids: &[Pubkey], + instructions: &[Vec], + accounts: Vec>, +) -> Result>, ParseIndexerEventError> { + // 0. Wrap program ids of instructions to filter but not change the pattern. + let program_ids = wrap_program_ids(program_ids, instructions, &accounts); + // 1. Find associated instructions by cpi pattern. + let mut patterns = find_cpi_patterns(&program_ids); + if patterns.is_empty() { + return Ok(None); + } + // We searched from the last pattern to the first. + // -> reverse to be in order + patterns.reverse(); + // 2. Deserialize associated instructions. + let associated_instructions = patterns + .iter() + .map(|pattern| deserialize_associated_instructions(pattern, instructions, &accounts)) + .collect::, _>>()?; + // 3. Create batched transaction events. + let batched_transaction_events = associated_instructions + .iter() + .map(|associated_instruction| create_batched_transaction_event(associated_instruction)) + .collect::, _>>()?; + + // // Sanity checks: + // // - this must not throw in production because indexing just works if all instructions are in the same transaction. + // // - It's ok if someone misues the cpi context account but transaction data will not be available in photon. + // // - if we would throw an error it would brick photon because we would not be able to index a transaction that changed queue state. + // // - I could add extra data to the account compression cpi to make this impossible. -> this makes sense it is more robust. + // // TODO: make debug + // batched_transaction_events.iter().for_each(|event| { + // println!("event: {:?}", event); + // assert_eq!( + // event.event.input_compressed_account_hashes.len(), + // event.batch_input_accounts.len(), + // "Input hashes and input accounts length mismatch " + // ); + // assert_eq!( + // event.event.output_compressed_account_hashes.len(), + // event.event.output_leaf_indices.len(), + // "Output hashes and output leaf indices length mismatch " + // ); + // assert_eq!( + // event.event.output_compressed_account_hashes.len(), + // event.event.output_compressed_accounts.len(), + // "Output hashes and output compressed accounts length mismatch " + // ); + // }); + Ok(Some(batched_transaction_events)) +} + +fn deserialize_associated_instructions<'a>( + indices: &Indices, + instructions: &'a [Vec], + accounts: &'a [Vec], +) -> Result, ParseIndexerEventError> { + let (insert_queues_instruction, cpi_context_outputs) = { + let ix = &instructions[indices.insert_into_queues]; + if ix.len() < 12 { + return Err(ParseIndexerEventError::InstructionDataTooSmall( + ix.len(), + 12, + )); + } + let discriminator: [u8; 8] = ix[0..8].try_into().unwrap(); + if discriminator == DISCRIMINATOR_INSERT_INTO_QUEUES { + let (data, bytes) = InsertIntoQueuesInstructionData::zero_copy_at(&ix[12..])?; + let cpi_context_outputs = + Vec::::deserialize(&mut &bytes[..])?; + Ok((data, cpi_context_outputs)) + } else { + Err(ParseIndexerEventError::DeserializeAccountLightSystemCpiInputsError) + } + }?; + let exec_instruction = + deserialize_instruction(&instructions[indices.system], &accounts[indices.system])?; + + // Get token instruction data if present + let token_instruction = indices.token.map(|token_idx| TokenInstructionData { + data: &instructions[token_idx], + accounts: &accounts[token_idx], + }); + + Ok(AssociatedInstructions { + executing_system_instruction: exec_instruction, + cpi_context_outputs, + insert_into_queues_instruction: insert_queues_instruction, + // Remove signer and register program accounts. + accounts: &accounts[indices.insert_into_queues][2..], + token_instruction, + }) +} + +/// Filter all system instructions which create cpi context accounts, +/// so that we can infer that a system program instruction is a light transaction. +/// Create new AssociatedInstructions when we find a system instruction +/// if next instruct is solana system program isntruction followed by insert into queues is executable instruction +/// else is cpi instruction +/// only push into vec if insert into queues instruction is found +pub fn find_cpi_patterns(program_ids: &[ProgramId]) -> Vec { + let mut vec = Vec::new(); + let mut next_index = usize::MAX; + for (last_index, program_id) in (0..program_ids.len()).rev().zip(program_ids.iter().rev()) { + // skip last found pattern + if last_index > next_index { + continue; + } + // In case that we encounter more than one account compression program ix + // before finding one or more system program ix we just overwrite. + if let ProgramId::AccountCompression = program_id { + let (res, last_index) = find_cpi_pattern(last_index, program_ids); + next_index = last_index; + if let Some(res) = res { + vec.push(res); + }; + } + } + vec +} + +/// Pattern, SYSTEM_PROGRAM_ID.., default ids .., account compression program id +/// We search for the pattern in reverse because there can be multiple system instructions +/// but only one account compression instruction. +/// Start index points to ACCOUNT_COMPRESSION_PROGRAM_ID +pub fn find_cpi_pattern(start_index: usize, program_ids: &[ProgramId]) -> (Option, usize) { + let mut index_account = Indices { + insert_into_queues: start_index, + ..Default::default() + }; + // Track tentative token index - will only be confirmed if registry is found + let mut tentative_token: Option = None; + + for (index, program_id) in (0..start_index) + .rev() + .zip(program_ids[..start_index].iter().rev()) + { + if let ProgramId::SolanaSystem = program_id { + index_account.found_solana_system_program_instruction = true; + continue; + } else if matches!(program_id, ProgramId::LightSystem) + && index_account.found_solana_system_program_instruction + && !index_account.found_system + { + index_account.system = index; + index_account.found_system = true; + } else if index_account.found_system && matches!(program_id, ProgramId::LightSystem) { + index_account.cpi.push(index); + } else if index_account.found_system && matches!(program_id, ProgramId::LightToken) { + // Token program Transfer2 instruction in the CPI chain. + // Track tentatively - will only be confirmed if registry is found later. + // Only track the first one (closest to system instruction). + if tentative_token.is_none() { + tentative_token = Some(index); + } + } else if index_account.found_system && matches!(program_id, ProgramId::Registry) { + // Registry program instruction - confirms token tracking for ATA owner extraction. + // Since we search backwards, registry is found after token in the search order, + // but registry is the outer caller in the actual CPI chain. + index_account.found_registry = true; + // Confirm the tentative token index now that we found registry + if index_account.token.is_none() { + index_account.token = tentative_token; + } + } else if matches!(program_id, ProgramId::AccountCompression) && index_account.found_system + { + // Possibly found next light transaction. + return (Some(index_account), index); + } else if !index_account.found_system { + // If no system program found pattern incomplete. + // Else search for cpi instructions until we find account compression program id. + return (None, index); + } + } + if index_account.found_system { + (Some(index_account), 0) + } else { + (None, 0) + } +} + +pub fn wrap_program_ids( + program_ids: &[Pubkey], + instructions: &[Vec], + accounts: &[Vec], +) -> Vec { + let mut vec = Vec::new(); + for ((instruction, program_id), accounts) in instructions + .iter() + .zip(program_ids.iter()) + .zip(accounts.iter()) + { + if instruction.len() < 12 { + vec.push(ProgramId::Unknown); + continue; + } + let discriminator: [u8; 8] = instruction[0..8].try_into().unwrap(); + if program_id == &Pubkey::default() { + vec.push(ProgramId::SolanaSystem); + } else if program_id == &LIGHT_SYSTEM_PROGRAM_ID { + if discriminator == CREATE_CPI_CONTEXT_ACCOUNT { + vec.push(ProgramId::Unknown); + } else { + vec.push(ProgramId::LightSystem); + } + } else if program_id == &ACCOUNT_COMPRESSION_PROGRAM_ID { + if discriminator == DISCRIMINATOR_INSERT_INTO_QUEUES + && accounts.len() > 2 + && accounts[1] == REGISTERED_PROGRAM_PDA + { + vec.push(ProgramId::AccountCompression); + } else { + vec.push(ProgramId::Unknown); + } + } else if program_id == &Pubkey::from(LIGHT_TOKEN_PROGRAM_ID) { + // Token program Transfer2 instruction + if !instruction.is_empty() && instruction[0] == TRANSFER2 { + vec.push(ProgramId::LightToken); + } else { + vec.push(ProgramId::Unknown); + } + } else if program_id == &LIGHT_REGISTRY_PROGRAM_ID { + vec.push(ProgramId::Registry); + } else { + vec.push(ProgramId::Unknown); + } + } + vec +} + +fn deserialize_instruction<'a>( + instruction: &'a [u8], + accounts: &'a [Pubkey], +) -> Result, ParseIndexerEventError> { + if instruction.len() < 12 { + return Err(ParseIndexerEventError::InstructionDataTooSmall( + instruction.len(), + 12, + )); + } + let instruction_discriminator = instruction[0..8].try_into().unwrap(); + let instruction = instruction.split_at(8).1; + match instruction_discriminator { + // Cannot be exucted with cpi context -> executing tx + DISCRIMINATOR_INVOKE => { + if accounts.len() < 9 { + return Err(ParseIndexerEventError::DeserializeSystemInstructionError); + } + let accounts = accounts.split_at(9).1; + // Skips vec size bytes + let data = InstructionDataInvoke::deserialize(&mut &instruction[4..])?; + Ok(ExecutingSystemInstruction { + output_compressed_accounts: data.output_compressed_accounts, + input_compressed_accounts: data.input_compressed_accounts_with_merkle_context, + is_compress: data.is_compress, + relay_fee: data.relay_fee, + compress_or_decompress_lamports: data.compress_or_decompress_lamports, + execute_cpi_context: false, + accounts, + }) + } + DISCRIMINATOR_INVOKE_CPI => { + if accounts.len() < 11 { + return Err(ParseIndexerEventError::DeserializeSystemInstructionError); + } + let accounts = accounts.split_at(11).1; + let data = light_compressed_account::instruction_data::invoke_cpi::InstructionDataInvokeCpi::deserialize( + &mut &instruction[4..], + )?; + Ok(ExecutingSystemInstruction { + output_compressed_accounts: data.output_compressed_accounts, + input_compressed_accounts: data.input_compressed_accounts_with_merkle_context, + is_compress: data.is_compress, + relay_fee: data.relay_fee, + compress_or_decompress_lamports: data.compress_or_decompress_lamports, + execute_cpi_context: data.cpi_context.is_some(), + accounts, + }) + } + DISCRIMINATOR_INVOKE_CPI_WITH_READ_ONLY => { + // Min len for a small instruction 3 accounts + 1 tree or queue + // Fee payer + authority + registered program + account compression program + account compression authority + if accounts.len() < 5 { + return Err(ParseIndexerEventError::DeserializeSystemInstructionError); + } + let data: InstructionDataInvokeCpiWithReadOnly = + InstructionDataInvokeCpiWithReadOnly::deserialize(&mut &instruction[..])?; + let system_accounts_len = if data.mode == 0 { + 11 + } else { + let mut len = 6; // fee_payer + authority + registered_program + account_compression_program + account_compression_authority + system_program + if data.compress_or_decompress_lamports > 0 { + len += 1; + } + if !data.is_compress && data.compress_or_decompress_lamports > 0 { + len += 1; + } + if data.with_cpi_context { + len += 1; + } + len + }; + + let accounts = accounts.split_at(system_accounts_len).1; + Ok(ExecutingSystemInstruction { + output_compressed_accounts: data.output_compressed_accounts, + input_compressed_accounts: data + .input_compressed_accounts + .iter() + .map(|x| { + x.into_packed_compressed_account_with_merkle_context( + data.invoking_program_id, + ) + }) + .collect::>(), + is_compress: data.is_compress && data.compress_or_decompress_lamports > 0, + relay_fee: None, + compress_or_decompress_lamports: if data.compress_or_decompress_lamports == 0 { + None + } else { + Some(data.compress_or_decompress_lamports) + }, + execute_cpi_context: data.with_cpi_context, + accounts, + }) + } + INVOKE_CPI_WITH_ACCOUNT_INFO_INSTRUCTION => { + // Min len for a small instruction 4 accounts + 1 tree or queue + // Fee payer + authority + registered program + account compression program + account compression authority + if accounts.len() < 5 { + return Err(ParseIndexerEventError::DeserializeSystemInstructionError); + } + let data: InstructionDataInvokeCpiWithAccountInfo = + InstructionDataInvokeCpiWithAccountInfo::deserialize(&mut &instruction[..])?; + let system_accounts_len = if data.mode == 0 { + 11 + } else { + let mut len = 6; // fee_payer + authority + registered_program + account_compression_program + account_compression_authority + system_program + if data.compress_or_decompress_lamports > 0 { + len += 1; + } + if !data.is_compress && data.compress_or_decompress_lamports > 0 { + len += 1; + } + if data.with_cpi_context { + len += 1; + } + len + }; + let accounts = accounts.split_at(system_accounts_len).1; + + let instruction = ExecutingSystemInstruction { + output_compressed_accounts: data + .account_infos + .iter() + .filter(|x| x.output.is_some()) + .map(|x| { + let account = x.output.as_ref().unwrap(); + OutputCompressedAccountWithPackedContext { + compressed_account: CompressedAccount { + address: x.address, + owner: data.invoking_program_id, + lamports: account.lamports, + data: Some(CompressedAccountData { + discriminator: account.discriminator, + data: account.data.clone(), + data_hash: account.data_hash, + }), + }, + merkle_tree_index: account.output_merkle_tree_index, + } + }) + .collect::>(), + input_compressed_accounts: data + .account_infos + .iter() + .filter(|x| x.input.is_some()) + .map(|x| { + let account = x.input.as_ref().unwrap(); + PackedCompressedAccountWithMerkleContext { + compressed_account: CompressedAccount { + address: x.address, + owner: data.invoking_program_id, + lamports: account.lamports, + data: Some(CompressedAccountData { + discriminator: account.discriminator, + data: vec![], + data_hash: account.data_hash, + }), + }, + read_only: false, + root_index: account.root_index, + merkle_context: account.merkle_context, + } + }) + .collect::>(), + is_compress: data.is_compress && data.compress_or_decompress_lamports > 0, + relay_fee: None, + compress_or_decompress_lamports: if data.compress_or_decompress_lamports == 0 { + None + } else { + Some(data.compress_or_decompress_lamports) + }, + execute_cpi_context: data.with_cpi_context, + accounts, + }; + + Ok(instruction) + } + _ => Err(ParseIndexerEventError::DeserializeSystemInstructionError), + } +} + +/// Extract ATA owner info from token instruction's out_tlv. +/// Returns a Vec of (output_index, wallet_owner) for ATAs. +pub fn extract_ata_owners( + token_instruction: &TokenInstructionData, +) -> Vec { + let mut ata_owners = Vec::new(); + + // Token instruction format: [discriminator (1 byte)] [serialized data] + if token_instruction.data.is_empty() || token_instruction.data[0] != TRANSFER2 { + return ata_owners; + } + + // Skip discriminator byte and deserialize using borsh + let data = &token_instruction.data[1..]; + let Ok(transfer_data) = CompressedTokenInstructionDataTransfer2::deserialize(&mut &data[..]) + else { + return ata_owners; + }; + + // Check if there's out_tlv data + let Some(out_tlv) = transfer_data.out_tlv.as_ref() else { + return ata_owners; + }; + + // Iterate over output TLV entries (one per output token account) + for (output_index, tlv_extensions) in out_tlv.iter().enumerate() { + // Look for CompressedOnly extension with is_ata=true + for ext in tlv_extensions.iter() { + if let ExtensionInstructionData::CompressedOnly(compressed_only) = ext { + if compressed_only.is_ata { + // Get wallet owner from packed_accounts using owner_index. + // owner_index is an index into packed_accounts, which starts at position 7 + // in the Transfer2 accounts array (after the 7 system accounts). + const TRANSFER2_PACKED_ACCOUNTS_OFFSET: usize = 7; + let owner_idx = + compressed_only.owner_index as usize + TRANSFER2_PACKED_ACCOUNTS_OFFSET; + if owner_idx < token_instruction.accounts.len() { + ata_owners.push(AssociatedTokenAccountOwnerInfo { + output_index: output_index as u8, + wallet_owner: token_instruction.accounts[owner_idx], + }); + } + } + } + } + } + + ata_owners +} + +fn create_batched_transaction_event( + associated_instructions: &AssociatedInstructions, +) -> Result { + let input_sequence_numbers = associated_instructions + .insert_into_queues_instruction + .input_sequence_numbers + .iter() + .map(From::from) + .filter(|x: &MerkleTreeSequenceNumber| !(*x).is_empty()) + .collect::>(); + let mut batched_transaction_event = BatchPublicTransactionEvent { + event: PublicTransactionEvent { + input_compressed_account_hashes: associated_instructions + .insert_into_queues_instruction + .nullifiers + .iter() + .map(|x| x.account_hash) + .collect(), + output_compressed_account_hashes: associated_instructions + .insert_into_queues_instruction + .leaves + .iter() + .map(|x| x.leaf) + .collect(), + output_compressed_accounts: [ + associated_instructions.cpi_context_outputs.clone(), + associated_instructions + .executing_system_instruction + .output_compressed_accounts + .clone(), + ] + .concat(), + output_leaf_indices: associated_instructions + .insert_into_queues_instruction + .output_leaf_indices + .iter() + .map(|x| u32::from(*x)) + .collect(), + sequence_numbers: associated_instructions + .insert_into_queues_instruction + .output_sequence_numbers + .iter() + .map(From::from) + .filter(|x: &MerkleTreeSequenceNumber| !(*x).is_empty()) + .map(|x| MerkleTreeSequenceNumberV1 { + seq: x.seq, + tree_pubkey: x.tree_pubkey, + }) + .collect(), + relay_fee: associated_instructions + .executing_system_instruction + .relay_fee, + is_compress: associated_instructions + .executing_system_instruction + .is_compress, + compress_or_decompress_lamports: associated_instructions + .executing_system_instruction + .compress_or_decompress_lamports, + pubkey_array: associated_instructions + .executing_system_instruction + .accounts + .to_vec(), + message: None, + ata_owners: associated_instructions + .token_instruction + .as_ref() + .map(extract_ata_owners) + .unwrap_or_default(), + }, + tx_hash: associated_instructions + .insert_into_queues_instruction + .tx_hash, + new_addresses: associated_instructions + .insert_into_queues_instruction + .addresses + .iter() + .map(|x| NewAddress { + address: x.address, + mt_pubkey: associated_instructions.accounts[x.tree_index as usize], + queue_index: u64::MAX, + }) + .collect::>(), + address_sequence_numbers: associated_instructions + .insert_into_queues_instruction + .address_sequence_numbers + .iter() + .map(From::from) + .filter(|x: &MerkleTreeSequenceNumber| !(*x).is_empty()) + .collect::>(), + batch_input_accounts: associated_instructions + .insert_into_queues_instruction + .nullifiers + .iter() + .filter(|x| { + input_sequence_numbers.iter().any(|y| { + y.tree_pubkey == associated_instructions.accounts[x.tree_index as usize] + }) + }) + .map(|n| { + Ok(BatchNullifyContext { + tx_hash: associated_instructions + .insert_into_queues_instruction + .tx_hash, + account_hash: n.account_hash, + nullifier: { + // The nullifier is computed inside the account compression program. + // -> it is not part of the cpi system to account compression program that we index. + // -> we need to compute the nullifier here. + create_nullifier( + &n.account_hash, + n.leaf_index.into(), + &associated_instructions + .insert_into_queues_instruction + .tx_hash, + )? + }, + nullifier_queue_index: u64::MAX, + }) + }) + .collect::, ParseIndexerEventError>>()?, + input_sequence_numbers, + }; + + let nullifier_queue_indices = create_nullifier_queue_indices( + associated_instructions, + batched_transaction_event.batch_input_accounts.len(), + ); + + batched_transaction_event + .batch_input_accounts + .iter_mut() + .zip(nullifier_queue_indices.iter()) + .for_each(|(context, index)| { + context.nullifier_queue_index = *index; + }); + + let address_queue_indices = create_address_queue_indices( + associated_instructions, + batched_transaction_event.new_addresses.len(), + ); + + batched_transaction_event + .new_addresses + .iter_mut() + .zip(address_queue_indices.iter()) + .for_each(|(context, index)| { + context.queue_index = *index; + }); + + Ok(batched_transaction_event) +} + +fn create_nullifier_queue_indices( + associated_instructions: &AssociatedInstructions, + len: usize, +) -> Vec { + let input_merkle_tree_pubkeys = associated_instructions + .executing_system_instruction + .input_compressed_accounts + .iter() + .map(|x| { + associated_instructions + .executing_system_instruction + .accounts[x.merkle_context.merkle_tree_pubkey_index as usize] + }) + .collect::>(); + let mut internal_input_sequence_numbers = associated_instructions + .insert_into_queues_instruction + .input_sequence_numbers + .to_vec(); + // For every sequence number: + // 1. Find every input compressed account + // 2. assign sequence number as nullifier queue index + // 3. increment the sequence number + // Fix: size the indices vec to match input_merkle_tree_pubkeys (which i indexes into), + // not the filtered batch_input_accounts count. The caller zips with batch_input_accounts + // so extra entries are harmlessly ignored. + let mut nullifier_queue_indices = vec![u64::MAX; input_merkle_tree_pubkeys.len()]; + internal_input_sequence_numbers.iter_mut().for_each(|seq| { + for (i, merkle_tree_pubkey) in input_merkle_tree_pubkeys.iter().enumerate() { + if *merkle_tree_pubkey == seq.tree_pubkey { + nullifier_queue_indices[i] = seq.seq.into(); + seq.seq += 1; + } + } + }); + nullifier_queue_indices +} + +fn create_address_queue_indices( + associated_instructions: &AssociatedInstructions, + len: usize, +) -> Vec { + let address_merkle_tree_pubkeys = associated_instructions + .insert_into_queues_instruction + .addresses + .iter() + .map(|x| associated_instructions.accounts[x.tree_index as usize]) + .collect::>(); + let mut address_queue_indices = vec![u64::MAX; len]; + let mut internal_address_sequence_numbers = associated_instructions + .insert_into_queues_instruction + .address_sequence_numbers + .to_vec(); + internal_address_sequence_numbers + .iter_mut() + .for_each(|seq| { + for (i, merkle_tree_pubkey) in address_merkle_tree_pubkeys.iter().enumerate() { + if *merkle_tree_pubkey == seq.tree_pubkey { + address_queue_indices[i] = seq.seq.into(); + seq.seq += 1; + } + } + }); + address_queue_indices +} diff --git a/light-event-patched/tests/parse_test.rs b/light-event-patched/tests/parse_test.rs new file mode 100644 index 00000000..be470958 --- /dev/null +++ b/light-event-patched/tests/parse_test.rs @@ -0,0 +1,1287 @@ +use borsh::BorshSerialize; +use light_compressed_account::{ + constants::{ + ACCOUNT_COMPRESSION_PROGRAM_ID, LIGHT_REGISTRY_PROGRAM_ID, REGISTERED_PROGRAM_PDA, + }, + discriminators::DISCRIMINATOR_INSERT_INTO_QUEUES, + Pubkey, +}; +use light_event::parse::{ + extract_ata_owners, find_cpi_pattern, find_cpi_patterns, wrap_program_ids, Indices, ProgramId, + TokenInstructionData, +}; +use light_token_interface::{ + instructions::{ + extensions::{CompressedOnlyExtensionInstructionData, ExtensionInstructionData}, + transfer2::{CompressedTokenInstructionDataTransfer2, MultiTokenTransferOutputData}, + }, + LIGHT_TOKEN_PROGRAM_ID, TRANSFER2, +}; +use rand::{ + rngs::{StdRng, ThreadRng}, + Rng, RngCore, SeedableRng, +}; + +fn get_rnd_program_id(rng: &mut R, with_system_program: bool) -> ProgramId { + let vec = [ + ProgramId::Unknown, + ProgramId::AccountCompression, + ProgramId::LightSystem, + ]; + let len = if with_system_program { 3 } else { 2 }; + let index = rng.gen_range(0..len); + vec[index] +} + +fn get_rnd_program_ids( + rng: &mut R, + len: usize, + with_system_program: bool, +) -> Vec { + (0..len) + .map(|_| get_rnd_program_id(rng, with_system_program)) + .collect() +} + +/// Helper to create valid Transfer2 instruction data with ATA extensions +fn create_transfer2_with_ata(owner_index: u8, is_ata: bool) -> Vec { + let transfer_data = CompressedTokenInstructionDataTransfer2 { + with_transaction_hash: false, + with_lamports_change_account_merkle_tree_index: false, + lamports_change_account_merkle_tree_index: 0, + lamports_change_account_owner_index: 0, + output_queue: 0, + max_top_up: 0, + cpi_context: None, + compressions: None, + proof: None, + in_token_data: vec![], + out_token_data: vec![MultiTokenTransferOutputData { + owner: owner_index, + amount: 1000, + has_delegate: false, + delegate: 0, + mint: 0, + version: 3, + }], + in_lamports: None, + out_lamports: None, + in_tlv: None, + out_tlv: Some(vec![vec![ExtensionInstructionData::CompressedOnly( + CompressedOnlyExtensionInstructionData { + delegated_amount: 0, + withheld_transfer_fee: 0, + is_frozen: false, + compression_index: 0, + is_ata, + bump: 255, + owner_index, + }, + )]]), + }; + let mut data = vec![TRANSFER2]; // discriminator + data.extend(transfer_data.try_to_vec().unwrap()); + data +} + +/// Helper to create Transfer2 instruction data with multiple outputs +fn create_transfer2_with_multiple_outputs( + outputs: Vec<(u8, bool)>, // (owner_index, is_ata) +) -> Vec { + let out_token_data: Vec = outputs + .iter() + .map(|(owner_index, _)| MultiTokenTransferOutputData { + owner: *owner_index, + amount: 1000, + has_delegate: false, + delegate: 0, + mint: 0, + version: 3, + }) + .collect(); + + let out_tlv: Vec> = outputs + .iter() + .map(|(owner_index, is_ata)| { + vec![ExtensionInstructionData::CompressedOnly( + CompressedOnlyExtensionInstructionData { + delegated_amount: 0, + withheld_transfer_fee: 0, + is_frozen: false, + compression_index: 0, + is_ata: *is_ata, + bump: 255, + owner_index: *owner_index, + }, + )] + }) + .collect(); + + let transfer_data = CompressedTokenInstructionDataTransfer2 { + with_transaction_hash: false, + with_lamports_change_account_merkle_tree_index: false, + lamports_change_account_merkle_tree_index: 0, + lamports_change_account_owner_index: 0, + output_queue: 0, + max_top_up: 0, + cpi_context: None, + compressions: None, + proof: None, + in_token_data: vec![], + out_token_data, + in_lamports: None, + out_lamports: None, + in_tlv: None, + out_tlv: Some(out_tlv), + }; + let mut data = vec![TRANSFER2]; + data.extend(transfer_data.try_to_vec().unwrap()); + data +} + +#[test] +fn test_rnd_functional() { + let mut thread_rng = ThreadRng::default(); + let seed = thread_rng.next_u64(); + // Keep this print so that in case the test fails + // we can use the seed to reproduce the error. + println!("\n\ntest seed {}\n\n", seed); + let mut rng = StdRng::seed_from_u64(seed); + let num_iters = 100000; + for _ in 0..num_iters { + let len_pre = rng.gen_range(0..6); + let rnd_vec_pre = get_rnd_program_ids(&mut rng, len_pre, false); + let len_post = rng.gen_range(0..6); + let rnd_vec_post = get_rnd_program_ids(&mut rng, len_post, false); + let num_mid = rng.gen_range(1..6); + + let program_ids = [ + rnd_vec_pre.as_slice(), + [ProgramId::LightSystem].as_slice(), + vec![ProgramId::SolanaSystem; num_mid].as_slice(), + [ProgramId::AccountCompression].as_slice(), + rnd_vec_post.as_slice(), + ] + .concat(); + let start_index = program_ids.len() - 1 - len_post; + let system_index = program_ids.len() - 1 - len_post - num_mid - 1; + let vec = find_cpi_patterns(&program_ids); + let expected = Indices { + system: system_index, + cpi: vec![], + insert_into_queues: start_index, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + }; + assert!( + vec.contains(&expected), + "program ids {:?} parsed events {:?} expected {:?} ", + program_ids, + vec, + expected, + ); + } + + for _ in 0..num_iters { + let len_pre = rng.gen_range(0..6); + let rnd_vec_pre = get_rnd_program_ids(&mut rng, len_pre, true); + let len_post = rng.gen_range(0..6); + let rnd_vec_post = get_rnd_program_ids(&mut rng, len_post, true); + let num_mid = rng.gen_range(1..6); + + let program_ids = [ + rnd_vec_pre.as_slice(), + [ProgramId::LightSystem].as_slice(), + vec![ProgramId::SolanaSystem; num_mid].as_slice(), + [ProgramId::AccountCompression].as_slice(), + rnd_vec_post.as_slice(), + ] + .concat(); + let start_index = program_ids.len() - 1 - len_post; + let system_index = program_ids.len() - 1 - len_post - num_mid - 1; + let vec = find_cpi_patterns(&program_ids); + let expected = Indices { + system: system_index, + cpi: vec![], + insert_into_queues: start_index, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + }; + assert!( + vec.iter().any(|x| x.system == expected.system + && x.insert_into_queues == expected.insert_into_queues), + "program ids {:?} parsed events {:?} expected {:?} ", + program_ids, + vec, + expected, + ); + } +} + +#[test] +fn test_rnd_failing() { + let mut thread_rng = ThreadRng::default(); + let seed = thread_rng.next_u64(); + // Keep this print so that in case the test fails + // we can use the seed to reproduce the error. + println!("\n\ntest seed {}\n\n", seed); + let mut rng = StdRng::seed_from_u64(seed); + let num_iters = 100000; + for _ in 0..num_iters { + let len = rng.gen_range(0..20); + let mut program_ids = get_rnd_program_ids(&mut rng, len, true); + // if any ProgramId::LightSystem is followed by ProgramId::SolanaSystem overwrite ProgramId::SolanaSystem with ProgramId::Unknown + for i in 0..program_ids.len().saturating_sub(1) { + if matches!(program_ids[i], ProgramId::LightSystem) + && matches!(program_ids[i + 1], ProgramId::SolanaSystem) + { + program_ids[i + 1] = ProgramId::Unknown; + } + } + + let vec = find_cpi_patterns(&program_ids); + + assert!( + vec.is_empty(), + "program_ids {:?} result {:?}", + program_ids, + vec + ); + } +} + +#[test] +fn test_find_two_patterns() { + // Std pattern + { + let program_ids = vec![ + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let vec = find_cpi_patterns(&program_ids); + assert_eq!(vec.len(), 2); + assert_eq!( + vec[0], + Indices { + system: 5, + cpi: vec![], + insert_into_queues: 7, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + } + ); + assert_eq!( + vec[1], + Indices { + system: 1, + cpi: vec![], + insert_into_queues: 3, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + } + ); + // Modify only second event is valid + { + let mut program_ids = program_ids.clone(); + program_ids[2] = ProgramId::Unknown; + let vec = find_cpi_patterns(&program_ids); + assert_eq!(vec.len(), 1); + assert_eq!( + vec[0], + Indices { + system: 5, + cpi: vec![], + insert_into_queues: 7, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + } + ); + } + // Modify only first event is valid + { + let mut program_ids = program_ids; + program_ids[6] = ProgramId::Unknown; + let vec = find_cpi_patterns(&program_ids); + assert_eq!(vec.len(), 1); + assert_eq!( + vec[0], + Indices { + system: 1, + cpi: vec![], + insert_into_queues: 3, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + } + ); + } + } +} + +#[test] +fn test_find_pattern() { + // Std pattern + { + let program_ids = vec![ + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, last_index) = find_cpi_pattern(3, &program_ids); + assert_eq!(last_index, 0); + assert_eq!( + res, + Some(Indices { + system: 1, + cpi: vec![], + insert_into_queues: 3, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + }) + ); + } + { + let program_ids = vec![ + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::SolanaSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let start_index = program_ids.len() - 1; + let (res, last_index) = find_cpi_pattern(start_index, &program_ids); + assert_eq!(last_index, 0); + assert_eq!( + res, + Some(Indices { + system: 1, + cpi: vec![], + insert_into_queues: start_index, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + }) + ); + } + { + let program_ids = vec![ + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::Unknown, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let start_index = program_ids.len() - 1; + let (res, last_index) = find_cpi_pattern(start_index, &program_ids); + assert_eq!(last_index, 3); + assert_eq!(res, None); + } + // With cpi context + { + let program_ids = vec![ + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::SolanaSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let start_index = program_ids.len() - 1; + let (res, last_index) = find_cpi_pattern(start_index, &program_ids); + assert_eq!(last_index, 0); + assert_eq!( + res, + Some(Indices { + system: 3, + cpi: vec![1], + insert_into_queues: start_index, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + }) + ); + // Failing + { + let mut program_ids = program_ids; + program_ids[5] = ProgramId::Unknown; + let (res, last_index) = find_cpi_pattern(start_index, &program_ids); + assert_eq!(last_index, 5); + assert_eq!(res, None); + } + } + // With cpi context + { + let program_ids = vec![ + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::SolanaSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let start_index = program_ids.len() - 1; + let (res, last_index) = find_cpi_pattern(start_index, &program_ids); + assert_eq!(last_index, 0); + assert_eq!( + res, + Some(Indices { + system: 2, + cpi: vec![1], + insert_into_queues: start_index, + found_solana_system_program_instruction: true, + found_system: true, + token: None, + found_registry: false, + }) + ); + // Failing + { + let mut program_ids = program_ids; + program_ids[4] = ProgramId::Unknown; + let (res, last_index) = find_cpi_pattern(start_index, &program_ids); + assert_eq!(last_index, 4); + assert_eq!(res, None); + } + } +} + +// ========================================================================== +// Tests for extract_ata_owners +// ========================================================================== + +#[test] +fn test_extract_ata_owners_empty_data() { + let token_instruction = TokenInstructionData { + data: &[], + accounts: &[], + }; + let result = extract_ata_owners(&token_instruction); + assert!(result.is_empty(), "Empty data should return empty vec"); +} + +#[test] +fn test_extract_ata_owners_wrong_discriminator() { + let token_instruction = TokenInstructionData { + data: &[0xFF, 0x00, 0x00], // Wrong discriminator + accounts: &[], + }; + let result = extract_ata_owners(&token_instruction); + assert!( + result.is_empty(), + "Wrong discriminator should return empty vec" + ); +} + +#[test] +fn test_extract_ata_owners_only_discriminator() { + let token_instruction = TokenInstructionData { + data: &[TRANSFER2], // Only discriminator, no data + accounts: &[], + }; + let result = extract_ata_owners(&token_instruction); + assert!( + result.is_empty(), + "Only discriminator should return empty vec (deserialization fails)" + ); +} + +#[test] +fn test_extract_ata_owners_malformed_data() { + // Random garbage after discriminator + let token_instruction = TokenInstructionData { + data: &[TRANSFER2, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], + accounts: &[], + }; + let result = extract_ata_owners(&token_instruction); + assert!( + result.is_empty(), + "Malformed data should return empty vec (deserialization fails)" + ); +} + +#[test] +fn test_extract_ata_owners_valid_non_ata() { + let data = create_transfer2_with_ata(0, false); // is_ata = false + let accounts = vec![Pubkey::default(); 10]; + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + assert!( + result.is_empty(), + "Non-ATA accounts should not produce ATA owner info" + ); +} + +#[test] +fn test_extract_ata_owners_valid_ata() { + let owner_index = 2u8; // Index into packed_accounts + let data = create_transfer2_with_ata(owner_index, true); + + // Create accounts array: 7 system accounts + packed_accounts + // owner_index=2 means packed_accounts[2] = accounts[7+2] = accounts[9] + let mut accounts = vec![Pubkey::default(); 10]; + let expected_owner = Pubkey::new_from_array([42u8; 32]); + accounts[7 + owner_index as usize] = expected_owner; + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + assert_eq!(result.len(), 1, "Should extract one ATA owner"); + assert_eq!(result[0].output_index, 0); + assert_eq!(result[0].wallet_owner, expected_owner); +} + +#[test] +fn test_extract_ata_owners_owner_index_out_of_bounds() { + let owner_index = 100u8; // Way beyond accounts array + let data = create_transfer2_with_ata(owner_index, true); + + // Only 10 accounts, but owner_index + 7 = 107 + let accounts = vec![Pubkey::default(); 10]; + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + assert!( + result.is_empty(), + "Out of bounds owner_index should be safely skipped" + ); +} + +#[test] +fn test_extract_ata_owners_boundary_owner_index() { + // Test with owner_index at the boundary + let owner_index = 2u8; + let data = create_transfer2_with_ata(owner_index, true); + + // Create exactly enough accounts: 7 system + 3 packed (indices 0, 1, 2) + // owner_index=2 needs accounts[9], so we need 10 accounts total + let mut accounts = vec![Pubkey::default(); 10]; + let expected_owner = Pubkey::new_from_array([99u8; 32]); + accounts[9] = expected_owner; + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + assert_eq!(result.len(), 1); + assert_eq!(result[0].wallet_owner, expected_owner); + + // Now with one less account - should be skipped + let accounts_short = vec![Pubkey::default(); 9]; + let token_instruction_short = TokenInstructionData { + data: &data, + accounts: &accounts_short, + }; + let result_short = extract_ata_owners(&token_instruction_short); + assert!( + result_short.is_empty(), + "Boundary case with insufficient accounts should be skipped" + ); +} + +#[test] +fn test_extract_ata_owners_max_owner_index() { + // Test with u8::MAX owner_index + let owner_index = u8::MAX; + let data = create_transfer2_with_ata(owner_index, true); + + // 255 + 7 = 262, need 263 accounts + let accounts = vec![Pubkey::default(); 10]; // Way too few + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + assert!( + result.is_empty(), + "u8::MAX owner_index with small accounts array should be safely skipped" + ); +} + +// ========================================================================== +// Tests for wrap_program_ids with LightToken and Registry +// ========================================================================== + +#[test] +fn test_wrap_program_ids_light_token_transfer2() { + let program_ids = vec![Pubkey::from(LIGHT_TOKEN_PROGRAM_ID)]; + let mut instruction_data = vec![0u8; 12]; // Minimum size + instruction_data[0] = TRANSFER2; + let instructions = vec![instruction_data]; + let accounts = vec![vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!(result, vec![ProgramId::LightToken]); +} + +#[test] +fn test_wrap_program_ids_light_token_non_transfer2() { + let program_ids = vec![Pubkey::from(LIGHT_TOKEN_PROGRAM_ID)]; + let mut instruction_data = vec![0u8; 12]; + instruction_data[0] = 0xFF; // Not TRANSFER2 + let instructions = vec![instruction_data]; + let accounts = vec![vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!(result, vec![ProgramId::Unknown]); +} + +#[test] +fn test_wrap_program_ids_registry() { + let program_ids = vec![Pubkey::from(LIGHT_REGISTRY_PROGRAM_ID)]; + let instruction_data = vec![0u8; 12]; + let instructions = vec![instruction_data]; + let accounts = vec![vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!(result, vec![ProgramId::Registry]); +} + +#[test] +fn test_wrap_program_ids_instruction_too_small() { + let program_ids = vec![Pubkey::from(LIGHT_TOKEN_PROGRAM_ID)]; + let instruction_data = vec![TRANSFER2; 5]; // Less than 12 bytes + let instructions = vec![instruction_data]; + let accounts = vec![vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!( + result, + vec![ProgramId::Unknown], + "Instructions smaller than 12 bytes should be Unknown" + ); +} + +// ========================================================================== +// Tests for find_cpi_pattern with Registry and Token tracking +// ========================================================================== + +#[test] +fn test_find_cpi_pattern_with_registry_and_token() { + // Pattern: Registry -> Token -> LightSystem -> SolanaSystem -> AccountCompression + let program_ids = vec![ + ProgramId::Registry, + ProgramId::LightToken, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(4, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(indices.found_registry, "Should find registry"); + assert_eq!( + indices.token, + Some(1), + "Should track token when registry is present" + ); + assert_eq!(indices.system, 2); +} + +#[test] +fn test_find_cpi_pattern_token_without_registry() { + // Pattern: Token -> LightSystem -> SolanaSystem -> AccountCompression + // No registry means token should NOT be tracked + let program_ids = vec![ + ProgramId::LightToken, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(3, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(!indices.found_registry, "Should not find registry"); + assert_eq!( + indices.token, None, + "Should NOT track token without registry" + ); +} + +#[test] +fn test_find_cpi_pattern_registry_without_token() { + // Registry can call LightSystem directly without Token + // Pattern: Registry -> LightSystem -> SolanaSystem -> AccountCompression + let program_ids = vec![ + ProgramId::Registry, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(3, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(indices.found_registry, "Should find registry"); + assert_eq!(indices.token, None, "No token instruction in this pattern"); +} + +#[test] +fn test_find_cpi_pattern_multiple_tokens_only_first_tracked() { + // Only the first (closest to system) token should be tracked + // Pattern: Registry -> Token1 -> Token2 -> LightSystem -> SolanaSystem -> AccountCompression + let program_ids = vec![ + ProgramId::Registry, + ProgramId::LightToken, // Token1 - outer + ProgramId::LightToken, // Token2 - inner, should be tracked + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(5, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(indices.found_registry); + // The inner token (index 2) should be tracked as it's first when searching backwards + assert_eq!( + indices.token, + Some(2), + "Should track the token closest to system instruction" + ); +} + +// ========================================================================== +// Additional ATA and Program ID filtering edge case tests +// ========================================================================== + +#[test] +fn test_find_cpi_pattern_token_after_account_compression_not_tracked() { + // Token appearing after AccountCompression should not be part of this pattern + // Pattern: Registry -> LightSystem -> SolanaSystem -> AccountCompression -> Token + let program_ids = vec![ + ProgramId::Registry, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ProgramId::LightToken, // After AccountCompression - not part of this pattern + ]; + let (res, _) = find_cpi_pattern(3, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(indices.found_registry); + assert_eq!( + indices.token, None, + "Token after AccountCompression should not be tracked in this pattern" + ); +} + +#[test] +fn test_find_cpi_pattern_registry_after_account_compression_not_found() { + // Registry appearing after AccountCompression should not validate token tracking + // Pattern: Token -> LightSystem -> SolanaSystem -> AccountCompression -> Registry + let program_ids = vec![ + ProgramId::LightToken, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ProgramId::Registry, // After AccountCompression - not part of this pattern + ]; + let (res, _) = find_cpi_pattern(3, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!( + !indices.found_registry, + "Registry after AccountCompression should not be found" + ); + assert_eq!( + indices.token, None, + "Token should not be tracked without registry before AccountCompression" + ); +} + +#[test] +fn test_find_cpi_pattern_token_between_unknown_programs() { + // Token surrounded by Unknown programs, with Registry present + // Pattern: Registry -> Unknown -> Token -> Unknown -> LightSystem -> SolanaSystem -> AccountCompression + let program_ids = vec![ + ProgramId::Registry, + ProgramId::Unknown, + ProgramId::LightToken, + ProgramId::Unknown, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(6, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(indices.found_registry); + assert_eq!( + indices.token, + Some(2), + "Token should be tracked even with Unknown programs around it" + ); +} + +#[test] +fn test_find_cpi_pattern_empty_program_ids() { + let program_ids: Vec = vec![]; + let patterns = find_cpi_patterns(&program_ids); + assert!( + patterns.is_empty(), + "Empty program IDs should return no patterns" + ); +} + +#[test] +fn test_find_cpi_pattern_single_account_compression() { + let program_ids = vec![ProgramId::AccountCompression]; + let (res, _) = find_cpi_pattern(0, &program_ids); + assert!( + res.is_none(), + "Single AccountCompression without system should not match" + ); +} + +#[test] +fn test_find_cpi_pattern_registry_token_no_system() { + // Registry and Token without LightSystem - invalid pattern + let program_ids = vec![ + ProgramId::Registry, + ProgramId::LightToken, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(3, &program_ids); + assert!( + res.is_none(), + "Pattern without LightSystem should not match" + ); +} + +#[test] +fn test_find_cpi_pattern_token_at_position_zero_not_tracked() { + // Token at position 0 (outermost in CPI chain) - this is NOT a valid real-world pattern. + // In the actual protocol, Registry is always the outermost caller (Registry -> Token -> LightSystem). + // Pattern: Token -> Registry -> LightSystem -> SolanaSystem -> AccountCompression + // + // When searching backwards, we encounter Registry (index 1) BEFORE Token (index 0). + // At the point we find Registry, tentative_token is still None, so we don't confirm a token. + // Then we find Token at index 0, but Registry has already been processed. + // + // This behavior is CORRECT because Token being outermost is invalid - Registry must be outer. + let program_ids = vec![ + ProgramId::LightToken, // Position 0 - invalid as outermost + ProgramId::Registry, // Position 1 + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(4, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(indices.found_registry); + // Token at position 0 is NOT tracked because it appears AFTER Registry in backwards search. + // This is correct behavior - Token must be between Registry and LightSystem. + assert_eq!( + indices.token, None, + "Token at position 0 (before Registry in array) should NOT be tracked - invalid CPI order" + ); +} + +#[test] +fn test_find_cpi_pattern_multiple_registries() { + // Multiple Registry programs - behavior verification + // Pattern: Registry -> Registry -> Token -> LightSystem -> SolanaSystem -> AccountCompression + let program_ids = vec![ + ProgramId::Registry, // First Registry + ProgramId::Registry, // Second Registry + ProgramId::LightToken, + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(5, &program_ids); + assert!(res.is_some()); + let indices = res.unwrap(); + assert!(indices.found_registry, "Should find at least one registry"); + assert_eq!( + indices.token, + Some(2), + "Token should be tracked with registry present" + ); +} + +#[test] +fn test_find_cpi_pattern_token_before_system_instruction() { + // Token appearing before finding system instruction in backwards search + // Pattern: LightSystem -> SolanaSystem -> Token -> AccountCompression + // When searching backwards from AccountCompression, we find Token before system + let program_ids = vec![ + ProgramId::LightSystem, + ProgramId::SolanaSystem, + ProgramId::LightToken, // Between SolanaSystem and AccountCompression + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(3, &program_ids); + // This should fail because we need SolanaSystem right before AccountCompression + assert!( + res.is_none(), + "Token breaking the SolanaSystem -> AccountCompression chain should fail" + ); +} + +#[test] +fn test_find_cpi_pattern_registry_between_system_and_solana_system() { + // Registry between LightSystem and SolanaSystem + // Pattern: Registry -> LightSystem -> Registry -> SolanaSystem -> AccountCompression + let program_ids = vec![ + ProgramId::Registry, + ProgramId::LightSystem, + ProgramId::Registry, // Between LightSystem and SolanaSystem + ProgramId::SolanaSystem, + ProgramId::AccountCompression, + ]; + let (res, _) = find_cpi_pattern(4, &program_ids); + // Registry between should break the pattern + assert!( + res.is_none(), + "Registry between LightSystem and SolanaSystem should break pattern" + ); +} + +// ========================================================================== +// Additional extract_ata_owners edge case tests +// ========================================================================== + +#[test] +fn test_extract_ata_owners_multiple_outputs_all_ata() { + // Multiple outputs, all are ATAs + let data = create_transfer2_with_multiple_outputs(vec![ + (0, true), // output 0: ATA with owner at packed_accounts[0] + (1, true), // output 1: ATA with owner at packed_accounts[1] + (2, true), // output 2: ATA with owner at packed_accounts[2] + ]); + + let mut accounts = vec![Pubkey::default(); 12]; // 7 system + 5 packed + let owner0 = Pubkey::new_from_array([10u8; 32]); + let owner1 = Pubkey::new_from_array([11u8; 32]); + let owner2 = Pubkey::new_from_array([12u8; 32]); + accounts[7] = owner0; + accounts[8] = owner1; + accounts[9] = owner2; + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + + assert_eq!(result.len(), 3, "Should extract 3 ATA owners"); + assert_eq!(result[0].output_index, 0); + assert_eq!(result[0].wallet_owner, owner0); + assert_eq!(result[1].output_index, 1); + assert_eq!(result[1].wallet_owner, owner1); + assert_eq!(result[2].output_index, 2); + assert_eq!(result[2].wallet_owner, owner2); +} + +#[test] +fn test_extract_ata_owners_multiple_outputs_mixed() { + // Mixed: some ATA, some not + let data = create_transfer2_with_multiple_outputs(vec![ + (0, false), // output 0: NOT an ATA + (1, true), // output 1: ATA + (2, false), // output 2: NOT an ATA + (3, true), // output 3: ATA + ]); + + let mut accounts = vec![Pubkey::default(); 12]; + let owner1 = Pubkey::new_from_array([21u8; 32]); + let owner3 = Pubkey::new_from_array([23u8; 32]); + accounts[8] = owner1; // packed_accounts[1] + accounts[10] = owner3; // packed_accounts[3] + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + + assert_eq!(result.len(), 2, "Should only extract ATA outputs"); + assert_eq!(result[0].output_index, 1); + assert_eq!(result[0].wallet_owner, owner1); + assert_eq!(result[1].output_index, 3); + assert_eq!(result[1].wallet_owner, owner3); +} + +#[test] +fn test_extract_ata_owners_multiple_outputs_none_ata() { + // All outputs are non-ATA + let data = create_transfer2_with_multiple_outputs(vec![(0, false), (1, false), (2, false)]); + + let accounts = vec![Pubkey::default(); 12]; + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + + assert!( + result.is_empty(), + "Should not extract any owners when no ATAs" + ); +} + +#[test] +fn test_extract_ata_owners_same_owner_multiple_atas() { + // Multiple ATAs pointing to the same owner (same owner_index) + let data = create_transfer2_with_multiple_outputs(vec![ + (0, true), // output 0: ATA with owner at packed_accounts[0] + (0, true), // output 1: ATA with SAME owner + (0, true), // output 2: ATA with SAME owner + ]); + + let mut accounts = vec![Pubkey::default(); 10]; + let shared_owner = Pubkey::new_from_array([77u8; 32]); + accounts[7] = shared_owner; + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + + assert_eq!(result.len(), 3, "Should extract all 3 ATA entries"); + assert!( + result.iter().all(|r| r.wallet_owner == shared_owner), + "All should have the same owner" + ); + assert_eq!(result[0].output_index, 0); + assert_eq!(result[1].output_index, 1); + assert_eq!(result[2].output_index, 2); +} + +#[test] +fn test_extract_ata_owners_partial_out_of_bounds() { + // Some outputs have valid owner_index, some are out of bounds + let data = create_transfer2_with_multiple_outputs(vec![ + (0, true), // output 0: Valid owner_index + (100, true), // output 1: Out of bounds + (1, true), // output 2: Valid owner_index + ]); + + let mut accounts = vec![Pubkey::default(); 10]; + let owner0 = Pubkey::new_from_array([30u8; 32]); + let owner1 = Pubkey::new_from_array([31u8; 32]); + accounts[7] = owner0; + accounts[8] = owner1; + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + + assert_eq!(result.len(), 2, "Should only extract valid owner indices"); + assert_eq!(result[0].output_index, 0); + assert_eq!(result[0].wallet_owner, owner0); + assert_eq!(result[1].output_index, 2); + assert_eq!(result[1].wallet_owner, owner1); +} + +#[test] +fn test_extract_ata_owners_zero_packed_accounts() { + // Edge case: exactly 7 accounts (no packed_accounts at all) + let data = create_transfer2_with_ata(0, true); // Wants packed_accounts[0] which doesn't exist + + let accounts = vec![Pubkey::default(); 7]; // Only system accounts + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + + assert!( + result.is_empty(), + "Should not extract ATA when no packed_accounts exist" + ); +} + +#[test] +fn test_extract_ata_owners_exactly_one_packed_account() { + // Edge case: exactly 8 accounts (only one packed_account at index 0) + let data = create_transfer2_with_ata(0, true); + + let mut accounts = vec![Pubkey::default(); 8]; + let owner = Pubkey::new_from_array([55u8; 32]); + accounts[7] = owner; + + let token_instruction = TokenInstructionData { + data: &data, + accounts: &accounts, + }; + let result = extract_ata_owners(&token_instruction); + + assert_eq!(result.len(), 1); + assert_eq!(result[0].wallet_owner, owner); +} + +// ========================================================================== +// Tests for wrap_program_ids edge cases +// ========================================================================== + +#[test] +fn test_wrap_program_ids_empty_instruction_data() { + let program_ids = vec![Pubkey::from(LIGHT_TOKEN_PROGRAM_ID)]; + let instructions = vec![vec![]]; // Empty instruction data + let accounts = vec![vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!( + result, + vec![ProgramId::Unknown], + "Empty instruction should be Unknown" + ); +} + +#[test] +fn test_wrap_program_ids_exactly_12_bytes() { + // Boundary: exactly 12 bytes is valid + let program_ids = vec![Pubkey::from(LIGHT_TOKEN_PROGRAM_ID)]; + let mut instruction_data = vec![0u8; 12]; + instruction_data[0] = TRANSFER2; + let instructions = vec![instruction_data]; + let accounts = vec![vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!(result, vec![ProgramId::LightToken]); +} + +#[test] +fn test_wrap_program_ids_11_bytes() { + // Boundary: 11 bytes is too small + let program_ids = vec![Pubkey::from(LIGHT_TOKEN_PROGRAM_ID)]; + let mut instruction_data = vec![0u8; 11]; + instruction_data[0] = TRANSFER2; + let instructions = vec![instruction_data]; + let accounts = vec![vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!(result, vec![ProgramId::Unknown], "11 bytes is too small"); +} + +#[test] +fn test_wrap_program_ids_mixed_valid_invalid() { + // Mix of valid and invalid instructions + let program_ids = vec![ + Pubkey::from(LIGHT_TOKEN_PROGRAM_ID), + Pubkey::from(LIGHT_REGISTRY_PROGRAM_ID), + Pubkey::from(LIGHT_TOKEN_PROGRAM_ID), + Pubkey::from(LIGHT_TOKEN_PROGRAM_ID), + ]; + + let mut valid_transfer = vec![0u8; 12]; + valid_transfer[0] = TRANSFER2; + + let instructions = vec![ + valid_transfer.clone(), // Valid Token + TRANSFER2 + vec![0u8; 12], // Valid Registry (any 12+ bytes) + vec![0xFF; 12], // Token but not TRANSFER2 + vec![TRANSFER2; 5], // Token + TRANSFER2 but too short + ]; + let accounts = vec![vec![], vec![], vec![], vec![]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!( + result, + vec![ + ProgramId::LightToken, + ProgramId::Registry, + ProgramId::Unknown, + ProgramId::Unknown, + ] + ); +} + +#[test] +fn test_wrap_program_ids_account_compression_missing_registered_pda() { + // AccountCompression with wrong registered PDA + let program_ids = vec![Pubkey::from(ACCOUNT_COMPRESSION_PROGRAM_ID)]; + let mut instruction_data = vec![0u8; 12]; + instruction_data[0..8].copy_from_slice(&DISCRIMINATOR_INSERT_INTO_QUEUES); + let instructions = vec![instruction_data]; + // accounts[1] should be REGISTERED_PROGRAM_PDA but we use a different pubkey + let accounts = vec![vec![ + Pubkey::default(), + Pubkey::new_from_array([99u8; 32]), // Wrong PDA + Pubkey::default(), + ]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!( + result, + vec![ProgramId::Unknown], + "AccountCompression with wrong registered PDA should be Unknown" + ); +} + +#[test] +fn test_wrap_program_ids_account_compression_valid() { + // AccountCompression with correct setup + let program_ids = vec![Pubkey::from(ACCOUNT_COMPRESSION_PROGRAM_ID)]; + let mut instruction_data = vec![0u8; 12]; + instruction_data[0..8].copy_from_slice(&DISCRIMINATOR_INSERT_INTO_QUEUES); + let instructions = vec![instruction_data]; + let accounts = vec![vec![ + Pubkey::default(), + Pubkey::from(REGISTERED_PROGRAM_PDA), // Correct PDA + Pubkey::default(), + ]]; + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!(result, vec![ProgramId::AccountCompression]); +} + +#[test] +fn test_wrap_program_ids_account_compression_insufficient_accounts() { + // AccountCompression with too few accounts + let program_ids = vec![Pubkey::from(ACCOUNT_COMPRESSION_PROGRAM_ID)]; + let mut instruction_data = vec![0u8; 12]; + instruction_data[0..8].copy_from_slice(&DISCRIMINATOR_INSERT_INTO_QUEUES); + let instructions = vec![instruction_data]; + let accounts = vec![vec![Pubkey::default()]]; // Only 1 account, need 3 + + let result = wrap_program_ids(&program_ids, &instructions, &accounts); + assert_eq!( + result, + vec![ProgramId::Unknown], + "AccountCompression with insufficient accounts should be Unknown" + ); +}