From 170e1afd2f5bc5cc6aaf70f38fead2ec38ecee05 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Mon, 9 Mar 2026 16:14:19 +0000 Subject: [PATCH 01/16] feat: infrastructure updates (#332) * feat: infrastructure updates - migrations, ingester, prover API key, DAO schema, monitor, CLI args, dep updates - Add prover_api_key parameter to PhotonApi and validity proof methods - Add max_connections parameter to run_server - Add new migrations: onchain_pubkey, ata_owner, backfill_mint, ata_owner_index - Update ingester with startup cleanup, improved parsing, and persist logic - Update DAO generated models (accounts, token_accounts, queue_hash_chains, transactions) - Update monitor with queue monitoring and tree metadata sync improvements - Consolidate OpenAPI specs into single api.yaml - Fix OpenAPI AllOf handling and iterator usage - Update dependencies in Cargo.toml/Cargo.lock - Add token_layout module and update token_data types - Update snapshot loader/snapshotter and tree validator * refactor: remove unused backfill migration for mint onchain pubkey * refactor: rename compressed mint PDA constants to light mint PDA for clarity * refactor: remove parse_account_discriminator function and update usages for clarity * feat: add discriminator_v2 field and update related logic for account processing --- Cargo.lock | 2029 ++++++++++++++--- Cargo.toml | 21 +- src/api/api.rs | 19 +- .../get_compressed_accounts_by_owner/v1.rs | 2 +- .../get_compressed_accounts_by_owner/v2.rs | 2 +- .../get_compressed_token_balances_by_owner.rs | 3 +- .../method/get_multiple_new_address_proofs.rs | 4 +- src/api/method/get_queue_elements.rs | 82 +- .../get_validity_proof/prover/helpers.rs | 64 +- .../method/get_validity_proof/prover/prove.rs | 18 +- .../get_validity_proof/prover/structs.rs | 33 +- src/api/method/get_validity_proof/v1.rs | 5 +- src/api/method/get_validity_proof/v2.rs | 4 +- src/api/rpc_server.rs | 7 +- src/common/mod.rs | 1 + src/common/token_layout.rs | 14 + src/common/typedefs/account/context.rs | 15 +- src/common/typedefs/account/mod.rs | 5 +- src/common/typedefs/account/v1.rs | 23 +- src/common/typedefs/account/v2.rs | 31 +- src/common/typedefs/token_data.rs | 325 +-- src/dao/generated/accounts.rs | 16 +- src/dao/generated/queue_hash_chains.rs | 2 + src/dao/generated/token_accounts.rs | 1 + src/dao/generated/transactions.rs | 8 + src/dao/helpers.rs | 82 +- src/ingester/fetchers/mod.rs | 14 +- src/ingester/fetchers/poller.rs | 6 +- src/ingester/indexer/mod.rs | 8 +- src/ingester/mod.rs | 1 + src/ingester/parser/indexer_events.rs | 63 +- src/ingester/parser/mod.rs | 77 +- src/ingester/parser/state_update.rs | 5 + src/ingester/parser/tx_event_parser.rs | 62 +- src/ingester/parser/tx_event_parser_v2.rs | 8 +- src/ingester/persist/mod.rs | 147 +- .../persist/persisted_batch_event/address.rs | 2 +- .../persist/persisted_batch_event/append.rs | 4 +- .../persist/persisted_batch_event/mod.rs | 8 +- .../persist/persisted_batch_event/nullify.rs | 10 +- .../persist/persisted_indexed_merkle_tree.rs | 8 +- src/ingester/persist/persisted_state_tree.rs | 6 +- src/ingester/persist/spend.rs | 2 +- src/ingester/startup_cleanup.rs | 138 ++ src/ingester/typedefs/block_info.rs | 8 +- src/main.rs | 47 +- .../custom/custom20250211_000002_solayer2.rs | 4 +- .../custom/custom20252201_000001_init.rs | 4 +- .../standard/m20220101_000001_init.rs | 2 +- .../standard/m20240914_000005_init.rs | 2 +- .../standard/m20241008_000006_init.rs | 2 +- .../standard/m20250206_000007_init.rs | 2 +- ...1_000001_optimize_nullifier_queue_index.rs | 2 +- .../m20260127_000001_add_onchain_pubkey.rs | 57 + .../m20260201_000002_add_ata_owner.rs | 35 + .../m20260210_000002_add_ata_owner_index.rs | 56 + .../m20260220_000001_add_discriminator_v2.rs | 31 + src/migration/migrations/standard/mod.rs | 9 +- src/migration/model/table.rs | 3 + src/monitor/mod.rs | 39 +- src/monitor/queue_monitor.rs | 35 +- src/monitor/tree_metadata_sync.rs | 14 +- src/openapi/mod.rs | 5 +- src/openapi/specs/api.yaml | 721 ++++-- src/openapi/specs/getCompressedAccount.yaml | 165 -- .../specs/getCompressedAccountBalance.yaml | 117 - .../specs/getCompressedAccountProof.yaml | 130 -- .../specs/getCompressedAccountsByOwner.yaml | 787 ------- .../specs/getCompressedBalanceByOwner.yaml | 1143 ---------- .../specs/getCompressedMintTokenHolders.yaml | 140 -- .../getCompressedTokenAccountBalance.yaml | 931 -------- .../getCompressedTokenAccountsByDelegate.yaml | 671 ------ .../getCompressedTokenAccountsByOwner.yaml | 552 ----- .../getCompressedTokenBalancesByOwner.yaml | 1292 ----------- .../getCompressedTokenBalancesByOwnerV2.yaml | 144 -- .../getCompressionSignaturesForAccount.yaml | 1515 ------------ .../getCompressionSignaturesForAddress.yaml | 1637 ------------- .../getCompressionSignaturesForOwner.yaml | 1750 -------------- ...getCompressionSignaturesForTokenOwner.yaml | 1863 --------------- src/openapi/specs/getIndexerHealth.yaml | 69 - src/openapi/specs/getIndexerSlot.yaml | 67 - .../specs/getLatestCompressionSignatures.yaml | 139 -- .../specs/getLatestNonVotingSignatures.yaml | 139 -- .../getMultipleCompressedAccountProofs.yaml | 129 -- .../specs/getMultipleCompressedAccounts.yaml | 866 ------- .../specs/getMultipleNewAddressProofs.yaml | 139 -- .../specs/getMultipleNewAddressProofsV2.yaml | 150 -- src/openapi/specs/getQueueElements.yaml | 89 - .../getTransactionWithCompressionInfo.yaml | 1569 ------------- src/openapi/specs/getValidityProof.yaml | 169 -- src/openapi/specs/openapitools.json | 7 - src/snapshot/loader/main.rs | 2 +- src/snapshot/mod.rs | 5 +- src/snapshot/snapshotter/main.rs | 2 +- src/tools/tree_validator/main.rs | 1 - .../batched_state_tree_tests.rs | 29 +- tests/integration_tests/e2e_tests.rs | 3 +- tests/integration_tests/mock_tests.rs | 34 +- tests/integration_tests/prod_tests.rs | 4 +- tests/integration_tests/utils.rs | 28 +- 100 files changed, 3600 insertions(+), 17340 deletions(-) create mode 100644 src/common/token_layout.rs create mode 100644 src/ingester/startup_cleanup.rs create mode 100644 src/migration/migrations/standard/m20260127_000001_add_onchain_pubkey.rs create mode 100644 src/migration/migrations/standard/m20260201_000002_add_ata_owner.rs create mode 100644 src/migration/migrations/standard/m20260210_000002_add_ata_owner_index.rs create mode 100644 src/migration/migrations/standard/m20260220_000001_add_discriminator_v2.rs delete mode 100644 src/openapi/specs/getCompressedAccount.yaml delete mode 100644 src/openapi/specs/getCompressedAccountBalance.yaml delete mode 100644 src/openapi/specs/getCompressedAccountProof.yaml delete mode 100644 src/openapi/specs/getCompressedAccountsByOwner.yaml delete mode 100644 src/openapi/specs/getCompressedBalanceByOwner.yaml delete mode 100644 src/openapi/specs/getCompressedMintTokenHolders.yaml delete mode 100644 src/openapi/specs/getCompressedTokenAccountBalance.yaml delete mode 100644 src/openapi/specs/getCompressedTokenAccountsByDelegate.yaml delete mode 100644 src/openapi/specs/getCompressedTokenAccountsByOwner.yaml delete mode 100644 src/openapi/specs/getCompressedTokenBalancesByOwner.yaml delete mode 100644 src/openapi/specs/getCompressedTokenBalancesByOwnerV2.yaml delete mode 100644 src/openapi/specs/getCompressionSignaturesForAccount.yaml delete mode 100644 src/openapi/specs/getCompressionSignaturesForAddress.yaml delete mode 100644 src/openapi/specs/getCompressionSignaturesForOwner.yaml delete mode 100644 src/openapi/specs/getCompressionSignaturesForTokenOwner.yaml delete mode 100644 src/openapi/specs/getIndexerHealth.yaml delete mode 100644 src/openapi/specs/getIndexerSlot.yaml delete mode 100644 src/openapi/specs/getLatestCompressionSignatures.yaml delete mode 100644 src/openapi/specs/getLatestNonVotingSignatures.yaml delete mode 100644 src/openapi/specs/getMultipleCompressedAccountProofs.yaml delete mode 100644 src/openapi/specs/getMultipleCompressedAccounts.yaml delete mode 100644 src/openapi/specs/getMultipleNewAddressProofs.yaml delete mode 100644 src/openapi/specs/getMultipleNewAddressProofsV2.yaml delete mode 100644 src/openapi/specs/getQueueElements.yaml delete mode 100644 src/openapi/specs/getTransactionWithCompressionInfo.yaml delete mode 100644 src/openapi/specs/getValidityProof.yaml delete mode 100644 src/openapi/specs/openapitools.json diff --git a/Cargo.lock b/Cargo.lock index 2c8641f3..7b1d9aea 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -61,7 +61,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6b71300ed93a9dff1c3231c3f1417e242e3da38529ebc32f828bc8560bf4a2a" dependencies = [ "ahash 0.8.12", - "solana-epoch-schedule", + "solana-epoch-schedule 3.0.0", "solana-hash 3.1.0", "solana-pubkey 3.0.0", "solana-sha256-hasher 3.1.0", @@ -76,7 +76,7 @@ checksum = "ac34d0410a2a015df7d45d092449c7ec59264081d05f18c7f305ccf7c81bd3b7" dependencies = [ "agave-feature-set", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -273,7 +273,7 @@ dependencies = [ "ark-std 0.5.0", "educe", "fnv", - "hashbrown 0.15.5", + "hashbrown 0.15.2", "itertools 0.13.0", "num-bigint 0.4.6", "num-integer", @@ -392,7 +392,7 @@ dependencies = [ "ark-std 0.5.0", "educe", "fnv", - "hashbrown 0.15.5", + "hashbrown 0.15.2", ] [[package]] @@ -1444,6 +1444,26 @@ dependencies = [ "windows-sys 0.61.2", ] +[[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 = "const-oid" version = "0.9.6" @@ -1874,7 +1894,7 @@ dependencies = [ "ed25519", "rand_core 0.6.4", "serde", - "sha2", + "sha2 0.10.9", "subtle", "zeroize", ] @@ -2096,6 +2116,12 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + [[package]] name = "foreign-types" version = "0.3.2" @@ -2280,6 +2306,17 @@ dependencies = [ "winapi", ] +[[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" @@ -2289,7 +2326,7 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] @@ -2450,11 +2487,13 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.15.5" +version = "0.15.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ "allocator-api2", + "equivalent", + "foldhash", ] [[package]] @@ -3257,6 +3296,52 @@ dependencies = [ "redox_syscall 0.5.18", ] +[[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 = "libsqlite3-sys" version = "0.24.2" @@ -3270,18 +3355,27 @@ dependencies = [ [[package]] name = "light-account-checks" -version = "0.5.1" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e70bd1a384bff312860d4b60a0ccd814c36b88ce91966192dd88a35e595f7a2" +checksum = "34d74dd13535c6014abb4cac694e14083b206a7f6cf1bbbc9611aa5c2e11cdd1" dependencies = [ "thiserror 2.0.17", ] +[[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-batched-merkle-tree" -version = "0.6.1" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "421977e990b1edb39a0973ed0d0e919313517585e5dcb0e8faded1396c7cce12" +checksum = "bb07ef41d9d99db94072d556767a93d774323bc34940db349555abc4504de015" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -3299,9 +3393,9 @@ dependencies = [ [[package]] name = "light-bloom-filter" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8a609e3c9179f0ae8488cc70c5413c86dfd97dad7ad85fee2ad8da2d0a11e61" +checksum = "380b8cf734ccf5fbc1f5fed8e5308b57ebde6774d9304c167bcb0de2854412d8" dependencies = [ "bitvec", "num-bigint 0.4.6", @@ -3322,9 +3416,9 @@ dependencies = [ [[package]] name = "light-compressed-account" -version = "0.6.2" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a9cecda1680283ecba0f8ef64073d36998f057ac5aa96569dc8e74d6a37a3a2" +checksum = "adab5a8dddd9675306b0a808900578ed60b40b5c5457e330e28c9cb51361118d" dependencies = [ "borsh 0.10.4", "bytemuck", @@ -3337,6 +3431,28 @@ dependencies = [ "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 2.4.0", + "solana-rent 2.2.1", + "thiserror 2.0.17", + "zerocopy", +] + [[package]] name = "light-concurrent-merkle-tree" version = "4.0.1" @@ -3352,13 +3468,14 @@ dependencies = [ [[package]] name = "light-event" -version = "0.1.1" +version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "554228ce821d9c3b789f1c675f79663fe3872c77a3527e1e20e5f2f268eeb02d" +checksum = "ae607b61749246439e9e302a75dc565c98d6b9a81efcb1c6dd5e755a24b427ab" dependencies = [ "borsh 0.10.4", "light-compressed-account", "light-hasher", + "light-token-interface", "light-zero-copy", "thiserror 2.0.17", ] @@ -3372,9 +3489,9 @@ dependencies = [ "ark-bn254 0.5.0", "ark-ff 0.5.0", "borsh 0.10.4", - "light-poseidon", + "light-poseidon 0.3.0", "num-bigint 0.4.6", - "sha2", + "sha2 0.10.9", "sha3", "thiserror 2.0.17", "tinyvec", @@ -3422,9 +3539,9 @@ dependencies = [ [[package]] name = "light-merkle-tree-metadata" -version = "0.6.0" +version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6474045d3358e952f11a6cec44b9280ae127446a2b8246b3fdb29b83fda4e6b7" +checksum = "7623246ad0015345f6a88471f554381e24635b770fe4b15b38384daddf1d2f5f" dependencies = [ "borsh 0.10.4", "bytemuck", @@ -3458,6 +3575,18 @@ dependencies = [ "thiserror 1.0.69", ] +[[package]] +name = "light-poseidon" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47a1ccadd0bb5a32c196da536fd72c59183de24a055f6bf0513bf845fefab862" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ff 0.5.0", + "num-bigint 0.4.6", + "thiserror 1.0.69", +] + [[package]] name = "light-profiler-macro" version = "0.1.1" @@ -3478,11 +3607,55 @@ dependencies = [ "light-profiler-macro", ] +[[package]] +name = "light-sdk-types" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d60036a8f1af0d3aa651780aa57ae2cdca3fa0f16acecda71c98f81a53e37c9" +dependencies = [ + "borsh 0.10.4", + "bytemuck", + "light-account-checks", + "light-compressed-account", + "light-compressible", + "light-hasher", + "light-macros", + "solana-msg 2.2.1", + "thiserror 2.0.17", +] + +[[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 2.3.0", + "solana-pubkey 2.4.0", + "spl-pod 0.5.1", + "spl-token-2022", + "thiserror 2.0.17", + "tinyvec", + "zerocopy", +] + [[package]] name = "light-verifier" -version = "5.0.0" +version = "9.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da621c1996c02f10a263eb5a26f03ad34c074f3f07abf566318985f53f5a26d9" +checksum = "65a33dc6b302f2cfb7319006f1234f1d86c992ac1991ade7c97653828b7f1735" dependencies = [ "groth16-solana", "light-compressed-account", @@ -3491,9 +3664,9 @@ dependencies = [ [[package]] name = "light-zero-copy" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a8862f463792fd60ae8f5dc418150c16213e302e19d54fba0694cf8515be5ff" +checksum = "a5621fb515e14af46148699c0b65334aabe230a1d2cbd06736ccc7a408c8a4af" dependencies = [ "light-zero-copy-derive", "zerocopy", @@ -3501,9 +3674,9 @@ dependencies = [ [[package]] name = "light-zero-copy-derive" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8af086d52100b3cab1f2993b146adc7a69fa6aaa878ae4c19514c77c50304379" +checksum = "41c46425e5c7ab5203ff5c86ae2615b169cca55f9283f5f60f5dd74143be6934" dependencies = [ "lazy_static", "proc-macro2", @@ -3664,7 +3837,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" dependencies = [ "libc", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "windows-sys 0.61.2", ] @@ -4150,7 +4323,9 @@ dependencies = [ "light-indexed-merkle-tree", "light-merkle-tree-metadata", "light-merkle-tree-reference", - "light-poseidon", + "light-poseidon 0.4.0", + "light-sdk-types", + "light-token-interface", "light-zero-copy", "log", "num-bigint 0.4.6", @@ -4166,15 +4341,18 @@ dependencies = [ "serde", "serde_json", "serial_test", - "solana-account", + "solana-account 3.2.0", "solana-bn254 3.1.2", "solana-client", - "solana-clock", + "solana-clock 3.0.0", "solana-commitment-config", + "solana-program-option 3.0.0", + "solana-program-pack 3.0.0", "solana-pubkey 3.0.0", - "solana-signature", + "solana-signature 3.1.0", "solana-transaction", "solana-transaction-status", + "spl-token-interface", "sqlx", "thiserror 1.0.69", "tokio", @@ -4219,6 +4397,23 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +[[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 0.1.4", + "pinocchio", + "sha2-const-stable", +] + [[package]] name = "piper" version = "0.2.4" @@ -4495,7 +4690,7 @@ dependencies = [ "libc", "once_cell", "raw-cpuid", - "wasi", + "wasi 0.11.1+wasi-snapshot-preview1", "web-sys", "winapi", ] @@ -4588,6 +4783,19 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" +[[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" @@ -4609,6 +4817,16 @@ dependencies = [ "rand_core 0.9.3", ] +[[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" @@ -4629,6 +4847,15 @@ dependencies = [ "rand_core 0.9.3", ] +[[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" @@ -4647,6 +4874,15 @@ dependencies = [ "getrandom 0.3.4", ] +[[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 = "raw-cpuid" version = "11.6.0" @@ -4980,7 +5216,7 @@ dependencies = [ "serde", "serde_derive", "serde_json", - "sha2", + "sha2 0.10.9", "thiserror 1.0.69", "time", "tokio", @@ -5579,6 +5815,19 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug", +] + [[package]] name = "sha2" version = "0.10.9" @@ -5590,6 +5839,12 @@ dependencies = [ "digest 0.10.7", ] +[[package]] +name = "sha2-const-stable" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" + [[package]] name = "sha3" version = "0.10.8" @@ -5739,6 +5994,19 @@ dependencies = [ "sha-1", ] +[[package]] +name = "solana-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" +dependencies = [ + "solana-account-info 2.3.0", + "solana-clock 2.2.2", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", +] + [[package]] name = "solana-account" version = "3.2.0" @@ -5749,12 +6017,12 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-account-info", - "solana-clock", + "solana-account-info 3.1.0", + "solana-clock 3.0.0", "solana-instruction-error", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-sysvar", + "solana-sdk-ids 3.1.0", + "solana-sysvar 3.1.0", ] [[package]] @@ -5770,31 +6038,31 @@ dependencies = [ "bv", "serde", "serde_json", - "solana-account", + "solana-account 3.2.0", "solana-account-decoder-client-types", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.0.0", + "solana-clock 3.0.0", "solana-config-interface", - "solana-epoch-schedule", - "solana-fee-calculator", - "solana-instruction", - "solana-loader-v3-interface", - "solana-nonce", - "solana-program-option", - "solana-program-pack", + "solana-epoch-schedule 3.0.0", + "solana-fee-calculator 3.0.0", + "solana-instruction 3.1.0", + "solana-loader-v3-interface 6.1.0", + "solana-nonce 3.0.0", + "solana-program-option 3.0.0", + "solana-program-pack 3.0.0", "solana-pubkey 3.0.0", - "solana-rent", - "solana-sdk-ids", - "solana-slot-hashes", - "solana-slot-history", - "solana-stake-interface", - "solana-sysvar", - "solana-vote-interface", + "solana-rent 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.0", + "solana-slot-history 3.0.0", + "solana-stake-interface 2.0.1", + "solana-sysvar 3.1.0", + "solana-vote-interface 4.0.4", "spl-generic-token", "spl-token-2022-interface", - "spl-token-group-interface", + "spl-token-group-interface 0.7.1", "spl-token-interface", - "spl-token-metadata-interface", + "spl-token-metadata-interface 0.8.0", "thiserror 2.0.17", "zstd", ] @@ -5809,11 +6077,24 @@ dependencies = [ "bs58 0.5.1", "serde", "serde_json", - "solana-account", + "solana-account 3.2.0", "solana-pubkey 3.0.0", "zstd", ] +[[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 2.2.2", + "solana-program-memory 2.3.1", + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-account-info" version = "3.1.0" @@ -5821,8 +6102,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" dependencies = [ "solana-address 2.0.0", - "solana-program-error", - "solana-program-memory", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", ] [[package]] @@ -5850,11 +6131,28 @@ dependencies = [ "serde_derive", "solana-atomic-u64 3.0.0", "solana-define-syscall 4.0.1", - "solana-program-error", + "solana-program-error 3.0.0", "solana-sanitize 3.0.1", "solana-sha256-hasher 3.1.0", ] +[[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 2.2.2", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-slot-hashes 2.2.1", +] + [[package]] name = "solana-address-lookup-table-interface" version = "3.0.0" @@ -5865,12 +6163,12 @@ dependencies = [ "bytemuck", "serde", "serde_derive", - "solana-clock", - "solana-instruction", + "solana-clock 3.0.0", + "solana-instruction 3.1.0", "solana-instruction-error", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-slot-hashes", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.0", ] [[package]] @@ -5892,37 +6190,81 @@ dependencies = [ ] [[package]] -name = "solana-bn254" -version = "2.2.2" +name = "solana-big-mod-exp" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4420f125118732833f36facf96a27e7b78314b2d642ba07fa9ffdacd8d79e243" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" dependencies = [ - "ark-bn254 0.4.0", - "ark-ec 0.4.2", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "bytemuck", + "num-bigint 0.4.6", + "num-traits", "solana-define-syscall 2.3.0", - "thiserror 2.0.17", ] [[package]] -name = "solana-bn254" -version = "3.1.2" +name = "solana-bincode" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d08583be08d2d5f19aa21efbb6fbdb968ba7fd0de74562441437a7d776772bf" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" dependencies = [ - "ark-bn254 0.4.0", - "ark-ec 0.4.2", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", - "bytemuck", - "solana-define-syscall 3.0.0", - "thiserror 2.0.17", + "bincode", + "serde", + "solana-instruction 2.3.3", ] [[package]] -name = "solana-borsh" +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 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-bn254" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4420f125118732833f36facf96a27e7b78314b2d642ba07fa9ffdacd8d79e243" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "bytemuck", + "solana-define-syscall 2.3.0", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-bn254" +version = "3.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d08583be08d2d5f19aa21efbb6fbdb968ba7fd0de74562441437a7d776772bf" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "bytemuck", + "solana-define-syscall 3.0.0", + "thiserror 2.0.17", +] + +[[package]] +name = "solana-borsh" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", +] + +[[package]] +name = "solana-borsh" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc402b16657abbfa9991cd5cbfac5a11d809f7e7d28d3bb291baeb088b39060e" @@ -5946,16 +6288,16 @@ dependencies = [ "log", "quinn", "rayon", - "solana-account", + "solana-account 3.2.0", "solana-client-traits", "solana-commitment-config", "solana-connection-cache", "solana-epoch-info", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.1.0", "solana-keypair", "solana-measure", - "solana-message", + "solana-message 3.0.1", "solana-net-utils", "solana-pubkey 3.0.0", "solana-pubsub-client", @@ -5964,13 +6306,13 @@ dependencies = [ "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-signature", - "solana-signer", + "solana-signature 3.1.0", + "solana-signer 3.0.0", "solana-streamer", "solana-time-utils", "solana-tpu-client", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "solana-transaction-status-client-types", "solana-udp-client", "thiserror 2.0.17", @@ -5984,19 +6326,32 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08618ed587e128105510c54ae3e456b9a06d674d8640db75afe66dad65cb4e02" dependencies = [ - "solana-account", + "solana-account 3.2.0", "solana-commitment-config", "solana-epoch-info", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.1.0", "solana-keypair", - "solana-message", + "solana-message 3.0.1", "solana-pubkey 3.0.0", - "solana-signature", - "solana-signer", - "solana-system-interface", + "solana-signature 3.1.0", + "solana-signer 3.0.0", + "solana-system-interface 2.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.0.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 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -6007,9 +6362,9 @@ checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -6040,12 +6395,12 @@ dependencies = [ "bincode", "serde", "serde_derive", - "solana-account", - "solana-instruction", + "solana-account 3.2.0", + "solana-instruction 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-short-vec", - "solana-system-interface", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.1.0", + "solana-system-interface 2.0.0", ] [[package]] @@ -6066,23 +6421,51 @@ dependencies = [ "solana-measure", "solana-metrics", "solana-time-utils", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "thiserror 2.0.17", "tokio", ] +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info 2.3.0", + "solana-define-syscall 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-stable-layout 2.2.1", +] + [[package]] name = "solana-cpi" version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" dependencies = [ - "solana-account-info", + "solana-account-info 3.1.0", "solana-define-syscall 4.0.1", - "solana-instruction", - "solana-program-error", + "solana-instruction 3.1.0", + "solana-program-error 3.0.0", "solana-pubkey 4.0.0", - "solana-stable-layout", + "solana-stable-layout 3.0.0", +] + +[[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 2.3.0", + "subtle", + "thiserror 2.0.17", ] [[package]] @@ -6126,6 +6509,17 @@ version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" +[[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-derivation-path" version = "3.0.0" @@ -6147,6 +6541,20 @@ dependencies = [ "serde_derive", ] +[[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 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-epoch-rewards" version = "3.0.0" @@ -6156,9 +6564,22 @@ dependencies = [ "serde", "serde_derive", "solana-hash 3.1.0", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[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 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -6169,9 +6590,49 @@ checksum = "6e5481e72cc4d52c169db73e4c0cd16de8bc943078aac587ec4817a75cc6388f" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[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 2.2.2", + "solana-clock 2.2.2", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-keccak-hasher", + "solana-message 2.4.0", + "solana-nonce 2.2.1", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", + "thiserror 2.0.17", +] + +[[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 2.2.1", + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", ] [[package]] @@ -6182,9 +6643,20 @@ checksum = "7347ab62e6d47a82e340c865133795b394feea7c2b2771d293f57691c6544c3f" dependencies = [ "serde", "serde_derive", - "solana-program-error", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", +] + +[[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]] @@ -6204,8 +6676,13 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", "five8 0.2.1", "js-sys", + "serde", + "serde_derive", "solana-atomic-u64 2.2.1", "solana-sanitize 2.2.1", "wasm-bindgen", @@ -6242,6 +6719,25 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e92f37a14e7c660628752833250dd3dcd8e95309876aee751d7f8769a27947c6" +[[package]] +name = "solana-instruction" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab5682934bd1f65f8d2c16f21cb532526fcc1a09f796e2cacdb091eee5774ad" +dependencies = [ + "bincode", + "borsh 1.5.7", + "getrandom 0.2.16", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "serde_json", + "solana-define-syscall 2.3.0", + "solana-pubkey 2.4.0", + "wasm-bindgen", +] + [[package]] name = "solana-instruction" version = "3.1.0" @@ -6266,7 +6762,24 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-program-error", + "solana-program-error 3.0.0", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" +dependencies = [ + "bitflags 2.10.0", + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serialize-utils 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -6276,15 +6789,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" dependencies = [ "bitflags 2.10.0", - "solana-account-info", - "solana-instruction", + "solana-account-info 3.1.0", + "solana-instruction 3.1.0", "solana-instruction-error", - "solana-program-error", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "solana-sanitize 3.0.1", - "solana-sdk-ids", - "solana-serialize-utils", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-serialize-utils 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[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 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", ] [[package]] @@ -6297,9 +6822,22 @@ dependencies = [ "five8 1.0.0", "rand 0.8.5", "solana-address 2.0.0", - "solana-seed-phrase", - "solana-signature", - "solana-signer", + "solana-seed-phrase 3.0.0", + "solana-signature 3.1.0", + "solana-signer 3.0.0", +] + +[[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 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -6310,9 +6848,23 @@ checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[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 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", ] [[package]] @@ -6324,9 +6876,24 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-instruction", + "solana-instruction 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", +] + +[[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 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", ] [[package]] @@ -6338,10 +6905,25 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-instruction", + "solana-instruction 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-system-interface", + "solana-sdk-ids 3.1.0", + "solana-system-interface 2.0.0", +] + +[[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 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", ] [[package]] @@ -6350,6 +6932,29 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f96102f7c7c9f21cba06453b2274a55f279f5c4a0201ddef63df940db9c7bf61" +[[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 2.3.0", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction-error 2.2.1", + "wasm-bindgen", +] + [[package]] name = "solana-message" version = "3.0.1" @@ -6363,11 +6968,11 @@ dependencies = [ "serde_derive", "solana-address 1.1.0", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.1.0", "solana-sanitize 3.0.1", - "solana-sdk-ids", - "solana-short-vec", - "solana-transaction-error", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.1.0", + "solana-transaction-error 3.0.0", ] [[package]] @@ -6386,6 +6991,15 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall 2.3.0", +] + [[package]] name = "solana-msg" version = "3.0.0" @@ -6395,6 +7009,12 @@ dependencies = [ "solana-define-syscall 3.0.0", ] +[[package]] +name = "solana-native-token" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61515b880c36974053dd499c0510066783f0cc6ac17def0c7ef2a244874cf4a9" + [[package]] name = "solana-net-utils" version = "3.1.1" @@ -6418,6 +7038,20 @@ dependencies = [ "url", ] +[[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 2.2.1", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", + "solana-sha256-hasher 2.3.0", +] + [[package]] name = "solana-nonce" version = "3.0.0" @@ -6426,7 +7060,7 @@ checksum = "abbdc6c8caf1c08db9f36a50967539d0f72b9f1d4aea04fec5430f532e5afadc" dependencies = [ "serde", "serde_derive", - "solana-fee-calculator", + "solana-fee-calculator 3.0.0", "solana-hash 3.1.0", "solana-pubkey 3.0.0", "solana-sha256-hasher 3.1.0", @@ -6476,30 +7110,138 @@ dependencies = [ "rayon", "serde", "solana-hash 3.1.0", - "solana-message", + "solana-message 3.0.1", "solana-metrics", "solana-packet", "solana-pubkey 3.0.0", "solana-rayon-threadlimit", - "solana-sdk-ids", - "solana-short-vec", - "solana-signature", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.1.0", + "solana-signature 3.1.0", "solana-time-utils", "solana-transaction-context", ] +[[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.5.7", + "bs58 0.5.1", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.16", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 2.3.0", + "solana-address-lookup-table-interface 2.2.2", + "solana-atomic-u64 2.2.1", + "solana-big-mod-exp", + "solana-bincode", + "solana-blake3-hasher", + "solana-borsh 2.2.1", + "solana-clock 2.2.2", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-example-mocks", + "solana-feature-gate-interface 2.2.2", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-keccak-hasher", + "solana-last-restart-slot 2.2.1", + "solana-loader-v2-interface 2.2.1", + "solana-loader-v3-interface 5.0.0", + "solana-loader-v4-interface", + "solana-message 2.4.0", + "solana-msg 2.2.1", + "solana-native-token", + "solana-nonce 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-program-option 2.2.1", + "solana-program-pack 2.2.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-secp256k1-recover", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-sha256-hasher 2.3.0", + "solana-short-vec 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stable-layout 2.2.1", + "solana-stake-interface 1.2.1", + "solana-system-interface 1.0.0", + "solana-sysvar 2.3.0", + "solana-sysvar-id 2.2.1", + "solana-vote-interface 2.2.6", + "thiserror 2.0.17", + "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 2.3.0", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-program-entrypoint" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" dependencies = [ - "solana-account-info", + "solana-account-info 3.1.0", "solana-define-syscall 4.0.1", - "solana-program-error", + "solana-program-error 3.0.0", "solana-pubkey 4.0.0", ] +[[package]] +name = "solana-program-error" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" +dependencies = [ + "borsh 1.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-program-error" version = "3.0.0" @@ -6509,6 +7251,15 @@ dependencies = [ "borsh 1.5.7", ] +[[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 2.3.0", +] + [[package]] name = "solana-program-memory" version = "3.1.0" @@ -6518,19 +7269,34 @@ dependencies = [ "solana-define-syscall 4.0.1", ] +[[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-option" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8e7b4ddb464f274deb4a497712664c3b612e3f5f82471d4e47710fc4ab1c3095" +[[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 2.2.2", +] + [[package]] name = "solana-program-pack" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c169359de21f6034a63ebf96d6b380980307df17a8d371344ff04a883ec4e9d0" dependencies = [ - "solana-program-error", + "solana-program-error 3.0.0", ] [[package]] @@ -6539,12 +7305,18 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" dependencies = [ + "borsh 0.10.4", + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", "curve25519-dalek", "five8 0.2.1", "five8_const 0.1.4", "getrandom 0.2.16", "js-sys", "num-traits", + "serde", + "serde_derive", "solana-atomic-u64 2.2.1", "solana-decode-error", "solana-define-syscall 2.3.0", @@ -6585,10 +7357,10 @@ dependencies = [ "serde", "serde_json", "solana-account-decoder-client-types", - "solana-clock", + "solana-clock 3.0.0", "solana-pubkey 3.0.0", "solana-rpc-client-types", - "solana-signature", + "solana-signature 3.1.0", "thiserror 2.0.17", "tokio", "tokio-stream", @@ -6619,10 +7391,10 @@ dependencies = [ "solana-pubkey 3.0.0", "solana-quic-definitions", "solana-rpc-client-api", - "solana-signer", + "solana-signer 3.0.0", "solana-streamer", "solana-tls-utils", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "thiserror 2.0.17", "tokio", ] @@ -6646,6 +7418,19 @@ dependencies = [ "num_cpus", ] +[[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 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-rent" version = "3.0.0" @@ -6654,9 +7439,9 @@ checksum = "b702d8c43711e3c8a9284a4f1bbc6a3de2553deb25b0c8142f9a44ef0ce5ddc1" dependencies = [ "serde", "serde_derive", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -6687,25 +7472,25 @@ dependencies = [ "semver", "serde", "serde_json", - "solana-account", + "solana-account 3.2.0", "solana-account-decoder", "solana-account-decoder-client-types", - "solana-clock", + "solana-clock 3.0.0", "solana-commitment-config", "solana-epoch-info", - "solana-epoch-schedule", - "solana-feature-gate-interface", + "solana-epoch-schedule 3.0.0", + "solana-feature-gate-interface 3.0.0", "solana-hash 3.1.0", - "solana-instruction", - "solana-message", + "solana-instruction 3.1.0", + "solana-message 3.0.1", "solana-pubkey 3.0.0", "solana-rpc-client-api", - "solana-signature", + "solana-signature 3.1.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "solana-transaction-status-client-types", "solana-version", - "solana-vote-interface", + "solana-vote-interface 4.0.4", "tokio", ] @@ -6722,10 +7507,10 @@ dependencies = [ "serde", "serde_json", "solana-account-decoder-client-types", - "solana-clock", + "solana-clock 3.0.0", "solana-rpc-client-types", - "solana-signer", - "solana-transaction-error", + "solana-signer 3.0.0", + "solana-transaction-error 3.0.0", "solana-transaction-status-client-types", "thiserror 2.0.17", ] @@ -6736,14 +7521,14 @@ version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ede5005bd6f29d131fdaeae736348b5c6dc238a4be42550ade03d27d32ebf676" dependencies = [ - "solana-account", + "solana-account 3.2.0", "solana-commitment-config", "solana-hash 3.1.0", - "solana-message", - "solana-nonce", + "solana-message 3.0.1", + "solana-nonce 3.0.0", "solana-pubkey 3.0.0", "solana-rpc-client", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "thiserror 2.0.17", ] @@ -6758,16 +7543,16 @@ dependencies = [ "semver", "serde", "serde_json", - "solana-account", + "solana-account 3.2.0", "solana-account-decoder-client-types", "solana-address 1.1.0", - "solana-clock", + "solana-clock 3.0.0", "solana-commitment-config", - "solana-fee-calculator", + "solana-fee-calculator 3.0.0", "solana-inflation", "solana-reward-info", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "solana-transaction-status-client-types", "solana-version", "spl-generic-token", @@ -6800,6 +7585,15 @@ dependencies = [ "thiserror 2.0.17", ] +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey 2.4.0", +] + [[package]] name = "solana-sdk-ids" version = "3.1.0" @@ -6809,6 +7603,18 @@ dependencies = [ "solana-address 2.0.0", ] +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58 0.5.1", + "proc-macro2", + "quote", + "syn 2.0.110", +] + [[package]] name = "solana-sdk-macro" version = "3.0.0" @@ -6821,13 +7627,53 @@ dependencies = [ "syn 2.0.110", ] +[[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 2.3.0", + "thiserror 2.0.17", +] + +[[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 2.2.1", +] + [[package]] name = "solana-seed-derivable" version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ff7bdb72758e3bec33ed0e2658a920f1f35dfb9ed576b951d20d63cb61ecd95c" dependencies = [ - "solana-derivation-path", + "solana-derivation-path 3.0.0", +] + +[[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]] @@ -6838,7 +7684,7 @@ checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" dependencies = [ "hmac", "pbkdf2", - "sha2", + "sha2 0.10.9", ] [[package]] @@ -6850,6 +7696,15 @@ dependencies = [ "serde", ] +[[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-serde-varint" version = "3.0.0" @@ -6859,6 +7714,17 @@ 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 2.3.3", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", +] + [[package]] name = "solana-serialize-utils" version = "3.1.0" @@ -6876,7 +7742,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5aa3feb32c28765f6aa1ce8f3feac30936f16c5c3f7eb73d63a5b8f6f8ecdc44" dependencies = [ - "sha2", + "sha2 0.10.9", "solana-define-syscall 2.3.0", "solana-hash 2.3.0", ] @@ -6887,11 +7753,20 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" dependencies = [ - "sha2", + "sha2 0.10.9", "solana-define-syscall 4.0.1", "solana-hash 4.0.1", ] +[[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-short-vec" version = "3.1.0" @@ -6901,6 +7776,16 @@ dependencies = [ "serde_core", ] +[[package]] +name = "solana-signature" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c8ec8e657aecfc187522fc67495142c12f35e55ddeca8698edbb738b8dbd8c" +dependencies = [ + "five8 0.2.1", + "solana-sanitize 2.2.1", +] + [[package]] name = "solana-signature" version = "3.1.0" @@ -6915,6 +7800,17 @@ dependencies = [ "solana-sanitize 3.0.1", ] +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-signature 2.3.0", + "solana-transaction-error 2.2.1", +] + [[package]] name = "solana-signer" version = "3.0.0" @@ -6922,8 +7818,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" dependencies = [ "solana-pubkey 3.0.0", - "solana-signature", - "solana-transaction-error", + "solana-signature 3.1.0", + "solana-transaction-error 3.0.0", +] + +[[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 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -6935,8 +7844,21 @@ dependencies = [ "serde", "serde_derive", "solana-hash 3.1.0", - "solana-sdk-ids", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[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 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] @@ -6948,8 +7870,18 @@ dependencies = [ "bv", "serde", "serde_derive", - "solana-sdk-ids", - "solana-sysvar-id", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", ] [[package]] @@ -6958,10 +7890,31 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" dependencies = [ - "solana-instruction", + "solana-instruction 3.1.0", "solana-pubkey 3.0.0", ] +[[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.5.7", + "num-traits", + "serde", + "serde_derive", + "solana-clock 2.2.2", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-system-interface 1.0.0", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-stake-interface" version = "2.0.1" @@ -6971,14 +7924,14 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-clock", - "solana-cpi", - "solana-instruction", - "solana-program-error", + "solana-clock 3.0.0", + "solana-cpi 3.1.0", + "solana-instruction 3.1.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", - "solana-system-interface", - "solana-sysvar", - "solana-sysvar-id", + "solana-system-interface 2.0.0", + "solana-sysvar 3.1.0", + "solana-sysvar-id 3.1.0", ] [[package]] @@ -7017,11 +7970,11 @@ dependencies = [ "solana-perf", "solana-pubkey 3.0.0", "solana-quic-definitions", - "solana-signature", - "solana-signer", + "solana-signature 3.1.0", + "solana-signer 3.0.0", "solana-time-utils", "solana-tls-utils", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "solana-transaction-metrics-tracker", "thiserror 2.0.17", "tokio", @@ -7039,9 +7992,25 @@ checksum = "d848a90245dbaffeb8c43492eb902c2b988200a1b59b3959435d17abcea3eb3d" name = "solana-svm-type-overrides" version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cddcdb9981c7838ceb16bb97929c5cab015b0bdcb12243720000f8e44c9a5af2" +checksum = "cddcdb9981c7838ceb16bb97929c5cab015b0bdcb12243720000f8e44c9a5af2" +dependencies = [ + "rand 0.8.5", +] + +[[package]] +name = "solana-system-interface" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" dependencies = [ - "rand 0.8.5", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "wasm-bindgen", ] [[package]] @@ -7053,12 +8022,49 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-instruction", - "solana-msg", - "solana-program-error", + "solana-instruction 3.1.0", + "solana-msg 3.0.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", ] +[[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 2.3.0", + "solana-clock 2.2.2", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-last-restart-slot 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stake-interface 1.2.1", + "solana-sysvar-id 2.2.1", +] + [[package]] name = "solana-sysvar" version = "3.1.0" @@ -7070,25 +8076,35 @@ dependencies = [ "lazy_static", "serde", "serde_derive", - "solana-account-info", - "solana-clock", + "solana-account-info 3.1.0", + "solana-clock 3.0.0", "solana-define-syscall 4.0.1", - "solana-epoch-rewards", - "solana-epoch-schedule", - "solana-fee-calculator", + "solana-epoch-rewards 3.0.0", + "solana-epoch-schedule 3.0.0", + "solana-fee-calculator 3.0.0", "solana-hash 4.0.1", - "solana-instruction", - "solana-last-restart-slot", - "solana-program-entrypoint", - "solana-program-error", - "solana-program-memory", + "solana-instruction 3.1.0", + "solana-last-restart-slot 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", "solana-pubkey 4.0.0", - "solana-rent", - "solana-sdk-ids", - "solana-sdk-macro", - "solana-slot-hashes", - "solana-slot-history", - "solana-sysvar-id", + "solana-rent 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.0", + "solana-slot-hashes 3.0.0", + "solana-slot-history 3.0.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-sysvar-id" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", ] [[package]] @@ -7098,7 +8114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" dependencies = [ "solana-address 2.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", ] [[package]] @@ -7116,7 +8132,7 @@ dependencies = [ "rustls 0.23.35", "solana-keypair", "solana-pubkey 3.0.0", - "solana-signer", + "solana-signer 3.0.0", "x509-parser", ] @@ -7134,22 +8150,22 @@ dependencies = [ "log", "rayon", "solana-client-traits", - "solana-clock", + "solana-clock 3.0.0", "solana-commitment-config", "solana-connection-cache", - "solana-epoch-schedule", + "solana-epoch-schedule 3.0.0", "solana-measure", - "solana-message", + "solana-message 3.0.1", "solana-net-utils", "solana-pubkey 3.0.0", "solana-pubsub-client", "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", - "solana-signature", - "solana-signer", + "solana-signature 3.1.0", + "solana-signer 3.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "thiserror 2.0.17", "tokio", ] @@ -7165,15 +8181,15 @@ dependencies = [ "serde_derive", "solana-address 2.0.0", "solana-hash 4.0.1", - "solana-instruction", + "solana-instruction 3.1.0", "solana-instruction-error", - "solana-message", + "solana-message 3.0.1", "solana-sanitize 3.0.1", - "solana-sdk-ids", - "solana-short-vec", - "solana-signature", - "solana-signer", - "solana-transaction-error", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.1.0", + "solana-signature 3.1.0", + "solana-signer 3.0.0", + "solana-transaction-error 3.0.0", ] [[package]] @@ -7184,13 +8200,23 @@ checksum = "1bd55fe81fbc36ee00fde8233764b1f60c141e93a069932f126b707a515b8199" dependencies = [ "bincode", "serde", - "solana-account", - "solana-instruction", - "solana-instructions-sysvar", + "solana-account 3.2.0", + "solana-instruction 3.1.0", + "solana-instructions-sysvar 3.0.0", "solana-pubkey 3.0.0", - "solana-rent", + "solana-rent 3.0.0", "solana-sbpf", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-transaction-error" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" +dependencies = [ + "solana-instruction 2.3.3", + "solana-sanitize 2.2.1", ] [[package]] @@ -7217,8 +8243,8 @@ dependencies = [ "rand 0.8.5", "solana-packet", "solana-perf", - "solana-short-vec", - "solana-signature", + "solana-short-vec 3.1.0", + "solana-signature 3.1.0", ] [[package]] @@ -7237,30 +8263,30 @@ dependencies = [ "serde", "serde_json", "solana-account-decoder", - "solana-address-lookup-table-interface", - "solana-clock", + "solana-address-lookup-table-interface 3.0.0", + "solana-clock 3.0.0", "solana-hash 3.1.0", - "solana-instruction", - "solana-loader-v2-interface", - "solana-loader-v3-interface", - "solana-message", - "solana-program-option", + "solana-instruction 3.1.0", + "solana-loader-v2-interface 3.0.0", + "solana-loader-v3-interface 6.1.0", + "solana-message 3.0.1", + "solana-program-option 3.0.0", "solana-pubkey 3.0.0", "solana-reward-info", - "solana-sdk-ids", - "solana-signature", - "solana-stake-interface", - "solana-system-interface", + "solana-sdk-ids 3.1.0", + "solana-signature 3.1.0", + "solana-stake-interface 2.0.1", + "solana-system-interface 2.0.0", "solana-transaction", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "solana-transaction-status-client-types", - "solana-vote-interface", + "solana-vote-interface 4.0.4", "spl-associated-token-account-interface", "spl-memo-interface", "spl-token-2022-interface", - "spl-token-group-interface", + "spl-token-group-interface 0.7.1", "spl-token-interface", - "spl-token-metadata-interface", + "spl-token-metadata-interface 0.8.0", "thiserror 2.0.17", ] @@ -7277,14 +8303,14 @@ dependencies = [ "serde_json", "solana-account-decoder-client-types", "solana-commitment-config", - "solana-instruction", - "solana-message", + "solana-instruction 3.1.0", + "solana-message 3.0.1", "solana-pubkey 3.0.0", "solana-reward-info", - "solana-signature", + "solana-signature 3.1.0", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "thiserror 2.0.17", ] @@ -7299,7 +8325,7 @@ dependencies = [ "solana-keypair", "solana-net-utils", "solana-streamer", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "thiserror 2.0.17", "tokio", ] @@ -7315,7 +8341,31 @@ dependencies = [ "semver", "serde", "solana-sanitize 3.0.1", - "solana-serde-varint", + "solana-serde-varint 3.0.0", +] + +[[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 2.2.2", + "solana-decode-error", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", ] [[package]] @@ -7331,17 +8381,53 @@ dependencies = [ "serde", "serde_derive", "serde_with", - "solana-clock", + "solana-clock 3.0.0", "solana-hash 3.1.0", - "solana-instruction", + "solana-instruction 3.1.0", "solana-instruction-error", "solana-pubkey 3.0.0", - "solana-rent", - "solana-sdk-ids", - "solana-serde-varint", - "solana-serialize-utils", - "solana-short-vec", - "solana-system-interface", + "solana-rent 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-serde-varint 3.0.0", + "solana-serialize-utils 3.1.0", + "solana-short-vec 3.1.0", + "solana-system-interface 2.0.0", +] + +[[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 2.2.1", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-seed-derivable 2.2.1", + "solana-seed-phrase 2.2.1", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "subtle", + "thiserror 2.0.17", + "wasm-bindgen", + "zeroize", ] [[package]] @@ -7367,14 +8453,14 @@ dependencies = [ "serde_derive", "serde_json", "sha3", - "solana-derivation-path", - "solana-instruction", + "solana-derivation-path 3.0.0", + "solana-instruction 3.1.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-seed-derivable", - "solana-seed-phrase", - "solana-signature", - "solana-signer", + "solana-sdk-ids 3.1.0", + "solana-seed-derivable 3.0.0", + "solana-seed-phrase 3.0.0", + "solana-signature 3.1.0", + "solana-signer 3.0.0", "subtle", "thiserror 2.0.17", "wasm-bindgen", @@ -7422,10 +8508,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6433917b60441d68d99a17e121d9db0ea15a9a69c0e5afa34649cf5ba12612f" dependencies = [ "borsh 1.5.7", - "solana-instruction", + "solana-instruction 3.1.0", "solana-pubkey 3.0.0", ] +[[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 2.2.2", + "solana-sha256-hasher 2.3.0", + "spl-discriminator-derive", +] + [[package]] name = "spl-discriminator" version = "0.5.1" @@ -7433,7 +8531,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d48cc11459e265d5b501534144266620289720b4c44522a47bc6b63cd295d2f3" dependencies = [ "bytemuck", - "solana-program-error", + "solana-program-error 3.0.0", "solana-sha256-hasher 3.1.0", "spl-discriminator-derive", ] @@ -7457,11 +8555,24 @@ checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" dependencies = [ "proc-macro2", "quote", - "sha2", + "sha2 0.10.9", "syn 2.0.110", "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 2.3.13", + "spl-pod 0.5.1", + "spl-token-confidential-transfer-proof-extraction 0.2.1", +] + [[package]] name = "spl-generic-token" version = "2.0.1" @@ -7472,16 +8583,50 @@ dependencies = [ "solana-pubkey 3.0.0", ] +[[package]] +name = "spl-memo" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" +dependencies = [ + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", +] + [[package]] name = "spl-memo-interface" version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d4e2aedd58f858337fa609af5ad7100d4a243fdaf6a40d6eb4c28c5f19505d3" dependencies = [ - "solana-instruction", + "solana-instruction 3.1.0", "solana-pubkey 3.0.0", ] +[[package]] +name = "spl-pod" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" +dependencies = [ + "borsh 1.5.7", + "bytemuck", + "bytemuck_derive", + "num-derive", + "num-traits", + "solana-decode-error", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-program-option 2.2.1", + "solana-pubkey 2.4.0", + "solana-zk-sdk 2.3.13", + "thiserror 2.0.17", +] + [[package]] name = "spl-pod" version = "0.7.1" @@ -7494,10 +8639,100 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-program-error", - "solana-program-option", + "solana-program-error 3.0.0", + "solana-program-option 3.0.0", "solana-pubkey 3.0.0", - "solana-zk-sdk", + "solana-zk-sdk 4.0.0", + "thiserror 2.0.17", +] + +[[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.110", +] + +[[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 2.3.0", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "spl-discriminator 0.4.1", + "spl-pod 0.5.1", + "spl-program-error", + "spl-type-length-value 0.7.0", + "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 2.3.13", + "spl-elgamal-registry", + "spl-memo", + "spl-pod 0.5.1", + "spl-token", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction 0.2.1", + "spl-token-confidential-transfer-proof-generation 0.3.0", + "spl-token-group-interface 0.5.0", + "spl-token-metadata-interface 0.6.0", + "spl-transfer-hook-interface", + "spl-type-length-value 0.7.0", "thiserror 2.0.17", ] @@ -7512,20 +8747,46 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-account-info", - "solana-instruction", - "solana-program-error", - "solana-program-option", - "solana-program-pack", + "solana-account-info 3.1.0", + "solana-instruction 3.1.0", + "solana-program-error 3.0.0", + "solana-program-option 3.0.0", + "solana-program-pack 3.0.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-zk-sdk", - "spl-pod", - "spl-token-confidential-transfer-proof-extraction", - "spl-token-confidential-transfer-proof-generation", - "spl-token-group-interface", - "spl-token-metadata-interface", - "spl-type-length-value", + "solana-sdk-ids 3.1.0", + "solana-zk-sdk 4.0.0", + "spl-pod 0.7.1", + "spl-token-confidential-transfer-proof-extraction 0.5.1", + "spl-token-confidential-transfer-proof-generation 0.5.1", + "spl-token-group-interface 0.7.1", + "spl-token-metadata-interface 0.8.0", + "spl-type-length-value 0.9.0", + "thiserror 2.0.17", +] + +[[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 2.3.13", + "solana-zk-sdk 2.3.13", +] + +[[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 2.3.13", + "solana-program", + "solana-zk-sdk 2.3.13", + "spl-pod 0.5.1", "thiserror 2.0.17", ] @@ -7536,16 +8797,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "879a9ebad0d77383d3ea71e7de50503554961ff0f4ef6cbca39ad126e6f6da3a" dependencies = [ "bytemuck", - "solana-account-info", - "solana-curve25519", - "solana-instruction", - "solana-instructions-sysvar", - "solana-msg", - "solana-program-error", + "solana-account-info 3.1.0", + "solana-curve25519 3.1.1", + "solana-instruction 3.1.0", + "solana-instructions-sysvar 3.0.0", + "solana-msg 3.0.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", - "solana-zk-sdk", - "spl-pod", + "solana-sdk-ids 3.1.0", + "solana-zk-sdk 4.0.0", + "spl-pod 0.7.1", + "thiserror 2.0.17", +] + +[[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 2.3.13", "thiserror 2.0.17", ] @@ -7556,10 +8828,29 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a0cd59fce3dc00f563c6fa364d67c3f200d278eae681f4dc250240afcfe044b1" dependencies = [ "curve25519-dalek", - "solana-zk-sdk", + "solana-zk-sdk 4.0.0", "thiserror 2.0.17", ] +[[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 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "spl-discriminator 0.4.1", + "spl-pod 0.5.1", + "thiserror 1.0.69", +] + [[package]] name = "spl-token-group-interface" version = "0.7.1" @@ -7570,11 +8861,11 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-instruction", - "solana-program-error", + "solana-instruction 3.1.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", - "spl-discriminator", - "spl-pod", + "spl-discriminator 0.5.1", + "spl-pod 0.7.1", "thiserror 2.0.17", ] @@ -7589,15 +8880,36 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-instruction", - "solana-program-error", - "solana-program-option", - "solana-program-pack", + "solana-instruction 3.1.0", + "solana-program-error 3.0.0", + "solana-program-option 3.0.0", + "solana-program-pack 3.0.0", "solana-pubkey 3.0.0", - "solana-sdk-ids", + "solana-sdk-ids 3.1.0", "thiserror 2.0.17", ] +[[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.5.7", + "num-derive", + "num-traits", + "solana-borsh 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "spl-discriminator 0.4.1", + "spl-pod 0.5.1", + "spl-type-length-value 0.7.0", + "thiserror 1.0.69", +] + [[package]] name = "spl-token-metadata-interface" version = "0.8.0" @@ -7607,16 +8919,59 @@ dependencies = [ "borsh 1.5.7", "num-derive", "num-traits", - "solana-borsh", - "solana-instruction", - "solana-program-error", + "solana-borsh 3.0.0", + "solana-instruction 3.1.0", + "solana-program-error 3.0.0", "solana-pubkey 3.0.0", - "spl-discriminator", - "spl-pod", - "spl-type-length-value", + "spl-discriminator 0.5.1", + "spl-pod 0.7.1", + "spl-type-length-value 0.9.0", "thiserror 2.0.17", ] +[[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 2.3.0", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "spl-discriminator 0.4.1", + "spl-pod 0.5.1", + "spl-program-error", + "spl-tlv-account-resolution", + "spl-type-length-value 0.7.0", + "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 2.3.0", + "solana-decode-error", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "spl-discriminator 0.4.1", + "spl-pod 0.5.1", + "thiserror 1.0.69", +] + [[package]] name = "spl-type-length-value" version = "0.9.0" @@ -7627,11 +8982,11 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-account-info", - "solana-msg", - "solana-program-error", - "spl-discriminator", - "spl-pod", + "solana-account-info 3.1.0", + "solana-msg 3.0.0", + "solana-program-error 3.0.0", + "spl-discriminator 0.5.1", + "spl-pod 0.7.1", "thiserror 2.0.17", ] @@ -7702,7 +9057,7 @@ dependencies = [ "serde", "serde_json", "sha1", - "sha2", + "sha2 0.10.9", "smallvec", "sqlformat", "sqlx-rt", @@ -7731,7 +9086,7 @@ dependencies = [ "quote", "serde", "serde_json", - "sha2", + "sha2 0.10.9", "sqlx-core", "sqlx-rt", "syn 1.0.109", @@ -8716,6 +10071,12 @@ dependencies = [ "try-lock", ] +[[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" @@ -9375,16 +10736,16 @@ dependencies = [ "prost", "prost-types", "protobuf-src", - "solana-account", + "solana-account 3.2.0", "solana-account-decoder", - "solana-clock", + "solana-clock 3.0.0", "solana-hash 3.1.0", - "solana-message", + "solana-message 3.0.1", "solana-pubkey 3.0.0", - "solana-signature", + "solana-signature 3.1.0", "solana-transaction", "solana-transaction-context", - "solana-transaction-error", + "solana-transaction-error 3.0.0", "solana-transaction-status", "tonic", "tonic-build", diff --git a/Cargo.toml b/Cargo.toml index 9b082a8f..22e8fa03 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -84,16 +84,25 @@ solana-bn254 = "3.1.2" solana-commitment-config = "3.0.0" solana-transaction-status = "3.0.8" +solana-program-option = "3.0.0" +solana-program-pack = "3.0.0" +spl-token-interface = "2.0.0" -light-zero-copy = { version = "0.5",default-features = false} + + +light-zero-copy = { version = "0.6", default-features = false} light-concurrent-merkle-tree = {version = "4", default-features = false } -light-batched-merkle-tree = { version = "0.6", default-features = false} -light-merkle-tree-metadata = { version = "0.6", default-features = false } -light-compressed-account = { version = "0.6", default-features = false } +light-batched-merkle-tree = { version = "0.10", default-features = false} +light-merkle-tree-metadata = { version = "0.10", default-features = false } +light-compressed-account = { version = "0.10.1", default-features = false } light-hasher = { version = "5", features = ["poseidon", "keccak", "sha256"], default-features = false} -light-poseidon = "0.3.0" +light-poseidon = "0.4.0" light-indexed-merkle-tree = { version = "4", default-features = false } -light-event = "0.1" +light-event = "0.21" + +light-token-interface = "0.4" +light-sdk-types = "0.20" + sqlx = { version = "0.6.2", features = [ "macros", diff --git a/src/api/api.rs b/src/api/api.rs index ab6c03a9..e323c2cd 100644 --- a/src/api/api.rs +++ b/src/api/api.rs @@ -101,6 +101,7 @@ pub struct PhotonApi { db_conn: Arc, rpc_client: Arc, prover_url: String, + prover_api_key: Option, } impl PhotonApi { @@ -108,11 +109,13 @@ impl PhotonApi { db_conn: Arc, rpc_client: Arc, prover_url: String, + prover_api_key: Option, ) -> Self { Self { db_conn, rpc_client, prover_url, + prover_api_key, } } } @@ -363,14 +366,26 @@ impl PhotonApi { &self, request: GetValidityProofRequest, ) -> Result { - get_validity_proof(self.db_conn.as_ref(), &self.prover_url, request).await + get_validity_proof( + self.db_conn.as_ref(), + &self.prover_url, + self.prover_api_key.as_deref(), + request, + ) + .await } pub async fn get_validity_proof_v2( &self, request: GetValidityProofRequestV2, ) -> Result { - get_validity_proof_v2(self.db_conn.as_ref(), &self.prover_url, request).await + get_validity_proof_v2( + self.db_conn.as_ref(), + &self.prover_url, + self.prover_api_key.as_deref(), + request, + ) + .await } pub async fn get_latest_compression_signatures( diff --git a/src/api/method/get_compressed_accounts_by_owner/v1.rs b/src/api/method/get_compressed_accounts_by_owner/v1.rs index 19decc47..367e09d5 100644 --- a/src/api/method/get_compressed_accounts_by_owner/v1.rs +++ b/src/api/method/get_compressed_accounts_by_owner/v1.rs @@ -39,7 +39,7 @@ pub async fn get_compressed_accounts_by_owner( query_builder.build_base_query(conn, &request)?; let columns = format!( - "hash, {}, data_hash, address, owner, tree, leaf_index, seq, slot_created, spent, prev_spent, lamports, discriminator, queue, in_output_queue, nullifier_queue_index, nullified_in_tree, nullifier, tx_hash, tree_type", + "hash, {}, data_hash, address, onchain_pubkey, owner, tree, leaf_index, seq, slot_created, spent, prev_spent, lamports, discriminator, discriminator_v2, queue, in_output_queue, nullifier_queue_index, nullified_in_tree, nullifier, tx_hash, tree_type", query_builder.data_column ); diff --git a/src/api/method/get_compressed_accounts_by_owner/v2.rs b/src/api/method/get_compressed_accounts_by_owner/v2.rs index c7f86684..b241380b 100644 --- a/src/api/method/get_compressed_accounts_by_owner/v2.rs +++ b/src/api/method/get_compressed_accounts_by_owner/v2.rs @@ -41,7 +41,7 @@ pub async fn get_compressed_accounts_by_owner_v2( query_builder.build_base_query(conn, &request)?; let columns = format!( - "hash, {}, data_hash, address, owner, tree, queue, in_output_queue, nullifier_queue_index, tx_hash, nullifier, leaf_index, seq, slot_created, spent, prev_spent, lamports, discriminator, nullified_in_tree, tree_type", + "hash, {}, data_hash, address, onchain_pubkey, owner, tree, queue, in_output_queue, nullifier_queue_index, tx_hash, nullifier, leaf_index, seq, slot_created, spent, prev_spent, lamports, discriminator, discriminator_v2, nullified_in_tree, tree_type", query_builder.data_column ); diff --git a/src/api/method/get_compressed_token_balances_by_owner.rs b/src/api/method/get_compressed_token_balances_by_owner.rs index 6298c610..0b4a01e5 100644 --- a/src/api/method/get_compressed_token_balances_by_owner.rs +++ b/src/api/method/get_compressed_token_balances_by_owner.rs @@ -71,8 +71,7 @@ pub async fn get_compressed_token_balances_by_owner( // Only use mint > cursor_mint if we're not filtering by a specific mint // If filtering by a specific mint, the cursor should be ignored or we'd get no results if mint.is_none() { - filter = - filter.and(token_owner_balances::Column::Mint.gt::>(cursor_mint.into())); + filter = filter.and(token_owner_balances::Column::Mint.gt::>(cursor_mint)); } // If a specific mint is provided, we can't paginate within that mint // because there's only one record per owner-mint combination in token_owner_balances diff --git a/src/api/method/get_multiple_new_address_proofs.rs b/src/api/method/get_multiple_new_address_proofs.rs index 9ad38568..485a0e92 100644 --- a/src/api/method/get_multiple_new_address_proofs.rs +++ b/src/api/method/get_multiple_new_address_proofs.rs @@ -1,9 +1,9 @@ use light_compressed_account::TreeType; +use light_sdk_types::constants::ADDRESS_TREE_V1; use sea_orm::{ ConnectionTrait, DatabaseConnection, DatabaseTransaction, Statement, TransactionTrait, }; use serde::{Deserialize, Serialize}; -use solana_pubkey::{pubkey, Pubkey}; use utoipa::ToSchema; use crate::api::error::PhotonApiError; @@ -17,8 +17,6 @@ use std::collections::HashMap; pub const MAX_ADDRESSES: usize = 1000; -pub const ADDRESS_TREE_V1: Pubkey = pubkey!("amt1Ayt45jfbdw5YSo7iz6WZxUmnZsQTYXy82hVwyC2"); - #[derive(Debug, Clone, Serialize, Deserialize, ToSchema, PartialEq, Eq)] #[serde(deny_unknown_fields, rename_all = "camelCase")] #[allow(non_snake_case)] diff --git a/src/api/method/get_queue_elements.rs b/src/api/method/get_queue_elements.rs index 4d4d80fd..622941f7 100644 --- a/src/api/method/get_queue_elements.rs +++ b/src/api/method/get_queue_elements.rs @@ -28,6 +28,8 @@ use utoipa::ToSchema; const MAX_QUEUE_ELEMENTS: u16 = 30_000; const MAX_QUEUE_ELEMENTS_SQLITE: u16 = 500; +const MAX_SQL_PARAMS: usize = 30_000; + /// Encode tree node position as a single u64 /// Format: [level: u8][position: 56 bits] /// Level 0 = leaves, Level tree_height-1 = root @@ -236,13 +238,26 @@ pub async fn get_queue_elements( let (nodes, initial_root, root_seq) = merge_state_queue_proofs(&output_proof_data, &input_proof_data)?; - Some(StateQueueData { - nodes, - initial_root, - root_seq, - output_queue, - input_queue, - }) + let has_output_data = output_queue + .as_ref() + .map(|oq| !oq.leaf_indices.is_empty()) + .unwrap_or(false); + let has_input_data = input_queue + .as_ref() + .map(|iq| !iq.leaf_indices.is_empty()) + .unwrap_or(false); + + if has_output_data || has_input_data { + Some(StateQueueData { + nodes, + initial_root, + root_seq, + output_queue, + input_queue, + }) + } else { + None + } } else { None }; @@ -821,12 +836,16 @@ async fn fetch_address_queue_v2( let mut current_hash = hashed_leaf; for (level, sibling_hash) in proof.proof.iter().enumerate() { - let sibling_pos = if pos % 2 == 0 { pos + 1 } else { pos - 1 }; + let sibling_pos = if pos.is_multiple_of(2) { + pos + 1 + } else { + pos - 1 + }; let sibling_idx = encode_node_index(level as u8, sibling_pos, tree_info.height as u8); nodes_map.insert(sibling_idx, sibling_hash.clone()); - let parent_hash = if pos % 2 == 0 { + let parent_hash = if pos.is_multiple_of(2) { Poseidon::hashv(&[¤t_hash.0, &sibling_hash.0]) } else { Poseidon::hashv(&[&sibling_hash.0, ¤t_hash.0]) @@ -982,7 +1001,11 @@ fn deduplicate_nodes_from_refs( // Walk up the proof path, storing sibling hashes and path node hashes from DB for (level, sibling_hash) in proof_ctx.proof.iter().enumerate() { - let sibling_pos = if pos % 2 == 0 { pos + 1 } else { pos - 1 }; + let sibling_pos = if pos.is_multiple_of(2) { + pos + 1 + } else { + pos - 1 + }; // Store the sibling (from proof) let sibling_idx = encode_node_index(level as u8, sibling_pos, tree_height); @@ -1052,24 +1075,29 @@ async fn fetch_path_nodes_from_db( return Ok(HashMap::new()); } - let path_nodes = state_trees::Entity::find() - .filter( - state_trees::Column::Tree - .eq(tree_bytes) - .and(state_trees::Column::NodeIdx.is_in(all_path_indices)), - ) - .all(tx) - .await - .map_err(|e| { - PhotonApiError::UnexpectedError(format!("Failed to fetch path nodes: {}", e)) - })?; - let mut result = HashMap::new(); - for node in path_nodes { - let hash = Hash::try_from(node.hash).map_err(|e| { - PhotonApiError::UnexpectedError(format!("Invalid hash in path node: {}", e)) - })?; - result.insert(node.node_idx, hash); + + let tree_bytes_ref = tree_bytes.clone(); + + for chunk in all_path_indices.chunks(MAX_SQL_PARAMS) { + let path_nodes = state_trees::Entity::find() + .filter( + state_trees::Column::Tree + .eq(tree_bytes_ref.clone()) + .and(state_trees::Column::NodeIdx.is_in(chunk.to_vec())), + ) + .all(tx) + .await + .map_err(|e| { + PhotonApiError::UnexpectedError(format!("Failed to fetch path nodes: {}", e)) + })?; + + for node in path_nodes { + let hash = Hash::try_from(node.hash).map_err(|e| { + PhotonApiError::UnexpectedError(format!("Invalid hash in path node: {}", e)) + })?; + result.insert(node.node_idx, hash); + } } Ok(result) diff --git a/src/api/method/get_validity_proof/prover/helpers.rs b/src/api/method/get_validity_proof/prover/helpers.rs index ef2741bf..fc14723b 100644 --- a/src/api/method/get_validity_proof/prover/helpers.rs +++ b/src/api/method/get_validity_proof/prover/helpers.rs @@ -13,48 +13,32 @@ use light_compressed_account::hash_chain::create_two_inputs_hash_chain; pub fn convert_non_inclusion_merkle_proof_to_hex( non_inclusion_merkle_proof_inputs: Vec, ) -> Vec { - let mut inputs: Vec = Vec::new(); - for i in 0..non_inclusion_merkle_proof_inputs.len() { - let input = NonInclusionHexInputsForProver { - root: hash_to_hex(&non_inclusion_merkle_proof_inputs[i].root), - value: pubkey_to_hex(&non_inclusion_merkle_proof_inputs[i].address), - path_index: non_inclusion_merkle_proof_inputs[i].lowElementLeafIndex, - path_elements: non_inclusion_merkle_proof_inputs[i] - .proof - .iter() - .map(hash_to_hex) - .collect(), - next_index: non_inclusion_merkle_proof_inputs[i].nextIndex, - leaf_lower_range_value: pubkey_to_hex( - &non_inclusion_merkle_proof_inputs[i].lowerRangeAddress, - ), - leaf_higher_range_value: pubkey_to_hex( - &non_inclusion_merkle_proof_inputs[i].higherRangeAddress, - ), - }; - inputs.push(input); - } - inputs + non_inclusion_merkle_proof_inputs + .iter() + .map(|input| NonInclusionHexInputsForProver { + root: hash_to_hex(&input.root), + value: pubkey_to_hex(&input.address), + path_index: input.lowElementLeafIndex, + path_elements: input.proof.iter().map(hash_to_hex).collect(), + next_index: input.nextIndex, + leaf_lower_range_value: pubkey_to_hex(&input.lowerRangeAddress), + leaf_higher_range_value: pubkey_to_hex(&input.higherRangeAddress), + }) + .collect() } pub fn convert_inclusion_proofs_to_hex( inclusion_proof_inputs: Vec, ) -> Vec { - let mut inputs: Vec = Vec::new(); - for i in 0..inclusion_proof_inputs.len() { - let input = InclusionHexInputsForProver { - root: hash_to_hex(&inclusion_proof_inputs[i].root), - path_index: inclusion_proof_inputs[i].leaf_index, - path_elements: inclusion_proof_inputs[i] - .proof - .iter() - .map(hash_to_hex) - .collect(), - leaf: hash_to_hex(&inclusion_proof_inputs[i].hash), - }; - inputs.push(input); - } - inputs + inclusion_proof_inputs + .iter() + .map(|input| InclusionHexInputsForProver { + root: hash_to_hex(&input.root), + path_index: input.leaf_index, + path_elements: input.proof.iter().map(hash_to_hex).collect(), + leaf: hash_to_hex(&input.hash), + }) + .collect() } pub fn hash_to_hex(hash: &Hash) -> String { @@ -71,11 +55,7 @@ fn pubkey_to_hex(pubkey: &SerializablePubkey) -> String { } pub fn deserialize_hex_string_to_bytes(hex_str: &str) -> Result, PhotonApiError> { - let hex_str = if hex_str.starts_with("0x") { - &hex_str[2..] - } else { - hex_str - }; + let hex_str = hex_str.strip_prefix("0x").unwrap_or(hex_str); let hex_str = format!("{:0>64}", hex_str); hex::decode(hex_str) diff --git a/src/api/method/get_validity_proof/prover/prove.rs b/src/api/method/get_validity_proof/prover/prove.rs index e5f28f6e..f4d3d6f1 100644 --- a/src/api/method/get_validity_proof/prover/prove.rs +++ b/src/api/method/get_validity_proof/prover/prove.rs @@ -24,6 +24,7 @@ pub(crate) async fn generate_proof( db_new_address_proofs: Vec, root_history_capacity: u64, prover_url: &str, + prover_api_key: Option<&str>, ) -> Result { let state_tree_height = if db_account_proofs.is_empty() { 0 @@ -106,15 +107,18 @@ pub(crate) async fn generate_proof( PhotonApiError::UnexpectedError(format!("Error serializing prover request: {}", e)) })?; - let res = client + let mut request_builder = client .post(&prover_request_url) .body(json_body) - .header("Content-Type", "application/json") - .send() - .await - .map_err(|e| { - PhotonApiError::UnexpectedError(format!("Error sending request to prover: {}", e)) - })?; + .header("Content-Type", "application/json"); + + if let Some(api_key) = prover_api_key { + request_builder = request_builder.header("Authorization", format!("Bearer {}", api_key)); + } + + let res = request_builder.send().await.map_err(|e| { + PhotonApiError::UnexpectedError(format!("Error sending request to prover: {}", e)) + })?; if !res.status().is_success() { return Err(PhotonApiError::UnexpectedError(format!( diff --git a/src/api/method/get_validity_proof/prover/structs.rs b/src/api/method/get_validity_proof/prover/structs.rs index b2017a75..5d7f02b6 100644 --- a/src/api/method/get_validity_proof/prover/structs.rs +++ b/src/api/method/get_validity_proof/prover/structs.rs @@ -2,7 +2,6 @@ use crate::ingester::parser::tree_info::TreeInfo; use jsonrpsee_core::Serialize; use num_traits::identities::Zero; use serde::Deserialize; -use utoipa::ToSchema; #[derive(Debug, Clone)] pub(crate) struct AccountProofDetail { @@ -66,13 +65,43 @@ pub(crate) struct ProofABC { pub c: [u8; 64], } -#[derive(Serialize, Deserialize, Default, ToSchema, Debug, Clone)] +#[derive(Serialize, Deserialize, Default, Debug, Clone)] pub struct CompressedProof { pub a: Vec, pub b: Vec, pub c: Vec, } +impl<'__s> utoipa::ToSchema<'__s> for CompressedProof { + fn schema() -> (&'__s str, utoipa::openapi::RefOr) { + use utoipa::openapi::*; + // Vec is serialized by serde as a JSON array of integers. + // utoipa's default renders Vec as string/binary which is wrong. + let byte_array = || { + RefOr::T(Schema::Array( + ArrayBuilder::new() + .items(RefOr::T(Schema::Object( + ObjectBuilder::new() + .schema_type(SchemaType::Integer) + .build(), + ))) + .build(), + )) + }; + let schema = Schema::Object( + ObjectBuilder::new() + .property("a", byte_array()) + .required("a") + .property("b", byte_array()) + .required("b") + .property("c", byte_array()) + .required("c") + .build(), + ); + ("CompressedProof", RefOr::T(schema)) + } +} + #[derive(Serialize, Deserialize, Debug)] #[serde(rename_all = "camelCase")] pub struct HexBatchInputsForProver { diff --git a/src/api/method/get_validity_proof/v1.rs b/src/api/method/get_validity_proof/v1.rs index a8688484..ddbc2ac1 100644 --- a/src/api/method/get_validity_proof/v1.rs +++ b/src/api/method/get_validity_proof/v1.rs @@ -1,5 +1,5 @@ use crate::api::method::get_multiple_new_address_proofs::{ - get_multiple_new_address_proofs_helper, AddressWithTree, ADDRESS_TREE_V1, MAX_ADDRESSES, + get_multiple_new_address_proofs_helper, AddressWithTree, MAX_ADDRESSES, }; use crate::api::method::get_validity_proof::prover::prove::generate_proof; use crate::api::method::get_validity_proof::CompressedProof; @@ -11,6 +11,7 @@ use crate::{ api::error::PhotonApiError, common::typedefs::serializable_pubkey::SerializablePubkey, }; use jsonrpsee_core::Serialize; +use light_sdk_types::constants::ADDRESS_TREE_V1; use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, TransactionTrait}; use serde::Deserialize; use utoipa::ToSchema; @@ -57,6 +58,7 @@ pub struct GetValidityProofResponse { pub async fn get_validity_proof( conn: &DatabaseConnection, prover_url: &str, + prover_api_key: Option<&str>, mut request: GetValidityProofRequest, ) -> Result { if request.hashes.is_empty() @@ -149,6 +151,7 @@ pub async fn get_validity_proof( db_new_address_proofs, root_history_capacity, prover_url, + prover_api_key, ) .await?; diff --git a/src/api/method/get_validity_proof/v2.rs b/src/api/method/get_validity_proof/v2.rs index a4c054a8..c085ca28 100644 --- a/src/api/method/get_validity_proof/v2.rs +++ b/src/api/method/get_validity_proof/v2.rs @@ -130,6 +130,7 @@ impl From> for RootIndex { pub async fn get_validity_proof_v2( conn: &DatabaseConnection, prover_url: &str, + prover_api_key: Option<&str>, request: GetValidityProofRequestV2, ) -> Result { if request.hashes.is_empty() && request.new_addresses_with_trees.is_empty() { @@ -244,7 +245,7 @@ pub async fn get_validity_proof_v2( // Try to get tree from prove-by-index accounts accounts_for_prove_by_index_inputs .iter() - .find_map(|opt_acc| opt_acc.as_ref().map(|acc| acc.merkle_context.tree.clone())) + .find_map(|opt_acc| opt_acc.as_ref().map(|acc| acc.merkle_context.tree)) }; let root_history_capacity = if let Some(tree_pubkey) = tree_pubkey { @@ -281,6 +282,7 @@ pub async fn get_validity_proof_v2( db_new_address_proofs_for_prover, root_history_capacity, prover_url, + prover_api_key, ) .await?; diff --git a/src/api/rpc_server.rs b/src/api/rpc_server.rs index 231648ca..5cc11dd8 100644 --- a/src/api/rpc_server.rs +++ b/src/api/rpc_server.rs @@ -10,7 +10,11 @@ use tower_http::cors::{Any, CorsLayer}; use super::api::PhotonApi; -pub async fn run_server(api: PhotonApi, port: u16) -> Result { +pub async fn run_server( + api: PhotonApi, + port: u16, + max_connections: u32, +) -> Result { let addr = SocketAddr::from(([0, 0, 0, 0], port)); let cors = CorsLayer::new() .allow_methods([Method::POST, Method::GET]) @@ -21,6 +25,7 @@ pub async fn run_server(api: PhotonApi, port: u16) -> Result PathBuf { diff --git a/src/common/token_layout.rs b/src/common/token_layout.rs new file mode 100644 index 00000000..3310bce5 --- /dev/null +++ b/src/common/token_layout.rs @@ -0,0 +1,14 @@ +/// Shared constants for Light Token account byte layouts. +/// +/// SPL token account base length. +pub const SPL_TOKEN_ACCOUNT_BASE_LEN: usize = 165; +/// Account type marker byte offset in token/mint account data. +pub const TOKEN_ACCOUNT_TYPE_OFFSET: usize = SPL_TOKEN_ACCOUNT_BASE_LEN; + +/// AccountType::Mint discriminator value. +pub const ACCOUNT_TYPE_MINT: u8 = 1; + +/// Compressed mint PDA offset range `[84..116]` (32 bytes). +pub const LIGHT_MINT_PDA_OFFSET: usize = 84; +pub const LIGHT_MINT_PDA_LEN: usize = 32; +pub const LIGHT_MINT_PDA_END: usize = LIGHT_MINT_PDA_OFFSET + LIGHT_MINT_PDA_LEN; diff --git a/src/common/typedefs/account/context.rs b/src/common/typedefs/account/context.rs index eb041626..3141348d 100644 --- a/src/common/typedefs/account/context.rs +++ b/src/common/typedefs/account/context.rs @@ -17,7 +17,7 @@ use utoipa::ToSchema; /// - Internal (state_updates,..) /// - GetTransactionWithCompressionInfo (internally) /// - GetTransactionWithCompressionInfoV2 (internally) -/// All endpoints return AccountV2. +/// All endpoints return AccountV2. #[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema, Default)] #[serde(deny_unknown_fields, rename_all = "camelCase")] pub struct AccountContext { @@ -107,11 +107,20 @@ impl TryFrom for AccountWithContext { type Error = PhotonApiError; fn try_from(account: Model) -> Result { - let data = match (account.data, account.data_hash, account.discriminator) { + let parsed_discriminator = match account.discriminator_v2 { + Some(bytes) => { + let arr: [u8; 8] = bytes.try_into().map_err(|_| { + PhotonApiError::UnexpectedError("Invalid discriminator_v2 length".to_string()) + })?; + Some(u64::from_le_bytes(arr)) + } + None => account.discriminator.map(parse_decimal).transpose()?, + }; + let data = match (account.data, account.data_hash, parsed_discriminator) { (Some(data), Some(data_hash), Some(discriminator)) => Some(AccountData { data: Base64String(data), data_hash: data_hash.try_into()?, - discriminator: UnsignedInteger(parse_decimal(discriminator)?), + discriminator: UnsignedInteger(discriminator), }), (None, None, None) => None, _ => { diff --git a/src/common/typedefs/account/mod.rs b/src/common/typedefs/account/mod.rs index a508a289..1a8b7f63 100644 --- a/src/common/typedefs/account/mod.rs +++ b/src/common/typedefs/account/mod.rs @@ -3,5 +3,8 @@ mod v1; mod v2; pub use context::{AccountContext, AccountWithContext}; -pub use v1::{Account, AccountData}; +pub use v1::{ + Account, AccountData, C_TOKEN_DISCRIMINATOR_V1, C_TOKEN_DISCRIMINATOR_V2, + C_TOKEN_DISCRIMINATOR_V3, +}; pub use v2::AccountV2; diff --git a/src/common/typedefs/account/v1.rs b/src/common/typedefs/account/v1.rs index bed21dd3..7ab15a8c 100644 --- a/src/common/typedefs/account/v1.rs +++ b/src/common/typedefs/account/v1.rs @@ -7,12 +7,16 @@ use crate::common::typedefs::token_data::TokenData; use crate::common::typedefs::unsigned_integer::UnsignedInteger; use crate::dao::generated::accounts::Model; use crate::ingester::error::IngesterError; -use crate::ingester::persist::COMPRESSED_TOKEN_PROGRAM; +use crate::ingester::persist::LIGHT_TOKEN_PROGRAM_ID; use jsonrpsee_core::Serialize; +use light_sdk_types::TOKEN_COMPRESSED_ACCOUNT_DISCRIMINATOR; use utoipa::ToSchema; -pub const C_TOKEN_DISCRIMINATOR_V1: [u8; 8] = [2, 0, 0, 0, 0, 0, 0, 0]; +/// Re-export V1 discriminator from light-sdk-types under local naming convention. +pub const C_TOKEN_DISCRIMINATOR_V1: [u8; 8] = TOKEN_COMPRESSED_ACCOUNT_DISCRIMINATOR; +/// V2: batched Merkle trees (not yet exported from SDK crates) pub const C_TOKEN_DISCRIMINATOR_V2: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 3]; +/// V3/ShaFlat: SHA256 flat hash with TLV extensions (not yet exported from SDK crates) pub const C_TOKEN_DISCRIMINATOR_V3: [u8; 8] = [0, 0, 0, 0, 0, 0, 0, 4]; #[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema, Default)] @@ -37,7 +41,7 @@ impl Account { pub fn parse_token_data(&self) -> Result, IngesterError> { match self.data.as_ref() { Some(data) - if self.owner.0 == COMPRESSED_TOKEN_PROGRAM && data.is_c_token_discriminator() => + if self.owner.0 == LIGHT_TOKEN_PROGRAM_ID && data.is_c_token_discriminator() => { let data_slice = data.data.0.as_slice(); let token_data = TokenData::parse(data_slice).map_err(|e| { @@ -71,11 +75,20 @@ impl TryFrom for Account { type Error = PhotonApiError; fn try_from(account: Model) -> Result { - let data = match (account.data, account.data_hash, account.discriminator) { + let parsed_discriminator = match account.discriminator_v2 { + Some(bytes) => { + let arr: [u8; 8] = bytes.try_into().map_err(|_| { + PhotonApiError::UnexpectedError("Invalid discriminator_v2 length".to_string()) + })?; + Some(u64::from_le_bytes(arr)) + } + None => account.discriminator.map(parse_decimal).transpose()?, + }; + let data = match (account.data, account.data_hash, parsed_discriminator) { (Some(data), Some(data_hash), Some(discriminator)) => Some(AccountData { data: Base64String(data), data_hash: data_hash.try_into()?, - discriminator: UnsignedInteger(parse_decimal(discriminator)?), + discriminator: UnsignedInteger(discriminator), }), (None, None, None) => None, _ => { diff --git a/src/common/typedefs/account/v2.rs b/src/common/typedefs/account/v2.rs index 41ebb424..d809a56e 100644 --- a/src/common/typedefs/account/v2.rs +++ b/src/common/typedefs/account/v2.rs @@ -9,7 +9,7 @@ use crate::common::typedefs::token_data::TokenData; use crate::common::typedefs::unsigned_integer::UnsignedInteger; use crate::dao::generated::accounts::Model; use crate::ingester::error::IngesterError; -use crate::ingester::persist::COMPRESSED_TOKEN_PROGRAM; +use crate::ingester::persist::LIGHT_TOKEN_PROGRAM_ID; use serde::Serialize; use utoipa::ToSchema; @@ -41,7 +41,7 @@ impl AccountV2 { pub fn parse_token_data(&self) -> Result, IngesterError> { match self.data.as_ref() { Some(data) - if self.owner.0 == COMPRESSED_TOKEN_PROGRAM && data.is_c_token_discriminator() => + if self.owner.0 == LIGHT_TOKEN_PROGRAM_ID && data.is_c_token_discriminator() => { let data_slice = data.data.0.as_slice(); let token_data = TokenData::parse(data_slice).map_err(|e| { @@ -58,11 +58,20 @@ impl TryFrom for AccountV2 { type Error = PhotonApiError; fn try_from(account: Model) -> Result { - let data = match (account.data, account.data_hash, account.discriminator) { + let parsed_discriminator = match account.discriminator_v2 { + Some(bytes) => { + let arr: [u8; 8] = bytes.try_into().map_err(|_| { + PhotonApiError::UnexpectedError("Invalid discriminator_v2 length".to_string()) + })?; + Some(u64::from_le_bytes(arr)) + } + None => account.discriminator.map(parse_decimal).transpose()?, + }; + let data = match (account.data, account.data_hash, parsed_discriminator) { (Some(data), Some(data_hash), Some(discriminator)) => Some(AccountData { data: Base64String(data), data_hash: data_hash.try_into()?, - discriminator: UnsignedInteger(parse_decimal(discriminator)?), + discriminator: UnsignedInteger(discriminator), }), (None, None, None) => None, _ => { @@ -90,7 +99,11 @@ impl TryFrom for AccountV2 { merkle_context: MerkleContextV2 { tree_type: account.tree_type.map(|t| t as u16).unwrap_or(0), tree: account.tree.try_into()?, - queue: account.queue.unwrap_or_default().try_into()?, + queue: account + .queue + .map(SerializablePubkey::try_from) + .transpose()? + .unwrap_or_default(), cpi_context: None, next_tree_context: None, }, @@ -102,9 +115,9 @@ impl From<&AccountWithContext> for AccountV2 { fn from(x: &AccountWithContext) -> Self { AccountV2 { hash: x.account.hash.clone(), - address: x.account.address.clone(), + address: x.account.address, data: x.account.data.clone(), - owner: x.account.owner.clone(), + owner: x.account.owner, lamports: x.account.lamports, leaf_index: x.account.leaf_index, seq: x.account.seq, @@ -112,8 +125,8 @@ impl From<&AccountWithContext> for AccountV2 { prove_by_index: x.context.in_output_queue, merkle_context: MerkleContextV2 { tree_type: x.context.tree_type, - tree: x.account.tree.clone(), - queue: x.context.queue.clone(), + tree: x.account.tree, + queue: x.context.queue, cpi_context: None, next_tree_context: None, }, diff --git a/src/common/typedefs/token_data.rs b/src/common/typedefs/token_data.rs index b91e9a53..16d5b801 100644 --- a/src/common/typedefs/token_data.rs +++ b/src/common/typedefs/token_data.rs @@ -44,13 +44,11 @@ pub struct TokenData { pub delegate: Option, /// The account's state pub state: AccountState, - /// TokenExtension TLV data (raw bytes, opaque to the indexer) + /// TokenExtension TLV data pub tlv: Option, } impl TokenData { - /// Deserializes base fields via Borsh, then reads TLV as raw bytes (1-byte - /// option tag + remaining bytes). pub fn parse(data: &[u8]) -> Result { let mut buf = data; @@ -66,17 +64,19 @@ impl TokenData { let option_tag = buf[0]; buf = &buf[1..]; - match option_tag { - 0 => None, - 1 if !buf.is_empty() => Some(Base64String(buf.to_vec())), - other => { + if option_tag == 0 { + None + } else if option_tag == 1 && !buf.is_empty() { + Some(Base64String(buf.to_vec())) + } else { + if option_tag != 0 && option_tag != 1 { log::warn!( - "Unexpected TLV: option_tag={}, remaining_bytes={}", - other, + "Unknown TLV option_tag={} with {} bytes remaining", + option_tag, buf.len() ); - None } + None } }; @@ -114,177 +114,218 @@ mod tests { use super::*; use solana_pubkey::Pubkey; - fn build_onchain_token_data_bytes(has_delegate: bool, tlv: Option<&[u8]>) -> Vec { - let mut bytes = Vec::new(); - bytes.extend_from_slice(&[0x11u8; 32]); // mint - bytes.extend_from_slice(&[0x22u8; 32]); // owner - bytes.extend_from_slice(&100u64.to_le_bytes()); // amount - if has_delegate { - bytes.push(1); - bytes.extend_from_slice(&[0x33u8; 32]); - } else { - bytes.push(0); - } - bytes.push(0); // state = initialized - match tlv { - Some(tlv_data) => { - bytes.push(1); // Option tag = Some - bytes.extend_from_slice(tlv_data); - } - None => { - bytes.push(0); // Option tag = None - } + fn sample_token_data(tlv: Option>) -> TokenData { + TokenData { + mint: SerializablePubkey::from(Pubkey::new_unique()), + owner: SerializablePubkey::from(Pubkey::new_unique()), + amount: UnsignedInteger(42), + delegate: Some(SerializablePubkey::from(Pubkey::new_unique())), + state: AccountState::initialized, + tlv: tlv.map(Base64String), } - bytes - } - - fn build_compressed_only_tlv() -> Vec { - let mut tlv = Vec::new(); - tlv.extend_from_slice(&1u32.to_le_bytes()); // vec len = 1 element - tlv.push(31); // ExtensionStruct enum variant = CompressedOnly - tlv.extend_from_slice(&500u64.to_le_bytes()); // delegated_amount - tlv.extend_from_slice(&0u64.to_le_bytes()); // withheld_transfer_fee - tlv.push(1); // is_ata - tlv } #[test] - fn parse_v1_no_delegate_no_tlv() { - let bytes = build_onchain_token_data_bytes(false, None); - let td = TokenData::parse(&bytes).unwrap(); - assert_eq!(td.mint.0, Pubkey::from([0x11; 32])); - assert_eq!(td.owner.0, Pubkey::from([0x22; 32])); - assert_eq!(td.amount.0, 100); - assert!(td.delegate.is_none()); - assert_eq!(td.state, AccountState::initialized); - assert!(td.tlv.is_none()); - } + fn serialize_parse_roundtrip_without_tlv() { + let token_data = sample_token_data(None); - #[test] - fn parse_v1_with_delegate_no_tlv() { - let bytes = build_onchain_token_data_bytes(true, None); - let td = TokenData::parse(&bytes).unwrap(); - assert_eq!(td.delegate.unwrap().0, Pubkey::from([0x33; 32])); - assert!(td.tlv.is_none()); - } + let mut bytes = Vec::new(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); - #[test] - fn parse_v3_with_compressed_only_tlv() { - let tlv_raw = build_compressed_only_tlv(); - let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw)); - - let td = TokenData::parse(&bytes).unwrap(); - assert_eq!(td.amount.0, 100); - assert!(td.delegate.is_some()); - let tlv = td.tlv.unwrap(); - assert_eq!(tlv.0, tlv_raw); + let parsed = TokenData::parse(&bytes).unwrap(); + assert_eq!(parsed, token_data); } #[test] - fn parse_v3_no_delegate_with_tlv() { - let tlv_raw = build_compressed_only_tlv(); - let bytes = build_onchain_token_data_bytes(false, Some(&tlv_raw)); - - let td = TokenData::parse(&bytes).unwrap(); - assert!(td.delegate.is_none()); - assert!(td.tlv.is_some()); - assert_eq!(td.tlv.unwrap().0, tlv_raw); - } + fn serialize_parse_roundtrip_with_tlv_raw_bytes() { + // Starts with a vec-length-like prefix to ensure serializer doesn't add another one. + let raw_tlv = vec![2, 0, 0, 0, 7, 8, 9, 10]; + let token_data = sample_token_data(Some(raw_tlv.clone())); - #[derive(Debug, BorshDeserialize)] - struct OldTokenData { - pub mint: SerializablePubkey, - pub owner: SerializablePubkey, - pub amount: UnsignedInteger, - pub delegate: Option, - pub state: AccountState, - pub tlv: Option, - } + let mut bytes = Vec::new(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); - #[test] - fn old_try_from_slice_fails_with_not_all_bytes_read() { - let tlv_raw = build_compressed_only_tlv(); - let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw)); - - let err = OldTokenData::try_from_slice(&bytes) - .expect_err("old BorshDeserialize must fail on V3 TLV data"); - - assert_eq!(err.kind(), std::io::ErrorKind::InvalidData); - assert!( - err.to_string().contains("Not all bytes read"), - "Expected exact production error 'Not all bytes read', got: {}", - err - ); + // Fixed fields: mint(32) + owner(32) + amount(8) + delegate_option(1+32) + state(1) + let fixed_len = 32 + 32 + 8 + 33 + 1; + assert_eq!(bytes[fixed_len], 1); // tlv option tag + assert_eq!(&bytes[(fixed_len + 1)..], raw_tlv.as_slice()); + + let parsed = TokenData::parse(&bytes).unwrap(); + assert_eq!(parsed, token_data); } #[test] - fn new_parse_succeeds_where_old_try_from_slice_fails() { - let tlv_raw = build_compressed_only_tlv(); - let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw)); - - // Old code fails: - assert!(OldTokenData::try_from_slice(&bytes).is_err()); - // New code succeeds and captures TLV: - let td = TokenData::parse(&bytes).unwrap(); - assert_eq!(td.tlv.unwrap().0, tlv_raw); + fn serialize_parse_roundtrip_without_delegate() { + let token_data = TokenData { + mint: SerializablePubkey::from(Pubkey::new_unique()), + owner: SerializablePubkey::from(Pubkey::new_unique()), + amount: UnsignedInteger(123456789), + delegate: None, + state: AccountState::frozen, + tlv: None, + }; + + let mut bytes = Vec::new(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); + + // Fixed fields: mint(32) + owner(32) + amount(8) + delegate_option(1) + state(1) + tlv_option(1) = 75 + assert_eq!(bytes.len(), 75); + + let parsed = TokenData::parse(&bytes).unwrap(); + assert_eq!(parsed, token_data); } #[test] - fn roundtrip_no_tlv() { - let original = TokenData { - mint: SerializablePubkey(Pubkey::new_unique()), - owner: SerializablePubkey(Pubkey::new_unique()), - amount: UnsignedInteger(42), + fn serialize_tlv_option_none_explicit() { + let token_data = TokenData { + mint: SerializablePubkey::from([1u8; 32]), + owner: SerializablePubkey::from([2u8; 32]), + amount: UnsignedInteger(100), delegate: None, state: AccountState::initialized, tlv: None, }; + let mut bytes = Vec::new(); - borsh::BorshSerialize::serialize(&original, &mut bytes).unwrap(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); + + // TLV should serialize as a single 0 byte at the end + assert_eq!(bytes.len(), 75); // 32+32+8+1+1+1 = 75 + assert_eq!(*bytes.last().unwrap(), 0); // Last byte should be 0 (None option) + let parsed = TokenData::parse(&bytes).unwrap(); - assert_eq!(parsed, original); + assert_eq!(parsed.tlv, None); } #[test] - fn roundtrip_with_tlv() { - let original = TokenData { - mint: SerializablePubkey(Pubkey::new_unique()), - owner: SerializablePubkey(Pubkey::new_unique()), - amount: UnsignedInteger(1_000_000), - delegate: Some(SerializablePubkey(Pubkey::new_unique())), + fn serialize_empty_tlv_vec() { + let token_data = TokenData { + mint: SerializablePubkey::from([3u8; 32]), + owner: SerializablePubkey::from([4u8; 32]), + amount: UnsignedInteger(999), + delegate: Some(SerializablePubkey::from([5u8; 32])), state: AccountState::frozen, - tlv: Some(Base64String(vec![0xAA, 0xBB, 0xCC])), + tlv: Some(Base64String(vec![])), }; + let mut bytes = Vec::new(); - borsh::BorshSerialize::serialize(&original, &mut bytes).unwrap(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); + + // Fixed + tlv option tag (1) + let fixed_len = 32 + 32 + 8 + 33 + 1; + assert_eq!(bytes[fixed_len], 1); // Option::Some tag + assert_eq!(bytes.len(), fixed_len + 1); // No data after the tag + + // NOTE: parse() treats empty TLV (option=1, no data) as None per line 69 let parsed = TokenData::parse(&bytes).unwrap(); - assert_eq!(parsed, original); + assert_eq!(parsed.tlv, None); // parse behavior: empty TLV -> None } #[test] - fn byte_layout_no_delegate_no_tlv() { - let bytes = build_onchain_token_data_bytes(false, None); - // mint(32) + owner(32) + amount(8) + delegate_none(1) + state(1) + tlv_none(1) = 75 - assert_eq!(bytes.len(), 75); - let td = TokenData::parse(&bytes).unwrap(); - assert!(td.tlv.is_none()); + fn byte_layout_consistency() { + // Verify exact byte layout matches what parse() expects + let mint = [11u8; 32]; + let owner = [22u8; 32]; + let amount = 42u64; + let delegate = [33u8; 32]; + let state = 1u8; // frozen + let tlv_data = vec![0xAA, 0xBB, 0xCC]; + + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from(owner), + amount: UnsignedInteger(amount), + delegate: Some(SerializablePubkey::from(delegate)), + state: AccountState::frozen, + tlv: Some(Base64String(tlv_data.clone())), + }; + + let mut bytes = Vec::new(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); + + // Verify manual layout + assert_eq!(&bytes[0..32], &mint); + assert_eq!(&bytes[32..64], &owner); + assert_eq!(&bytes[64..72], &amount.to_le_bytes()); + assert_eq!(bytes[72], 1); // delegate option tag + assert_eq!(&bytes[73..105], &delegate); + assert_eq!(bytes[105], state); + assert_eq!(bytes[106], 1); // tlv option tag + assert_eq!(&bytes[107..], &tlv_data[..]); } #[test] - fn byte_layout_with_delegate_no_tlv() { - let bytes = build_onchain_token_data_bytes(true, None); - // mint(32) + owner(32) + amount(8) + delegate_some(1+32) + state(1) + tlv_none(1) = 107 + fn compatibility_with_light_token_format() { + // This test ensures our serialization matches the light program's expected format + // based on the TokenData struct from light-token-interface + let token_data = TokenData { + mint: SerializablePubkey::from([0x10; 32]), + owner: SerializablePubkey::from([0x20; 32]), + amount: UnsignedInteger(1_000_000), + delegate: Some(SerializablePubkey::from([0x30; 32])), + state: AccountState::initialized, + tlv: None, + }; + + let mut bytes = Vec::new(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); + + // Verify the format: + // 32 bytes: mint pubkey + // 32 bytes: owner pubkey + // 8 bytes: amount (u64 LE) + // 1 byte: delegate option (1 = Some) + // 32 bytes: delegate pubkey + // 1 byte: state (0 = initialized) + // 1 byte: tlv option (0 = None) assert_eq!(bytes.len(), 107); + + let parsed = TokenData::parse(&bytes).unwrap(); + assert_eq!(parsed, token_data); + } + + #[test] + fn various_amounts() { + for amount in [0u64, 1, 1000, u64::MAX] { + let token_data = TokenData { + mint: SerializablePubkey::from(Pubkey::new_unique()), + owner: SerializablePubkey::from(Pubkey::new_unique()), + amount: UnsignedInteger(amount), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let mut bytes = Vec::new(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); + let parsed = TokenData::parse(&bytes).unwrap(); + + assert_eq!(parsed.amount.0, amount); + } } #[test] - fn byte_layout_with_delegate_and_tlv() { - let tlv_raw = build_compressed_only_tlv(); - // tlv_raw: u32(4) + discriminant(1) + u64(8) + u64(8) + u8(1) = 22 - assert_eq!(tlv_raw.len(), 22); - let bytes = build_onchain_token_data_bytes(true, Some(&tlv_raw)); - // 107 (with delegate, no tlv excl the None byte) - 1 (remove None byte) - // + 1 (Some tag) + 22 (tlv_raw) = 129 - assert_eq!(bytes.len(), 129); + fn various_tlv_sizes() { + for tlv_size in [0, 1, 10, 100, 1000] { + let tlv_data = vec![0x42u8; tlv_size]; + let token_data = TokenData { + mint: SerializablePubkey::from(Pubkey::new_unique()), + owner: SerializablePubkey::from(Pubkey::new_unique()), + amount: UnsignedInteger(100), + delegate: None, + state: AccountState::initialized, + tlv: if tlv_size == 0 { + None + } else { + Some(Base64String(tlv_data.clone())) + }, + }; + + let mut bytes = Vec::new(); + borsh::BorshSerialize::serialize(&token_data, &mut bytes).unwrap(); + let parsed = TokenData::parse(&bytes).unwrap(); + + assert_eq!(parsed, token_data); + } } } diff --git a/src/dao/generated/accounts.rs b/src/dao/generated/accounts.rs index c968a218..bb49e407 100644 --- a/src/dao/generated/accounts.rs +++ b/src/dao/generated/accounts.rs @@ -19,8 +19,6 @@ pub struct Model { pub prev_spent: Option, #[sea_orm(column_type = "Decimal(Some((23, 0)))")] pub lamports: Decimal, - #[sea_orm(column_type = "Decimal(Some((23, 0)))", nullable)] - pub discriminator: Option, pub tree_type: Option, pub nullified_in_tree: bool, pub nullifier_queue_index: Option, @@ -28,14 +26,26 @@ pub struct Model { pub queue: Option>, pub nullifier: Option>, pub tx_hash: Option>, + pub onchain_pubkey: Option>, + pub discriminator_v2: Option>, + #[sea_orm(column_type = "Decimal(Some((23, 0)))", nullable)] + pub discriminator: Option, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { - #[sea_orm(has_many = "super::token_accounts::Entity")] + #[sea_orm(has_many = "super::account_transactions::Entity")] + AccountTransactions, + #[sea_orm(has_one = "super::token_accounts::Entity")] TokenAccounts, } +impl Related for Entity { + fn to() -> RelationDef { + Relation::AccountTransactions.def() + } +} + impl Related for Entity { fn to() -> RelationDef { Relation::TokenAccounts.def() diff --git a/src/dao/generated/queue_hash_chains.rs b/src/dao/generated/queue_hash_chains.rs index c892083d..e0f5ff4f 100644 --- a/src/dao/generated/queue_hash_chains.rs +++ b/src/dao/generated/queue_hash_chains.rs @@ -1,3 +1,5 @@ +//! `SeaORM` Entity. Generated by sea-orm-codegen 0.10.6 + use sea_orm::entity::prelude::*; #[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] diff --git a/src/dao/generated/token_accounts.rs b/src/dao/generated/token_accounts.rs index e9604cba..99dc815a 100644 --- a/src/dao/generated/token_accounts.rs +++ b/src/dao/generated/token_accounts.rs @@ -16,6 +16,7 @@ pub struct Model { #[sea_orm(column_type = "Decimal(Some((23, 0)))")] pub amount: Decimal, pub tlv: Option>, + pub ata_owner: Option>, } #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] diff --git a/src/dao/generated/transactions.rs b/src/dao/generated/transactions.rs index 977fc8de..b2d9f46a 100644 --- a/src/dao/generated/transactions.rs +++ b/src/dao/generated/transactions.rs @@ -15,6 +15,8 @@ pub struct Model { #[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] pub enum Relation { + #[sea_orm(has_many = "super::account_transactions::Entity")] + AccountTransactions, #[sea_orm( belongs_to = "super::blocks::Entity", from = "Column::Slot", @@ -25,6 +27,12 @@ pub enum Relation { Blocks, } +impl Related for Entity { + fn to() -> RelationDef { + Relation::AccountTransactions.def() + } +} + impl Related for Entity { fn to() -> RelationDef { Relation::Blocks.def() diff --git a/src/dao/helpers.rs b/src/dao/helpers.rs index b9d26f82..837af562 100644 --- a/src/dao/helpers.rs +++ b/src/dao/helpers.rs @@ -4,7 +4,10 @@ use crate::dao::generated::{accounts, state_trees}; use sea_orm::{ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter}; use std::collections::HashMap; -/// Finds accounts by multiple hashes, optionally filtering by spent status +/// Maximum number of parameters allowed in a single PostgreSQL query. +const MAX_SQL_PARAMS: usize = 30_000; + +/// Finds accounts by multiple hashes, optionally filtering by spent status. pub async fn find_accounts_by_hashes( conn: &DatabaseConnection, hashes: &[Hash], @@ -12,18 +15,24 @@ pub async fn find_accounts_by_hashes( ) -> Result, accounts::Model>, sea_orm::DbErr> { let raw_hashes: Vec> = hashes.iter().map(|h| h.to_vec()).collect(); - let mut query = accounts::Entity::find().filter(accounts::Column::Hash.is_in(raw_hashes)); + let mut result = HashMap::new(); - if let Some(spent) = spent_filter { - query = query.filter(accounts::Column::Spent.eq(spent)); - } + for chunk in raw_hashes.chunks(MAX_SQL_PARAMS) { + let mut query = + accounts::Entity::find().filter(accounts::Column::Hash.is_in(chunk.to_vec())); + + if let Some(spent) = spent_filter { + query = query.filter(accounts::Column::Spent.eq(spent)); + } + + let accounts = query.all(conn).await?; - let accounts = query.all(conn).await?; + for account in accounts { + result.insert(account.hash.clone(), account); + } + } - Ok(accounts - .into_iter() - .map(|account| (account.hash.clone(), account)) - .collect()) + Ok(result) } /// Finds accounts by multiple addresses, optionally filtering by spent status @@ -34,18 +43,24 @@ pub async fn find_accounts_by_addresses( ) -> Result, accounts::Model>, sea_orm::DbErr> { let raw_addresses: Vec> = addresses.iter().map(|addr| addr.to_bytes_vec()).collect(); - let mut query = accounts::Entity::find().filter(accounts::Column::Address.is_in(raw_addresses)); + let mut result = HashMap::new(); - if let Some(spent) = spent_filter { - query = query.filter(accounts::Column::Spent.eq(spent)); - } + for chunk in raw_addresses.chunks(MAX_SQL_PARAMS) { + let mut query = + accounts::Entity::find().filter(accounts::Column::Address.is_in(chunk.to_vec())); + + if let Some(spent) = spent_filter { + query = query.filter(accounts::Column::Spent.eq(spent)); + } + + let accounts = query.all(conn).await?; - let accounts = query.all(conn).await?; + for account in accounts { + result.insert(account.address.clone().unwrap_or_default(), account); + } + } - Ok(accounts - .into_iter() - .map(|account| (account.address.clone().unwrap_or_default(), account)) - .collect()) + Ok(result) } /// Finds leaf nodes in state_trees by multiple hashes @@ -55,19 +70,24 @@ pub async fn find_leaf_nodes_by_hashes( ) -> Result, state_trees::Model>, sea_orm::DbErr> { let raw_hashes: Vec> = hashes.iter().map(|h| h.to_vec()).collect(); - let leaf_nodes = state_trees::Entity::find() - .filter( - state_trees::Column::Hash - .is_in(raw_hashes) - .and(state_trees::Column::Level.eq(0)), - ) - .all(conn) - .await?; + let mut result = HashMap::new(); + + for chunk in raw_hashes.chunks(MAX_SQL_PARAMS) { + let leaf_nodes = state_trees::Entity::find() + .filter( + state_trees::Column::Hash + .is_in(chunk.to_vec()) + .and(state_trees::Column::Level.eq(0)), + ) + .all(conn) + .await?; + + for node in leaf_nodes { + result.insert(node.hash.clone(), node); + } + } - Ok(leaf_nodes - .into_iter() - .map(|node| (node.hash.clone(), node)) - .collect()) + Ok(result) } /// Finds a single account by hash diff --git a/src/ingester/fetchers/mod.rs b/src/ingester/fetchers/mod.rs index cc3235da..54854719 100644 --- a/src/ingester/fetchers/mod.rs +++ b/src/ingester/fetchers/mod.rs @@ -45,21 +45,15 @@ impl BlockStreamConfig { stream! { if let Some(grpc_stream) = grpc_stream { pin_mut!(grpc_stream); - loop { - match grpc_stream.next().await { - Some(blocks) => yield blocks, - None => break, - } + while let Some(blocks) = grpc_stream.next().await { + yield blocks; } } if let Some(poller_stream) = poller_stream { pin_mut!(poller_stream); - loop { - match poller_stream.next().await { - Some(blocks) => yield blocks, - None => break, - } + while let Some(blocks) = poller_stream.next().await { + yield blocks; } } } diff --git a/src/ingester/fetchers/poller.rs b/src/ingester/fetchers/poller.rs index 171eb67c..084083f1 100644 --- a/src/ingester/fetchers/poller.rs +++ b/src/ingester/fetchers/poller.rs @@ -77,11 +77,7 @@ fn pop_cached_blocks_to_index( mut last_indexed_slot: u64, ) -> (Vec, u64) { let mut blocks = Vec::new(); - loop { - let min_slot = match block_cache.keys().min() { - Some(&slot) => slot, - None => break, - }; + while let Some(&min_slot) = block_cache.keys().min() { let block: &BlockInfo = block_cache.get(&min_slot).unwrap(); if block.metadata.parent_slot == last_indexed_slot { last_indexed_slot = block.metadata.slot; diff --git a/src/ingester/indexer/mod.rs b/src/ingester/indexer/mod.rs index b414f6df..5f5c49af 100644 --- a/src/ingester/indexer/mod.rs +++ b/src/ingester/indexer/mod.rs @@ -56,11 +56,7 @@ pub async fn index_block_stream( pin_mut!(block_stream); let current_slot = end_slot.unwrap_or(fetch_current_slot_with_infinite_retry(&rpc_client).await); - let number_of_blocks_to_backfill = if current_slot > last_indexed_slot_at_start { - current_slot - last_indexed_slot_at_start - } else { - 0 - }; + let number_of_blocks_to_backfill = current_slot.saturating_sub(last_indexed_slot_at_start); info!( "Backfilling historical blocks. Current number of blocks to backfill: {}", number_of_blocks_to_backfill @@ -76,7 +72,7 @@ pub async fn index_block_stream( for slot in (last_indexed_slot + 1)..(last_slot_in_block + 1) { let blocks_indexed = slot - last_indexed_slot_at_start; if blocks_indexed < number_of_blocks_to_backfill { - if blocks_indexed % PRE_BACKFILL_FREQUENCY == 0 { + if blocks_indexed.is_multiple_of(PRE_BACKFILL_FREQUENCY) { info!( "Backfilled {} / {} blocks", blocks_indexed, number_of_blocks_to_backfill diff --git a/src/ingester/mod.rs b/src/ingester/mod.rs index c14c4cc8..d091240b 100644 --- a/src/ingester/mod.rs +++ b/src/ingester/mod.rs @@ -29,6 +29,7 @@ pub mod fetchers; pub mod indexer; pub mod parser; pub mod persist; +pub mod startup_cleanup; pub mod typedefs; async fn derive_block_state_update( diff --git a/src/ingester/parser/indexer_events.rs b/src/ingester/parser/indexer_events.rs index 6a92a3f6..0cb917b7 100644 --- a/src/ingester/parser/indexer_events.rs +++ b/src/ingester/parser/indexer_events.rs @@ -2,7 +2,7 @@ /// to avoid having to import all of Light's dependencies. use borsh::{BorshDeserialize, BorshSerialize}; use light_compressed_account::Pubkey; -use light_event::event::{BatchNullifyContext, NewAddress}; +use light_event::event::{AssociatedTokenAccountOwnerInfo, BatchNullifyContext, NewAddress}; #[derive(Debug, PartialEq, Eq, Default, Clone, BorshSerialize, BorshDeserialize)] pub struct OutputCompressedAccountWithPackedContext { @@ -20,7 +20,7 @@ pub struct MerkleTreeSequenceNumberV2 { #[derive(Debug, Clone, BorshSerialize, BorshDeserialize, Default, Eq, PartialEq)] pub struct MerkleTreeSequenceNumberV1 { - pub pubkey: Pubkey, + pub tree_pubkey: Pubkey, pub seq: u64, } @@ -33,7 +33,7 @@ pub enum MerkleTreeSequenceNumber { impl MerkleTreeSequenceNumber { pub fn tree_pubkey(&self) -> Pubkey { match self { - MerkleTreeSequenceNumber::V1(x) => x.pubkey, + MerkleTreeSequenceNumber::V1(x) => x.tree_pubkey, MerkleTreeSequenceNumber::V2(x) => x.tree_pubkey, } } @@ -45,6 +45,7 @@ impl MerkleTreeSequenceNumber { } } +/// Current version of PublicTransactionEvent (with ata_owners) #[derive(Debug, Clone, BorshSerialize, BorshDeserialize, Default, PartialEq, Eq)] pub struct PublicTransactionEvent { pub input_compressed_account_hashes: Vec<[u8; 32]>, @@ -54,10 +55,64 @@ pub struct PublicTransactionEvent { pub sequence_numbers: Vec, pub relay_fee: Option, pub is_compress: bool, - pub compression_lamports: Option, + pub compress_or_decompress_lamports: Option, pub pubkey_array: Vec, // TODO: remove(data can just be written into a compressed account) 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, +} + +/// Legacy version of PublicTransactionEvent (without ata_owners, with compression_lamports) +#[derive(Debug, Clone, BorshSerialize, BorshDeserialize, Default, PartialEq, Eq)] +pub struct PublicTransactionEventLegacy { + 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 compression_lamports: Option, + pub pubkey_array: Vec, + pub message: Option>, +} + +impl From for PublicTransactionEvent { + fn from(legacy: PublicTransactionEventLegacy) -> Self { + Self { + input_compressed_account_hashes: legacy.input_compressed_account_hashes, + output_compressed_account_hashes: legacy.output_compressed_account_hashes, + output_compressed_accounts: legacy.output_compressed_accounts, + output_leaf_indices: legacy.output_leaf_indices, + sequence_numbers: legacy.sequence_numbers, + relay_fee: legacy.relay_fee, + is_compress: legacy.is_compress, + compress_or_decompress_lamports: legacy.compression_lamports, + pubkey_array: legacy.pubkey_array, + message: legacy.message, + ata_owners: Vec::new(), + } + } +} + +impl PublicTransactionEvent { + /// Deserialize from bytes, trying the current format first, then falling back to legacy. + pub fn deserialize_versioned(data: &mut &[u8]) -> Result { + let data_copy = *data; + + if let Ok(event) = Self::deserialize(data) { + if data.is_empty() { + return Ok(event); + } + } + + // Fall back to legacy version + *data = data_copy; + let legacy = PublicTransactionEventLegacy::deserialize(data)?; + Ok(legacy.into()) + } } #[derive(Debug, Clone)] diff --git a/src/ingester/parser/mod.rs b/src/ingester/parser/mod.rs index f844a3d5..fd6a883b 100644 --- a/src/ingester/parser/mod.rs +++ b/src/ingester/parser/mod.rs @@ -89,52 +89,49 @@ where state_updates.push(state_update); } else { for (index, instruction) in ordered_instructions.iter().enumerate() { - if ordered_instructions.len() - index > 1 { - if get_compression_program_id() == instruction.program_id { - // Look for a NOOP_PROGRAM_ID instruction after one or two SYSTEM_PROGRAM instructions - // We handle up to two system program instructions in the case where we also have to pay a tree rollover fee - let mut noop_instruction_index = None; - let mut system_program_count = 0; - let mut all_intermediate_are_system = true; - - // Search for the NOOP instruction, ensuring we find at least one SYSTEM_PROGRAM but no more than two - for i in (index + 1)..ordered_instructions.len() { - let current_instruction = &ordered_instructions[i]; - - if current_instruction.program_id == NOOP_PROGRAM_ID { - noop_instruction_index = Some(i); - break; - } else if current_instruction.program_id == SYSTEM_PROGRAM { - system_program_count += 1; - if system_program_count > 2 { - all_intermediate_are_system = false; - break; - } - } else { + if ordered_instructions.len() - index > 1 + && get_compression_program_id() == instruction.program_id + { + // Look for a NOOP_PROGRAM_ID instruction after one or two SYSTEM_PROGRAM instructions + // We handle up to two system program instructions in the case where we also have to pay a tree rollover fee + let mut noop_instruction_index = None; + let mut system_program_count = 0; + let mut all_intermediate_are_system = true; + + // Search for the NOOP instruction, ensuring we find at least one SYSTEM_PROGRAM but no more than two + for (i, current_instruction) in + ordered_instructions.iter().enumerate().skip(index + 1) + { + if current_instruction.program_id == NOOP_PROGRAM_ID { + noop_instruction_index = Some(i); + break; + } else if current_instruction.program_id == SYSTEM_PROGRAM { + system_program_count += 1; + if system_program_count > 2 { all_intermediate_are_system = false; break; } + } else { + all_intermediate_are_system = false; + break; } + } - // If we found a NOOP instruction, exactly one or two SYSTEM_PROGRAM instructions, and all intermediates were valid - if let Some(noop_index) = noop_instruction_index { - if system_program_count >= 1 - && system_program_count <= 2 - && all_intermediate_are_system + // If we found a NOOP instruction, exactly one or two SYSTEM_PROGRAM instructions, and all intermediates were valid + if let Some(noop_index) = noop_instruction_index { + if (1..=2).contains(&system_program_count) && all_intermediate_are_system { + if let Some(state_update) = parse_public_transaction_event_v1( + conn, + tx, + slot, + instruction, + &ordered_instructions[noop_index], + resolver, + ) + .await? { - if let Some(state_update) = parse_public_transaction_event_v1( - conn, - tx, - slot, - instruction, - &ordered_instructions[noop_index], - resolver, - ) - .await? - { - is_compression_transaction = true; - state_updates.push(state_update); - } + is_compression_transaction = true; + state_updates.push(state_update); } } } diff --git a/src/ingester/parser/state_update.rs b/src/ingester/parser/state_update.rs index 1d25014d..20512542 100644 --- a/src/ingester/parser/state_update.rs +++ b/src/ingester/parser/state_update.rs @@ -103,6 +103,9 @@ pub struct StateUpdate { // v2 input accounts that are inserted into the input queue pub batch_nullify_context: Vec, pub batch_new_addresses: Vec, + /// ATA owner info for compressed ATAs (account_hash -> wallet_owner_pubkey). + /// Used to populate the ata_owner column in token_accounts table. + pub ata_owners: HashMap, } /// Result of filtering a StateUpdate by known trees @@ -324,6 +327,7 @@ impl StateUpdate { batch_merkle_tree_events, batch_nullify_context: self.batch_nullify_context, batch_new_addresses, + ata_owners: self.ata_owners, }; Ok(FilteredStateUpdate { @@ -371,6 +375,7 @@ impl StateUpdate { merged .batch_nullify_context .extend(update.batch_nullify_context); + merged.ata_owners.extend(update.ata_owners); } merged diff --git a/src/ingester/parser/tx_event_parser.rs b/src/ingester/parser/tx_event_parser.rs index af41300f..8e2ebffa 100644 --- a/src/ingester/parser/tx_event_parser.rs +++ b/src/ingester/parser/tx_event_parser.rs @@ -5,7 +5,6 @@ use crate::ingester::parser::state_update::{AccountTransaction, StateUpdate}; use crate::ingester::parser::tree_info::{TreeInfo, TreeResolver}; use crate::ingester::parser::{get_compression_program_id, NOOP_PROGRAM_ID}; use crate::ingester::typedefs::block_info::{Instruction, TransactionInfo}; -use borsh::BorshDeserialize; use light_compressed_account::TreeType; use log::info; use solana_signature::Signature; @@ -31,24 +30,17 @@ where slot, tx.signature ); - let public_transaction_event = PublicTransactionEvent::deserialize( - &mut noop_instruction.data.as_slice(), - ) - .map_err(|e| { - IngesterError::ParserError(format!( - "Failed to deserialize PublicTransactionEvent: {}", - e - )) - })?; - create_state_update_v1( - conn, - tx.signature, - slot, - public_transaction_event.into(), - resolver, - ) - .await - .map(Some) + let public_transaction_event = + PublicTransactionEvent::deserialize_versioned(&mut noop_instruction.data.as_slice()) + .map_err(|e| { + IngesterError::ParserError(format!( + "Failed to deserialize PublicTransactionEvent: {}", + e + )) + })?; + create_state_update_v1(conn, tx.signature, slot, public_transaction_event, resolver) + .await + .map(Some) } else { Ok(None) } @@ -68,18 +60,31 @@ where let mut tree_to_seq_number = transaction_event .sequence_numbers .iter() - .map(|seq| (seq.pubkey, seq.seq)) + .map(|seq| (seq.tree_pubkey, seq.seq)) .collect::>(); - for hash in transaction_event.input_compressed_account_hashes { - state_update.in_accounts.insert(hash.into()); + for hash in transaction_event.input_compressed_account_hashes.iter() { + state_update.in_accounts.insert((*hash).into()); } - for ((out_account, hash), leaf_index) in transaction_event + // Build index from output_index to ATA owner + let ata_owner_by_index: HashMap = transaction_event + .ata_owners + .iter() + .map(|info| { + ( + info.output_index, + solana_pubkey::Pubkey::new_from_array(info.wallet_owner.to_bytes()), + ) + }) + .collect(); + + for (output_index, ((out_account, hash), leaf_index)) in transaction_event .output_compressed_accounts - .into_iter() - .zip(transaction_event.output_compressed_account_hashes) + .iter() + .zip(transaction_event.output_compressed_account_hashes.iter()) .zip(transaction_event.output_leaf_indices.iter()) + .enumerate() { let tree = transaction_event.pubkey_array[out_account.merkle_tree_index as usize]; let tree_solana = solana_pubkey::Pubkey::new_from_array(tree.to_bytes()); @@ -127,7 +132,7 @@ where let enriched_account = AccountWithContext::new( out_account.compressed_account.clone(), - &hash, + hash, tree_pubkey, queue_pubkey, *leaf_index, @@ -140,6 +145,11 @@ where tree_and_queue.tree_type, ); + // If this output has an ATA owner, map the account hash to the owner + if let Some(ata_owner) = ata_owner_by_index.get(&(output_index as u8)) { + state_update.ata_owners.insert((*hash).into(), *ata_owner); + } + state_update.out_accounts.push(enriched_account); } diff --git a/src/ingester/parser/tx_event_parser_v2.rs b/src/ingester/parser/tx_event_parser_v2.rs index c3b9c5d1..6b8e6240 100644 --- a/src/ingester/parser/tx_event_parser_v2.rs +++ b/src/ingester/parser/tx_event_parser_v2.rs @@ -25,8 +25,7 @@ pub fn parse_public_transaction_event_v2( instructions: &[Vec], accounts: Vec>, ) -> Option> { - let light_program_ids: Vec = - program_ids.iter().map(|p| to_light_pubkey(p)).collect(); + let light_program_ids: Vec = program_ids.iter().map(to_light_pubkey).collect(); let light_accounts: Vec> = accounts .into_iter() .map(|acc_vec| { @@ -75,17 +74,18 @@ pub fn parse_public_transaction_event_v2( .sequence_numbers .iter() .map(|x| MerkleTreeSequenceNumberV1 { - pubkey: x.tree_pubkey, + tree_pubkey: x.tree_pubkey, seq: x.seq, }) .collect(), relay_fee: public_transaction_event.event.relay_fee, is_compress: public_transaction_event.event.is_compress, - compression_lamports: public_transaction_event + compress_or_decompress_lamports: public_transaction_event .event .compress_or_decompress_lamports, pubkey_array: public_transaction_event.event.pubkey_array, message: public_transaction_event.event.message, + ata_owners: public_transaction_event.event.ata_owners, }; let batch_public_transaction_event = BatchPublicTransactionEvent { diff --git a/src/ingester/persist/mod.rs b/src/ingester/persist/mod.rs index 2d64cd1f..544a47c1 100644 --- a/src/ingester/persist/mod.rs +++ b/src/ingester/persist/mod.rs @@ -2,7 +2,12 @@ use super::{error, parser::state_update::AccountTransaction}; use crate::ingester::parser::state_update::{AddressQueueUpdate, StateUpdate}; use crate::{ api::method::utils::PAGE_LIMIT, - common::typedefs::{hash::Hash, token_data::TokenData}, + common::{ + token_layout::{ + ACCOUNT_TYPE_MINT, LIGHT_MINT_PDA_END, LIGHT_MINT_PDA_OFFSET, TOKEN_ACCOUNT_TYPE_OFFSET, + }, + typedefs::{hash::Hash, token_data::TokenData}, + }, dao::generated::{ account_transactions, accounts, state_tree_histories, state_trees, token_accounts, transactions, @@ -50,7 +55,11 @@ pub use self::leaf_node_proof::{ get_multiple_compressed_leaf_proofs_from_full_leaf_info, }; -pub const COMPRESSED_TOKEN_PROGRAM: Pubkey = pubkey!("cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m"); +pub const LIGHT_TOKEN_PROGRAM_ID: Pubkey = pubkey!("cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m"); + +/// Discriminator for decompressed PDA accounts: [255, 255, 255, 255, 255, 255, 255, 0] +/// This matches DECOMPRESSED_PDA_DISCRIMINATOR from light_compressible. +pub const DECOMPRESSED_ACCOUNT_DISCRIMINATOR: u64 = 0x00FFFFFFFFFFFFFF; // To avoid exceeding the 64k total parameter limit pub const MAX_SQL_INSERTS: usize = 500; @@ -82,7 +91,7 @@ pub async fn persist_state_update( batch_merkle_tree_events, batch_nullify_context, batch_new_addresses, - .. + ata_owners, } = state_update; let input_accounts_len = in_accounts.len(); @@ -104,7 +113,7 @@ pub async fn persist_state_update( debug!("Persisting output accounts..."); for chunk in out_accounts.chunks(MAX_SQL_INSERTS) { - append_output_accounts(txn, chunk).await?; + append_output_accounts(txn, chunk, &ata_owners).await?; } debug!("Persisting spent accounts..."); @@ -173,7 +182,7 @@ pub async fn persist_state_update( .map_err(|e| IngesterError::ParserError(format!("Invalid tree pubkey: {}", e)))?; nodes_by_tree .entry(tree_pubkey) - .or_insert_with(Vec::new) + .or_default() .push((leaf_node, signature)); } @@ -277,6 +286,8 @@ async fn persist_state_tree_history( pub struct EnrichedTokenAccount { pub token_data: TokenData, pub hash: Hash, + /// The wallet owner pubkey that the ATA is derived from (for compressed ATAs) + pub ata_owner: Option, } #[derive(Debug)] @@ -423,14 +434,23 @@ async fn insert_addresses_into_queues( async fn append_output_accounts( txn: &DatabaseTransaction, out_accounts: &[AccountWithContext], + ata_owners: &HashMap, ) -> Result<(), IngesterError> { let mut account_models = Vec::new(); let mut token_accounts = Vec::new(); for account in out_accounts { + let onchain_pubkey = extract_onchain_pubkey(account); + account_models.push(accounts::ActiveModel { hash: Set(account.account.hash.to_vec()), address: Set(account.account.address.map(|x| x.to_bytes_vec())), + onchain_pubkey: Set(onchain_pubkey), + discriminator_v2: Set(account + .account + .data + .as_ref() + .map(|x| x.discriminator.0.to_le_bytes().to_vec())), discriminator: Set(account .account .data @@ -456,9 +476,11 @@ async fn append_output_accounts( }); if let Some(token_data) = account.account.parse_token_data()? { + let ata_owner = ata_owners.get(&account.account.hash).copied(); token_accounts.push(EnrichedTokenAccount { token_data, hash: account.account.hash.clone(), + ata_owner, }); } } @@ -488,6 +510,27 @@ async fn append_output_accounts( Ok(()) } +fn extract_onchain_pubkey(account: &AccountWithContext) -> Option> { + let data = account.account.data.as_ref()?; + + // Decompressed PDA accounts store the on-chain pubkey in the first 32 bytes. + if data.discriminator.0 == DECOMPRESSED_ACCOUNT_DISCRIMINATOR && data.data.0.len() >= 32 { + return Some(data.data.0[..32].to_vec()); + } + + // Compressed mints store the mint PDA at [84..116], and have account_type marker + // ACCOUNT_TYPE_MINT at byte TOKEN_ACCOUNT_TYPE_OFFSET. + if account.account.owner.0 == LIGHT_TOKEN_PROGRAM_ID + && !data.is_c_token_discriminator() + && data.data.0.len() > TOKEN_ACCOUNT_TYPE_OFFSET + && data.data.0[TOKEN_ACCOUNT_TYPE_OFFSET] == ACCOUNT_TYPE_MINT + { + return Some(data.data.0[LIGHT_MINT_PDA_OFFSET..LIGHT_MINT_PDA_END].to_vec()); + } + + None +} + pub async fn persist_token_accounts( txn: &DatabaseTransaction, token_accounts: Vec, @@ -495,7 +538,11 @@ pub async fn persist_token_accounts( let token_models = token_accounts .into_iter() .map( - |EnrichedTokenAccount { token_data, hash }| token_accounts::ActiveModel { + |EnrichedTokenAccount { + token_data, + hash, + ata_owner, + }| token_accounts::ActiveModel { hash: Set(hash.into()), mint: Set(token_data.mint.to_bytes_vec()), owner: Set(token_data.owner.to_bytes_vec()), @@ -505,6 +552,7 @@ pub async fn persist_token_accounts( spent: Set(false), prev_spent: Set(None), tlv: Set(token_data.tlv.map(|t| t.0)), + ata_owner: Set(ata_owner.map(|o| o.to_bytes().to_vec())), }, ) .collect::>(); @@ -631,3 +679,90 @@ async fn persist_account_transactions( Ok(()) } + +#[cfg(test)] +mod tests { + use super::*; + use crate::common::typedefs::account::{ + Account, AccountContext, AccountData, C_TOKEN_DISCRIMINATOR_V2, + }; + use crate::common::typedefs::bs64_string::Base64String; + use crate::common::typedefs::serializable_pubkey::SerializablePubkey; + use crate::common::typedefs::unsigned_integer::UnsignedInteger; + + fn sample_account_with_context( + owner: Pubkey, + discriminator: u64, + data: Vec, + ) -> AccountWithContext { + AccountWithContext { + account: Account { + hash: Hash::default(), + address: None, + data: Some(AccountData { + discriminator: UnsignedInteger(discriminator), + data: Base64String(data), + data_hash: Hash::default(), + }), + owner: SerializablePubkey::from(owner), + lamports: UnsignedInteger(0), + tree: SerializablePubkey::default(), + leaf_index: UnsignedInteger(0), + seq: None, + slot_created: UnsignedInteger(0), + }, + context: AccountContext { + queue: SerializablePubkey::default(), + in_output_queue: true, + spent: false, + nullified_in_tree: false, + nullifier_queue_index: None, + nullifier: None, + tx_hash: None, + tree_type: 0, + }, + } + } + + #[test] + fn test_extract_onchain_pubkey_for_decompressed_pda() { + let expected = (0u8..32).collect::>(); + let mut data = expected.clone(); + data.extend_from_slice(&[9u8; 8]); + + let account = sample_account_with_context( + Pubkey::new_unique(), + DECOMPRESSED_ACCOUNT_DISCRIMINATOR, + data, + ); + + assert_eq!(extract_onchain_pubkey(&account), Some(expected)); + } + + #[test] + fn test_extract_onchain_pubkey_for_compressed_mint() { + let mut data = vec![0u8; TOKEN_ACCOUNT_TYPE_OFFSET + 1]; + let expected = [7u8; 32]; + data[LIGHT_MINT_PDA_OFFSET..LIGHT_MINT_PDA_END].copy_from_slice(&expected); + data[TOKEN_ACCOUNT_TYPE_OFFSET] = ACCOUNT_TYPE_MINT; + + let account = sample_account_with_context(LIGHT_TOKEN_PROGRAM_ID, 0, data); + + assert_eq!(extract_onchain_pubkey(&account), Some(expected.to_vec())); + } + + #[test] + fn test_extract_onchain_pubkey_skips_ctoken_discriminator() { + let mut data = vec![0u8; TOKEN_ACCOUNT_TYPE_OFFSET + 1]; + data[LIGHT_MINT_PDA_OFFSET..LIGHT_MINT_PDA_END].copy_from_slice(&[8u8; 32]); + data[TOKEN_ACCOUNT_TYPE_OFFSET] = ACCOUNT_TYPE_MINT; + + let account = sample_account_with_context( + LIGHT_TOKEN_PROGRAM_ID, + u64::from_le_bytes(C_TOKEN_DISCRIMINATOR_V2), + data, + ); + + assert_eq!(extract_onchain_pubkey(&account), None); + } +} diff --git a/src/ingester/persist/persisted_batch_event/address.rs b/src/ingester/persist/persisted_batch_event/address.rs index 2acf92f4..0723077f 100644 --- a/src/ingester/persist/persisted_batch_event/address.rs +++ b/src/ingester/persist/persisted_batch_event/address.rs @@ -131,7 +131,7 @@ pub async fn persist_batch_address_append_event( Ok(()) } -async fn cleanup_stale_address_queue_entries( +pub async fn cleanup_stale_address_queue_entries( txn: &DatabaseTransaction, batch_address_append_event: &BatchEvent, queue_end: i64, diff --git a/src/ingester/persist/persisted_batch_event/append.rs b/src/ingester/persist/persisted_batch_event/append.rs index 010e7d1c..ceda96e3 100644 --- a/src/ingester/persist/persisted_batch_event/append.rs +++ b/src/ingester/persist/persisted_batch_event/append.rs @@ -24,7 +24,7 @@ pub async fn persist_batch_append_event( .saturating_sub(batch_append_event.old_next_index) as usize; let current_next_index = - get_tree_next_index(txn, &batch_append_event.merkle_tree_pubkey.to_vec()).await?; + get_tree_next_index(txn, batch_append_event.merkle_tree_pubkey.as_ref()).await?; // If old_next_index doesn't match current state, check if already processed if batch_append_event.old_next_index != current_next_index { @@ -53,7 +53,7 @@ pub async fn persist_batch_append_event( let accounts = fetch_accounts_to_append( txn, - &batch_append_event.merkle_tree_pubkey.to_vec(), + batch_append_event.merkle_tree_pubkey.as_ref(), batch_append_event.old_next_index as i64, batch_append_event.new_next_index as i64, ) diff --git a/src/ingester/persist/persisted_batch_event/mod.rs b/src/ingester/persist/persisted_batch_event/mod.rs index 6e635cb8..f95e5631 100644 --- a/src/ingester/persist/persisted_batch_event/mod.rs +++ b/src/ingester/persist/persisted_batch_event/mod.rs @@ -11,7 +11,7 @@ use log::debug; use sea_orm::DatabaseTransaction; use solana_pubkey::Pubkey; -use self::address::persist_batch_address_append_event; +use self::address::{cleanup_stale_address_queue_entries, persist_batch_address_append_event}; use self::append::persist_batch_append_event; use self::helpers::{deduplicate_events, persist_leaf_nodes_chunked, ZKP_BATCH_SIZE}; use self::nullify::persist_batch_nullify_event; @@ -19,7 +19,7 @@ use self::sequence::should_process_event; /// We need to find the events of the same tree: /// - order them by sequence number and execute them in order -/// HashMap> +/// HashMap> /// - execute a single function call to persist all changed nodes pub async fn persist_batch_events( txn: &DatabaseTransaction, @@ -74,6 +74,10 @@ pub async fn persist_batch_events( "Skipping already processed event with sequence {}", _event_seq ); + if let MerkleTreeEvent::BatchAddressAppend(batch_event) = event { + let queue_end = (batch_event.new_next_index as i64) - 1; + cleanup_stale_address_queue_entries(txn, batch_event, queue_end).await?; + } continue; } diff --git a/src/ingester/persist/persisted_batch_event/nullify.rs b/src/ingester/persist/persisted_batch_event/nullify.rs index 215fa631..8df56eef 100644 --- a/src/ingester/persist/persisted_batch_event/nullify.rs +++ b/src/ingester/persist/persisted_batch_event/nullify.rs @@ -17,7 +17,7 @@ use super::sequence::update_root_sequence; /// Persists a batch nullify event. /// 1. Create leaf nodes with nullifier as leaf. /// 2. Mark elements as nullified in tree -/// and remove them from the database nullifier queue. +/// and remove them from the database nullifier queue. pub async fn persist_batch_nullify_event( txn: &DatabaseTransaction, batch_nullify_event: &BatchEvent, @@ -38,7 +38,7 @@ pub async fn persist_batch_nullify_event( // Count accounts that are spent but not yet nullified in tree let queue_count = count_accounts_ready_to_nullify( txn, - &batch_nullify_event.merkle_tree_pubkey.to_vec(), + batch_nullify_event.merkle_tree_pubkey.as_ref(), queue_start, queue_end, ) @@ -56,7 +56,7 @@ pub async fn persist_batch_nullify_event( // Check if this is a re-indexing scenario (accounts already nullified) let already_processed = check_nullify_already_processed( txn, - &batch_nullify_event.merkle_tree_pubkey.to_vec(), + batch_nullify_event.merkle_tree_pubkey.as_ref(), queue_start, queue_end, ) @@ -90,7 +90,7 @@ pub async fn persist_batch_nullify_event( // Partial accounts found - gather more info for error message let in_queue_count = count_nullify_accounts_in_output_queue( txn, - &batch_nullify_event.merkle_tree_pubkey.to_vec(), + batch_nullify_event.merkle_tree_pubkey.as_ref(), queue_start, queue_end, ) @@ -112,7 +112,7 @@ pub async fn persist_batch_nullify_event( let accounts = fetch_accounts_to_nullify( txn, - &batch_nullify_event.merkle_tree_pubkey.to_vec(), + batch_nullify_event.merkle_tree_pubkey.as_ref(), queue_start, queue_end, ) diff --git a/src/ingester/persist/persisted_indexed_merkle_tree.rs b/src/ingester/persist/persisted_indexed_merkle_tree.rs index c2874b09..da095047 100644 --- a/src/ingester/persist/persisted_indexed_merkle_tree.rs +++ b/src/ingester/persist/persisted_indexed_merkle_tree.rs @@ -235,13 +235,9 @@ pub async fn persist_indexed_tree_updates( .iter() .map(|x| { Ok(LeafNode { - tree: SerializablePubkey::try_from(x.tree).map_err(|e| { - IngesterError::DatabaseError(format!("Failed to serialize pubkey: {}", e)) - })?, + tree: SerializablePubkey::from(x.tree), leaf_index: x.leaf.index as u32, - hash: Hash::try_from(x.hash).map_err(|e| { - IngesterError::DatabaseError(format!("Failed to serialize hash: {}", e)) - })?, + hash: Hash::from(x.hash), seq: Option::from(x.seq as u32), }) }) diff --git a/src/ingester/persist/persisted_state_tree.rs b/src/ingester/persist/persisted_state_tree.rs index 6e65fb6f..d3e0ed2f 100644 --- a/src/ingester/persist/persisted_state_tree.rs +++ b/src/ingester/persist/persisted_state_tree.rs @@ -102,7 +102,8 @@ where for (tree, index) in leaf_nodes_locations.iter() { result.entry((tree.clone(), *index)).or_insert_with(|| { let tree_height_with_level = tree_height + 1; - let model = state_trees::Model { + + state_trees::Model { tree: tree.clone(), level: get_level_by_node_index(*index, tree_height_with_level), node_idx: *index, @@ -111,8 +112,7 @@ where .to_vec(), leaf_idx: None, seq: None, - }; - model + } }); } } diff --git a/src/ingester/persist/spend.rs b/src/ingester/persist/spend.rs index 3a377d69..5ae46b9c 100644 --- a/src/ingester/persist/spend.rs +++ b/src/ingester/persist/spend.rs @@ -10,7 +10,7 @@ use sea_orm::QueryFilter; use sea_orm::{ColumnTrait, ConnectionTrait, DatabaseTransaction, EntityTrait, QueryTrait}; /// 1. Mark the input accounts as spent. -/// (From both V1 and V2 (batched) trees) +/// (From both V1 and V2 (batched) trees) /// 2. Update account compressed sol balances. /// 3. Update compressed token account balances. pub async fn spend_input_accounts( diff --git a/src/ingester/startup_cleanup.rs b/src/ingester/startup_cleanup.rs new file mode 100644 index 00000000..ceabdede --- /dev/null +++ b/src/ingester/startup_cleanup.rs @@ -0,0 +1,138 @@ +use crate::dao::generated::{address_queues, indexed_trees, tree_metadata}; +use light_compressed_account::TreeType; +use log::{debug, info}; +use sea_orm::{ + ColumnTrait, DatabaseConnection, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, +}; + +/// Cleans up stale address queue entries on startup. +/// +/// For each AddressV2 tree: +/// 1. Get the current next_index from indexed_trees (MAX(leaf_index) + 1) +/// 2. Delete address_queue entries where queue_index < next_index - 1 +/// +/// This handles cases where photon was restarted or re-indexed and stale +/// queue entries remain from batches that were already processed. +pub async fn cleanup_stale_address_queues( + db: &DatabaseConnection, +) -> Result<(), Box> { + info!("Starting address queue cleanup..."); + + let address_trees = tree_metadata::Entity::find() + .filter(tree_metadata::Column::TreeType.eq(TreeType::AddressV2 as i32)) + .all(db) + .await?; + + if address_trees.is_empty() { + debug!("No AddressV2 trees found, skipping cleanup"); + return Ok(()); + } + + let mut total_deleted = 0u64; + + for tree in address_trees { + let tree_pubkey = &tree.tree_pubkey; + + // Get current next_index from indexed_trees (MAX(leaf_index) + 1) + let current_next_index = indexed_trees::Entity::find() + .filter(indexed_trees::Column::Tree.eq(tree_pubkey.clone())) + .order_by_desc(indexed_trees::Column::LeafIndex) + .one(db) + .await? + .map(|t| t.leaf_index + 1) + .unwrap_or(1); + + // Address queue indices are 0-based, tree indices are 1-based + // So queue entries with queue_index < current_next_index - 1 are stale + let queue_threshold = current_next_index - 1; + + if queue_threshold <= 0 { + debug!( + "Tree {}: next_index={}, no cleanup needed", + bs58::encode(tree_pubkey).into_string(), + current_next_index + ); + continue; + } + + let stale_count = address_queues::Entity::find() + .filter( + address_queues::Column::Tree + .eq(tree_pubkey.clone()) + .and(address_queues::Column::QueueIndex.lt(queue_threshold)), + ) + .count(db) + .await?; + + if stale_count == 0 { + debug!( + "Tree {}: next_index={}, no stale entries", + bs58::encode(tree_pubkey).into_string(), + current_next_index + ); + continue; + } + + let delete_result = address_queues::Entity::delete_many() + .filter( + address_queues::Column::Tree + .eq(tree_pubkey.clone()) + .and(address_queues::Column::QueueIndex.lt(queue_threshold)), + ) + .exec(db) + .await?; + + let deleted = delete_result.rows_affected; + total_deleted += deleted; + + info!( + "Tree {}: deleted {} stale queue entries (queue_index < {}, next_index={})", + bs58::encode(tree_pubkey).into_string(), + deleted, + queue_threshold, + current_next_index + ); + } + + if total_deleted > 0 { + info!( + "Address queue cleanup complete: deleted {} total stale entries", + total_deleted + ); + } else { + info!("Address queue cleanup complete: no stale entries found"); + } + + let duplicate_deleted = cleanup_duplicate_addresses(db).await?; + if duplicate_deleted > 0 { + info!( + "Duplicate address cleanup: deleted {} addresses already in indexed_trees", + duplicate_deleted + ); + } + + Ok(()) +} + +/// Cleans up address_queues entries where the address already exists in indexed_trees. +async fn cleanup_duplicate_addresses( + db: &DatabaseConnection, +) -> Result> { + use sea_orm::{ConnectionTrait, DatabaseBackend, Statement}; + + info!("Checking for duplicate addresses in queue..."); + + let backend = db.get_database_backend(); + let sql = match backend { + DatabaseBackend::Postgres | DatabaseBackend::Sqlite => { + "DELETE FROM address_queues WHERE address IN (SELECT value FROM indexed_trees)" + } + _ => return Err("Unsupported database backend".into()), + }; + + let result = db + .execute(Statement::from_string(backend, sql.to_string())) + .await?; + + Ok(result.rows_affected()) +} diff --git a/src/ingester/typedefs/block_info.rs b/src/ingester/typedefs/block_info.rs index c2faf6c5..4f5dc50f 100644 --- a/src/ingester/typedefs/block_info.rs +++ b/src/ingester/typedefs/block_info.rs @@ -209,12 +209,12 @@ pub fn parse_instruction_groups( .instructions() .iter() .map(|ix| { - let program_id = accounts[ix.program_id_index as usize].clone(); + let program_id = accounts[ix.program_id_index as usize]; let data = ix.data.clone(); let instruction_accounts: Vec = ix .accounts .iter() - .map(|account_index| accounts[*account_index as usize].clone()) + .map(|account_index| accounts[*account_index as usize]) .collect(); InstructionGroup { @@ -236,14 +236,14 @@ pub fn parse_instruction_groups( match ui_instruction { UiInstruction::Compiled(ui_compiled_instruction) => { let program_id = - accounts[ui_compiled_instruction.program_id_index as usize].clone(); + accounts[ui_compiled_instruction.program_id_index as usize]; let data = bs58::decode(&ui_compiled_instruction.data) .into_vec() .map_err(|e| IngesterError::ParserError(e.to_string()))?; let instruction_accounts: Vec = ui_compiled_instruction .accounts .iter() - .map(|account_index| accounts[*account_index as usize].clone()) + .map(|account_index| accounts[*account_index as usize]) .collect(); instruction_groups[index as usize] .inner_instructions diff --git a/src/main.rs b/src/main.rs index 2b028eef..3b5e031a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ use async_stream::stream; use clap::Parser; use futures::pin_mut; use jsonrpsee::server::ServerHandle; -use log::{error, info}; +use log::{error, info, warn}; use photon_indexer::api::{self, api::PhotonApi}; use photon_indexer::common::{ @@ -73,6 +73,10 @@ struct Args { #[arg(long, default_value = "http://127.0.0.1:3001")] prover_url: String, + /// API key for the Light Prover service + #[arg(long)] + prover_api_key: Option, + /// Snasphot directory #[arg(long, default_value = None)] snapshot_dir: Option, @@ -107,16 +111,25 @@ struct Args { /// If provided, metrics will be sent to the specified statsd server. #[arg(long, default_value = None)] metrics_endpoint: Option, + + /// Max concurrent HTTP connections for the JSON-RPC server (jsonrpsee). + /// Connections beyond this limit receive HTTP 429. + #[arg(long, default_value_t = 1024)] + max_http_connections: u32, } async fn start_api_server( db: Arc, rpc_client: Arc, prover_url: String, + prover_api_key: Option, api_port: u16, + max_http_connections: u32, ) -> ServerHandle { - let api = PhotonApi::new(db, rpc_client, prover_url); - api::rpc_server::run_server(api, api_port).await.unwrap() + let api = PhotonApi::new(db, rpc_client, prover_url, prover_api_key); + api::rpc_server::run_server(api, api_port, max_http_connections) + .await + .unwrap() } async fn setup_temporary_sqlite_database_pool(max_connections: u32) -> SqlitePool { @@ -219,6 +232,14 @@ async fn main() { info!("Running migrations..."); Migrator::up(db_conn.as_ref(), None).await.unwrap(); } + + if let Err(e) = + photon_indexer::ingester::startup_cleanup::cleanup_stale_address_queues(db_conn.as_ref()) + .await + { + error!("Failed to cleanup stale address queues: {}", e); + } + let is_rpc_node_local = args.rpc_url.contains("127.0.0.1"); let rpc_client = get_rpc_client(&args.rpc_url); @@ -295,6 +316,19 @@ async fn main() { } false => { info!("Starting indexer..."); + + info!("Syncing tree metadata..."); + if let Err(e) = photon_indexer::monitor::tree_metadata_sync::sync_tree_metadata( + rpc_client.as_ref(), + db_conn.as_ref(), + ) + .await + { + warn!("Failed to sync tree metadata on startup: {}. Will retry in background monitor.", e); + } else { + info!("Tree metadata sync completed successfully"); + } + // For localnet we can safely use a large batch size to speed up indexing. let max_concurrent_block_fetches = match args.max_concurrent_block_fetches { Some(max_concurrent_block_fetches) => max_concurrent_block_fetches, @@ -348,7 +382,10 @@ async fn main() { } }; - info!("Starting API server with port {}...", args.port); + info!( + "Starting API server with port {}, max_http_connections={}...", + args.port, args.max_http_connections + ); let api_handler = if args.disable_api { None } else { @@ -357,7 +394,9 @@ async fn main() { db_conn.clone(), rpc_client.clone(), args.prover_url, + args.prover_api_key, args.port, + args.max_http_connections, ) .await, ) diff --git a/src/migration/migrations/custom/custom20250211_000002_solayer2.rs b/src/migration/migrations/custom/custom20250211_000002_solayer2.rs index f66725da..e517700c 100644 --- a/src/migration/migrations/custom/custom20250211_000002_solayer2.rs +++ b/src/migration/migrations/custom/custom20250211_000002_solayer2.rs @@ -8,7 +8,7 @@ use crate::migration::model::table::Accounts; #[derive(DeriveMigrationName)] pub struct Migration; -async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { manager .get_connection() .execute(Statement::from_string( @@ -22,7 +22,7 @@ async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), D #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - let solayer_accounts = vec![ + let solayer_accounts = [ "ARDPkhymCbfdan375FCgPnBJQvUfHeb7nHVdBfwWSxrp", "2sYfW81EENCMe415CPhE2XzBA5iQf4TXRs31W1KP63YT", ]; diff --git a/src/migration/migrations/custom/custom20252201_000001_init.rs b/src/migration/migrations/custom/custom20252201_000001_init.rs index d09d7859..3579a58d 100644 --- a/src/migration/migrations/custom/custom20252201_000001_init.rs +++ b/src/migration/migrations/custom/custom20252201_000001_init.rs @@ -9,7 +9,7 @@ use crate::migration::model::table::Accounts; #[derive(DeriveMigrationName)] pub struct Migration; -async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { manager .get_connection() .execute(Statement::from_string( @@ -23,7 +23,7 @@ async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), D #[async_trait::async_trait] impl MigrationTrait for Migration { async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - let solayer_accounts = vec![ + let solayer_accounts = [ "S1ay5sk6FVkvsNFZShMw2YK3nfgJZ8tpBBGuHWDZ266", "2sYfW81EENCMe415CPhE2XzBA5iQf4TXRs31W1KP63YT", ]; diff --git a/src/migration/migrations/standard/m20220101_000001_init.rs b/src/migration/migrations/standard/m20220101_000001_init.rs index 1f5fa7ff..1b09ace6 100644 --- a/src/migration/migrations/standard/m20220101_000001_init.rs +++ b/src/migration/migrations/standard/m20220101_000001_init.rs @@ -12,7 +12,7 @@ use super::super::super::model::table::{ #[derive(DeriveMigrationName)] pub struct Migration; -async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { manager .get_connection() .execute(Statement::from_string( diff --git a/src/migration/migrations/standard/m20240914_000005_init.rs b/src/migration/migrations/standard/m20240914_000005_init.rs index ff552875..bc136511 100644 --- a/src/migration/migrations/standard/m20240914_000005_init.rs +++ b/src/migration/migrations/standard/m20240914_000005_init.rs @@ -6,7 +6,7 @@ use crate::migration::model::table::AccountTransactions; #[derive(DeriveMigrationName)] pub struct Migration; -async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { manager .get_connection() .execute(Statement::from_string( diff --git a/src/migration/migrations/standard/m20241008_000006_init.rs b/src/migration/migrations/standard/m20241008_000006_init.rs index 5b13e74c..888ad799 100644 --- a/src/migration/migrations/standard/m20241008_000006_init.rs +++ b/src/migration/migrations/standard/m20241008_000006_init.rs @@ -6,7 +6,7 @@ use crate::migration::model::table::TokenOwnerBalances; #[derive(DeriveMigrationName)] pub struct Migration; -async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { manager .get_connection() .execute(Statement::from_string( diff --git a/src/migration/migrations/standard/m20250206_000007_init.rs b/src/migration/migrations/standard/m20250206_000007_init.rs index ca777af6..060d957d 100644 --- a/src/migration/migrations/standard/m20250206_000007_init.rs +++ b/src/migration/migrations/standard/m20250206_000007_init.rs @@ -7,7 +7,7 @@ use sea_orm_migration::{ #[derive(DeriveMigrationName)] pub struct Migration; -async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { manager .get_connection() .execute(Statement::from_string( diff --git a/src/migration/migrations/standard/m20251021_000001_optimize_nullifier_queue_index.rs b/src/migration/migrations/standard/m20251021_000001_optimize_nullifier_queue_index.rs index 8ccc669c..10ccdc3e 100644 --- a/src/migration/migrations/standard/m20251021_000001_optimize_nullifier_queue_index.rs +++ b/src/migration/migrations/standard/m20251021_000001_optimize_nullifier_queue_index.rs @@ -4,7 +4,7 @@ use sea_orm_migration::prelude::*; #[derive(DeriveMigrationName)] pub struct Migration; -async fn execute_sql<'a>(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { manager .get_connection() .execute(Statement::from_string( diff --git a/src/migration/migrations/standard/m20260127_000001_add_onchain_pubkey.rs b/src/migration/migrations/standard/m20260127_000001_add_onchain_pubkey.rs new file mode 100644 index 00000000..059151c9 --- /dev/null +++ b/src/migration/migrations/standard/m20260127_000001_add_onchain_pubkey.rs @@ -0,0 +1,57 @@ +use sea_orm_migration::{ + prelude::*, + sea_orm::{ConnectionTrait, Statement}, +}; + +use super::super::super::model::table::Accounts; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +async fn execute_sql(manager: &SchemaManager<'_>, sql: &str) -> Result<(), DbErr> { + manager + .get_connection() + .execute(Statement::from_string( + manager.get_database_backend(), + sql.to_string(), + )) + .await?; + Ok(()) +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Accounts::Table) + .add_column(ColumnDef::new(Accounts::OnchainPubkey).binary().null()) + .to_owned(), + ) + .await?; + + execute_sql( + manager, + "CREATE INDEX accounts_onchain_pubkey_idx ON accounts (onchain_pubkey) WHERE NOT spent AND onchain_pubkey IS NOT NULL;", + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + execute_sql(manager, "DROP INDEX IF EXISTS accounts_onchain_pubkey_idx;").await?; + + manager + .alter_table( + Table::alter() + .table(Accounts::Table) + .drop_column(Accounts::OnchainPubkey) + .to_owned(), + ) + .await?; + + Ok(()) + } +} diff --git a/src/migration/migrations/standard/m20260201_000002_add_ata_owner.rs b/src/migration/migrations/standard/m20260201_000002_add_ata_owner.rs new file mode 100644 index 00000000..7a93ea2e --- /dev/null +++ b/src/migration/migrations/standard/m20260201_000002_add_ata_owner.rs @@ -0,0 +1,35 @@ +use sea_orm_migration::prelude::*; + +use super::super::super::model::table::TokenAccounts; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(TokenAccounts::Table) + .add_column(ColumnDef::new(TokenAccounts::AtaOwner).binary().null()) + .to_owned(), + ) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(TokenAccounts::Table) + .drop_column(TokenAccounts::AtaOwner) + .to_owned(), + ) + .await?; + + Ok(()) + } +} diff --git a/src/migration/migrations/standard/m20260210_000002_add_ata_owner_index.rs b/src/migration/migrations/standard/m20260210_000002_add_ata_owner_index.rs new file mode 100644 index 00000000..6eec4ab8 --- /dev/null +++ b/src/migration/migrations/standard/m20260210_000002_add_ata_owner_index.rs @@ -0,0 +1,56 @@ +use sea_orm_migration::{ + prelude::*, + sea_orm::{ConnectionTrait, DatabaseBackend, Statement}, +}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +const ATA_OWNER_INDEX_NAME: &str = "token_accounts_spent_ata_owner_idx"; + +fn create_index_sql(backend: DatabaseBackend) -> Result { + match backend { + DatabaseBackend::Postgres => Ok(format!( + "CREATE INDEX IF NOT EXISTS {ATA_OWNER_INDEX_NAME} \ + ON token_accounts (spent, ata_owner) \ + WHERE ata_owner IS NOT NULL;" + )), + DatabaseBackend::Sqlite => Ok(format!( + "CREATE INDEX IF NOT EXISTS {ATA_OWNER_INDEX_NAME} \ + ON token_accounts (spent, ata_owner);" + )), + _ => Err(DbErr::Custom("Unsupported database backend".to_string())), + } +} + +fn drop_index_sql(backend: DatabaseBackend) -> Result { + match backend { + DatabaseBackend::Postgres | DatabaseBackend::Sqlite => { + Ok(format!("DROP INDEX IF EXISTS {ATA_OWNER_INDEX_NAME};")) + } + _ => Err(DbErr::Custom("Unsupported database backend".to_string())), + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let backend = manager.get_database_backend(); + let sql = create_index_sql(backend)?; + manager + .get_connection() + .execute(Statement::from_string(backend, sql)) + .await?; + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let backend = manager.get_database_backend(); + let sql = drop_index_sql(backend)?; + manager + .get_connection() + .execute(Statement::from_string(backend, sql)) + .await?; + Ok(()) + } +} diff --git a/src/migration/migrations/standard/m20260220_000001_add_discriminator_v2.rs b/src/migration/migrations/standard/m20260220_000001_add_discriminator_v2.rs new file mode 100644 index 00000000..7adc61a9 --- /dev/null +++ b/src/migration/migrations/standard/m20260220_000001_add_discriminator_v2.rs @@ -0,0 +1,31 @@ +use sea_orm_migration::prelude::*; + +use super::super::super::model::table::Accounts; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Accounts::Table) + .add_column(ColumnDef::new(Accounts::DiscriminatorV2).binary().null()) + .to_owned(), + ) + .await + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + manager + .alter_table( + Table::alter() + .table(Accounts::Table) + .drop_column(Accounts::DiscriminatorV2) + .to_owned(), + ) + .await + } +} diff --git a/src/migration/migrations/standard/mod.rs b/src/migration/migrations/standard/mod.rs index c58450f7..53527423 100644 --- a/src/migration/migrations/standard/mod.rs +++ b/src/migration/migrations/standard/mod.rs @@ -14,7 +14,10 @@ pub mod m20250909_000001_add_queue_hash_chains; pub mod m20250910_000002_add_v2_queue_indexes; pub mod m20250923_000001_add_tree_metadata; pub mod m20251021_000001_optimize_nullifier_queue_index; - +pub mod m20260127_000001_add_onchain_pubkey; +pub mod m20260201_000002_add_ata_owner; +pub mod m20260210_000002_add_ata_owner_index; +pub mod m20260220_000001_add_discriminator_v2; pub fn get_standard_migrations() -> Vec> { vec![ Box::new(m20220101_000001_init::Migration), @@ -31,5 +34,9 @@ pub fn get_standard_migrations() -> Vec> { Box::new(m20250910_000002_add_v2_queue_indexes::Migration), Box::new(m20250923_000001_add_tree_metadata::Migration), Box::new(m20251021_000001_optimize_nullifier_queue_index::Migration), + Box::new(m20260127_000001_add_onchain_pubkey::Migration), + Box::new(m20260201_000002_add_ata_owner::Migration), + Box::new(m20260210_000002_add_ata_owner_index::Migration), + Box::new(m20260220_000001_add_discriminator_v2::Migration), ] } diff --git a/src/migration/model/table.rs b/src/migration/model/table.rs index 12b0c025..8c2ef0b4 100644 --- a/src/migration/model/table.rs +++ b/src/migration/model/table.rs @@ -16,6 +16,8 @@ pub enum Accounts { Table, Hash, Address, + OnchainPubkey, + DiscriminatorV2, Data, DataHash, Owner, @@ -45,6 +47,7 @@ pub enum TokenAccounts { Tlv, Spent, PrevSpent, + AtaOwner, } #[derive(Copy, Clone, Iden)] diff --git a/src/monitor/mod.rs b/src/monitor/mod.rs index b88b4107..91a5f266 100644 --- a/src/monitor/mod.rs +++ b/src/monitor/mod.rs @@ -5,7 +5,7 @@ pub mod v1_tree_accounts; use std::{ sync::{ - atomic::{AtomicU64, Ordering}, + atomic::{AtomicBool, AtomicU64, Ordering}, Arc, }, time::Duration, @@ -42,6 +42,15 @@ use std::mem; const CHUNK_SIZE: usize = 100; pub static LATEST_SLOT: Lazy> = Lazy::new(|| Arc::new(AtomicU64::new(0))); +static TREE_VALIDATION_IN_PROGRESS: AtomicBool = AtomicBool::new(false); + +struct TreeValidationGuard; + +impl Drop for TreeValidationGuard { + fn drop(&mut self) { + TREE_VALIDATION_IN_PROGRESS.store(false, Ordering::SeqCst); + } +} async fn fetch_last_indexed_slot_with_infinite_retry(db: &DatabaseConnection) -> u64 { loop { @@ -77,11 +86,7 @@ pub fn continously_monitor_photon( let latest_slot = LATEST_SLOT.load(Ordering::SeqCst); let last_indexed_slot = fetch_last_indexed_slot_with_infinite_retry(db.as_ref()).await; - let lag = if latest_slot > last_indexed_slot { - latest_slot - last_indexed_slot - } else { - 0 - }; + let lag = latest_slot.saturating_sub(last_indexed_slot); metric! { statsd_gauge!("indexing_lag", lag); } @@ -94,14 +99,20 @@ pub fn continously_monitor_photon( error!("Indexing lag is too high: {}", lag); } } else { - let db_clone = db.clone(); - let rpc_clone = rpc_client.clone(); + if TREE_VALIDATION_IN_PROGRESS + .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) + .is_ok() + { + let db_clone = db.clone(); + let rpc_clone = rpc_client.clone(); - tokio::spawn(async move { - let tree_roots = - load_db_tree_roots_with_infinite_retry(db_clone.as_ref()).await; - validate_tree_roots(rpc_clone.as_ref(), tree_roots).await; - }); + tokio::spawn(async move { + let _validation_guard = TreeValidationGuard; + let tree_roots = + load_db_tree_roots_with_infinite_retry(db_clone.as_ref()).await; + validate_tree_roots(rpc_clone.as_ref(), tree_roots).await; + }); + } // Spawn parallel verification tasks for each V2 tree let v2_trees = match queue_monitor::collect_v2_trees(db.as_ref()).await { @@ -142,7 +153,7 @@ pub fn continously_monitor_photon( } pub async fn update_latest_slot(rpc_client: &RpcClient) { - let slot = fetch_current_slot_with_infinite_retry(&rpc_client).await; + let slot = fetch_current_slot_with_infinite_retry(rpc_client).await; LATEST_SLOT.fetch_max(slot, Ordering::SeqCst); } diff --git a/src/monitor/queue_monitor.rs b/src/monitor/queue_monitor.rs index 81cceaf3..d53b6dd4 100644 --- a/src/monitor/queue_monitor.rs +++ b/src/monitor/queue_monitor.rs @@ -97,7 +97,7 @@ async fn verify_output_queue_hash_chains( batch_metadata.zkp_batch_size, currently_processing_batch_index, current_batch.get_num_inserted_zkps(), - current_batch.get_num_inserted_zkp_batch(), + current_batch.get_num_inserted_zkp_batch() > 0, ) .await } @@ -139,7 +139,7 @@ async fn verify_input_queue_hash_chains( queue_batches.zkp_batch_size, pending_batch_index, pending_batch.get_num_inserted_zkps(), - pending_batch.get_num_inserted_zkp_batch(), + pending_batch.get_num_inserted_zkp_batch() > 0, ) .await } @@ -185,11 +185,12 @@ async fn verify_address_queue_hash_chains( queue_batches.zkp_batch_size, pending_batch_index, current_batch.get_num_inserted_zkps(), - current_batch.get_num_inserted_zkp_batch(), + current_batch.get_num_inserted_zkp_batch() > 0, ) .await } +#[allow(clippy::too_many_arguments)] async fn verify_queue_hash_chains( db: &DatabaseConnection, queue_type: QueueType, @@ -199,23 +200,28 @@ async fn verify_queue_hash_chains( zkp_batch_size: u64, pending_batch_index: usize, num_inserted_zkps: u64, - num_inserted_in_current_zkp: u64, + has_partial_zkp_batch: bool, ) -> Result<(), Vec> { let mut divergences = Vec::new(); - if num_inserted_in_current_zkp > 0 && num_inserted_in_current_zkp < zkp_batch_size { + let on_chain_batch_hash_chains = &on_chain_hash_chains[pending_batch_index]; + let total_on_chain_zkps = on_chain_batch_hash_chains.len() as u64; + if num_inserted_zkps >= total_on_chain_zkps { debug!( - "Skipping ZKP verification for tree {} type {:?} - incomplete batch: {}/{} elements", - tree_pubkey, queue_type, num_inserted_in_current_zkp, zkp_batch_size + "Tree {} type {:?}: All {} hash chains already inserted, skipping validation", + tree_pubkey, queue_type, total_on_chain_zkps ); return Ok(()); } - let on_chain_batch_hash_chains = &on_chain_hash_chains[pending_batch_index]; - let total_on_chain_zkps = on_chain_batch_hash_chains.len() as u64; - if num_inserted_zkps >= total_on_chain_zkps { + let chains_to_check = if has_partial_zkp_batch { + total_on_chain_zkps.saturating_sub(1) + } else { + total_on_chain_zkps + }; + if num_inserted_zkps >= chains_to_check { debug!( - "Tree {} type {:?}: All {} hash chains already inserted, skipping validation", + "Tree {} type {:?}: {} hash chains, skipping partial batch validation", tree_pubkey, queue_type, total_on_chain_zkps ); return Ok(()); @@ -224,7 +230,8 @@ async fn verify_queue_hash_chains( let on_chain_chains: Vec<[u8; 32]> = on_chain_batch_hash_chains .iter() .skip(num_inserted_zkps as usize) - .map(|h| *h) + .take((chains_to_check - num_inserted_zkps) as usize) + .copied() .collect(); if on_chain_chains.is_empty() { @@ -543,9 +550,9 @@ pub fn log_divergence(divergence: &HashChainDivergence) { ); error!( " Expected: {}", - hex::encode(&divergence.expected_hash_chain) + hex::encode(divergence.expected_hash_chain) ); - error!(" On-chain: {}", hex::encode(&divergence.actual_hash_chain)); + error!(" On-chain: {}", hex::encode(divergence.actual_hash_chain)); } pub async fn verify_single_queue( diff --git a/src/monitor/tree_metadata_sync.rs b/src/monitor/tree_metadata_sync.rs index 4e12fcaa..dbbd8ae8 100644 --- a/src/monitor/tree_metadata_sync.rs +++ b/src/monitor/tree_metadata_sync.rs @@ -96,6 +96,10 @@ where return Ok(false); } + debug!( + "Parsed as V1 state tree: {} (queue={}, owner={})", + pubkey, data.queue_pubkey, data.owner + ); upsert_tree_metadata(db, pubkey, TreeType::StateV1, &data, slot).await?; info!( "Synced V1 state tree {} with height {}, root_history_capacity {}, seq {}, next_idx {}", @@ -127,7 +131,7 @@ where let data = TreeAccountData { queue_pubkey: Pubkey::new_from_array(metadata.metadata.associated_queue.to_bytes()), root_history_capacity: metadata.root_history_capacity as usize, - height: tree_account.height as u32, + height: tree_account.height, sequence_number: metadata.sequence_number, next_index: metadata.next_index, owner: Pubkey::new_from_array(metadata.metadata.access_metadata.owner.to_bytes()), @@ -141,6 +145,10 @@ where return Ok(false); } + debug!( + "Parsed as V2 state tree: {} (queue={}, owner={})", + pubkey, data.queue_pubkey, data.owner + ); upsert_tree_metadata(db, pubkey, TreeType::StateV2, &data, slot).await?; info!( @@ -157,7 +165,7 @@ where let data = TreeAccountData { queue_pubkey: pubkey, // For V2 address trees, queue == tree root_history_capacity: metadata.root_history_capacity as usize, - height: tree_account.height as u32, + height: tree_account.height, sequence_number: metadata.sequence_number, next_index: metadata.next_index, owner: Pubkey::new_from_array(metadata.metadata.access_metadata.owner.to_bytes()), @@ -253,6 +261,8 @@ where .on_conflict( sea_orm::sea_query::OnConflict::column(tree_metadata::Column::TreePubkey) .update_columns([ + tree_metadata::Column::QueuePubkey, + tree_metadata::Column::TreeType, tree_metadata::Column::SequenceNumber, tree_metadata::Column::NextIndex, tree_metadata::Column::LastSyncedSlot, diff --git a/src/openapi/mod.rs b/src/openapi/mod.rs index c9498dec..5bfadf77 100644 --- a/src/openapi/mod.rs +++ b/src/openapi/mod.rs @@ -301,7 +301,8 @@ fn fix_examples_for_allOf_references(schema: RefOr) -> RefOr { } _ => schema, }), - Schema::AllOf(ref all_of) => all_of.items[0].clone(), + Schema::AllOf(ref all_of) if all_of.items.len() == 1 => all_of.items[0].clone(), + Schema::AllOf(_) => RefOr::T(schema), _ => RefOr::T(schema), }, RefOr::Ref(_) => schema, @@ -343,7 +344,7 @@ fn find_all_components(schema: RefOr) -> HashSet { ref_location .ref_location .split('/') - .last() + .next_back() .unwrap() .to_string(), ); diff --git a/src/openapi/specs/api.yaml b/src/openapi/specs/api.yaml index f857ec24..57b51647 100644 --- a/src/openapi/specs/api.yaml +++ b/src/openapi/specs/api.yaml @@ -4,12 +4,12 @@ info: description: Solana indexer for general compression license: name: Apache-2.0 - version: 0.50.0 + version: 0.51.2 servers: - url: https://devnet.helius-rpc.com?api-key= paths: - /getBatchAddressUpdateInfo: - summary: getBatchAddressUpdateInfo + /getAccountInterface: + summary: getAccountInterface post: requestBody: content: @@ -36,19 +36,15 @@ paths: type: string description: The name of the method to invoke. enum: - - getBatchAddressUpdateInfo + - getAccountInterface params: type: object + description: Request for getAccountInterface required: - - tree - - batchSize + - address properties: - batchSize: - type: integer - format: uint16 - minimum: 0 - tree: - $ref: '#/components/schemas/Hash' + address: + $ref: '#/components/schemas/SerializablePubkey' additionalProperties: false required: true responses: @@ -81,33 +77,14 @@ paths: - '2.0' result: type: object + description: Response for getAccountInterface required: - context - - startIndex - - addresses - - nonInclusionProofs - - subtrees properties: - addresses: - type: array - items: - $ref: '#/components/schemas/AddressSeq' context: $ref: '#/components/schemas/Context' - nonInclusionProofs: - type: array - items: - $ref: '#/components/schemas/MerkleContextWithNewAddressProof' - startIndex: - type: integer - format: uint64 - minimum: 0 - subtrees: - type: array - items: - type: string - format: binary - additionalProperties: false + value: + $ref: '#/components/schemas/AccountInterface' '429': description: Exceeded rate limit. content: @@ -3004,6 +2981,128 @@ paths: type: string jsonrpc: type: string + /getMultipleAccountInterfaces: + summary: getMultipleAccountInterfaces + post: + requestBody: + content: + application/json: + schema: + type: object + required: + - jsonrpc + - id + - method + - params + properties: + id: + type: string + description: An ID to identify the request. + enum: + - test-account + jsonrpc: + type: string + description: The version of the JSON-RPC protocol. + enum: + - '2.0' + method: + type: string + description: The name of the method to invoke. + enum: + - getMultipleAccountInterfaces + params: + type: object + description: Request for getMultipleAccountInterfaces + required: + - addresses + properties: + addresses: + type: array + items: + $ref: '#/components/schemas/SerializablePubkey' + description: List of account addresses to look up (max 100) + additionalProperties: false + required: true + responses: + '200': + description: '' + content: + application/json: + schema: + type: object + required: + - jsonrpc + - id + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + description: An ID to identify the response. + enum: + - test-account + jsonrpc: + type: string + description: The version of the JSON-RPC protocol. + enum: + - '2.0' + result: + type: object + description: Response for getMultipleAccountInterfaces + required: + - context + - value + properties: + context: + $ref: '#/components/schemas/Context' + value: + type: array + items: + allOf: + - $ref: '#/components/schemas/AccountInterface' + nullable: true + description: List of account results (Some for found accounts, None for not found) + '429': + description: Exceeded rate limit. + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + jsonrpc: + type: string + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + jsonrpc: + type: string /getMultipleCompressedAccountProofs: summary: getMultipleCompressedAccountProofs post: @@ -3261,8 +3360,8 @@ paths: default: addresses: null hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh + - 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs + - 1117mWrzzrZr312ebPDHu8tbfMwFNvCvMbr6WepCNG properties: addresses: type: array @@ -3278,8 +3377,8 @@ paths: example: addresses: null hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh + - 11157t3sqMV725NVRLrVQbAu98Jjfk1uCKehJnXXQs + - 1117mWrzzrZr312ebPDHu8tbfMwFNvCvMbr6WepCNG required: true responses: '200': @@ -3391,8 +3490,8 @@ paths: default: addresses: null hashes: - - 11111112D1oxKts8YPdTJRG5FzxTNpMtWmq8hkVx3 - - 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP + - 1119DWteoLSdjvrT6g6L8C2PfDD2faiTQUpsjY2RiF + - 111BuZ6b86gm7XhxjvTakhRvxSMjXp2GqgifkNUmDK properties: addresses: type: array @@ -3408,8 +3507,8 @@ paths: example: addresses: null hashes: - - 11111112D1oxKts8YPdTJRG5FzxTNpMtWmq8hkVx3 - - 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP + - 1119DWteoLSdjvrT6g6L8C2PfDD2faiTQUpsjY2RiF + - 111BuZ6b86gm7XhxjvTakhRvxSMjXp2GqgifkNUmDK required: true responses: '200': @@ -3740,28 +3839,20 @@ paths: required: - tree properties: - tree: - $ref: '#/components/schemas/Hash' - outputQueueStartIndex: - type: integer - format: uint64 - nullable: true - minimum: 0 - outputQueueLimit: - type: integer - format: uint16 + addressQueue: + allOf: + - $ref: '#/components/schemas/QueueRequest' nullable: true - minimum: 0 - inputQueueStartIndex: - type: integer - format: uint64 + inputQueue: + allOf: + - $ref: '#/components/schemas/QueueRequest' nullable: true - minimum: 0 - inputQueueLimit: - type: integer - format: uint16 + outputQueue: + allOf: + - $ref: '#/components/schemas/QueueRequest' nullable: true - minimum: 0 + tree: + $ref: '#/components/schemas/Hash' additionalProperties: false required: true responses: @@ -3797,29 +3888,130 @@ paths: required: - context properties: + addressQueue: + $ref: '#/components/schemas/AddressQueueData' context: $ref: '#/components/schemas/Context' - outputQueueElements: - type: array - nullable: true - items: - $ref: '#/components/schemas/GetQueueElementsResponseValue' - outputQueueIndex: + stateQueue: + $ref: '#/components/schemas/StateQueueData' + additionalProperties: false + '429': + description: Exceeded rate limit. + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: type: integer - format: uint64 - nullable: true - minimum: 0 - inputQueueElements: + message: + type: string + id: + type: string + jsonrpc: + type: string + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + jsonrpc: + type: string + /getQueueInfo: + summary: getQueueInfo + post: + requestBody: + content: + application/json: + schema: + type: object + required: + - jsonrpc + - id + - method + - params + properties: + id: + type: string + description: An ID to identify the request. + enum: + - test-account + jsonrpc: + type: string + description: The version of the JSON-RPC protocol. + enum: + - '2.0' + method: + type: string + description: The name of the method to invoke. + enum: + - getQueueInfo + params: + type: object + properties: + trees: + type: array + items: + type: string + nullable: true + additionalProperties: false + required: true + responses: + '200': + description: '' + content: + application/json: + schema: + type: object + required: + - jsonrpc + - id + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + description: An ID to identify the response. + enum: + - test-account + jsonrpc: + type: string + description: The version of the JSON-RPC protocol. + enum: + - '2.0' + result: + type: object + required: + - queues + - slot + properties: + queues: type: array - nullable: true items: - $ref: '#/components/schemas/GetQueueElementsResponseValue' - inputQueueIndex: + $ref: '#/components/schemas/QueueInfo' + slot: type: integer format: uint64 - nullable: true minimum: 0 - additionalProperties: false '429': description: Exceeded rate limit. content: @@ -4417,6 +4609,23 @@ components: discriminator: $ref: '#/components/schemas/UnsignedInteger' additionalProperties: false + AccountInterface: + type: object + description: Unified account interface — works for both on-chain and compressed accounts + required: + - key + - account + properties: + account: + $ref: '#/components/schemas/SolanaAccountData' + cold: + type: array + items: + $ref: '#/components/schemas/AccountV2' + description: Compressed accounts associated with this pubkey + nullable: true + key: + $ref: '#/components/schemas/SerializablePubkey' AccountList: type: object required: @@ -4440,6 +4649,27 @@ components: allOf: - $ref: '#/components/schemas/AccountV2' nullable: true + AccountProofInputs: + type: object + required: + - hash + - root + - rootIndex + - leafIndex + - merkleContext + properties: + hash: + type: string + leafIndex: + type: integer + format: uint64 + minimum: 0 + merkleContext: + $ref: '#/components/schemas/MerkleContextV2' + root: + type: string + rootIndex: + $ref: '#/components/schemas/RootIndex' AccountState: type: string enum: @@ -4512,18 +4742,93 @@ components: type: array items: $ref: '#/components/schemas/AddressWithTree' - AddressSeq: + AddressProofInputs: type: object required: - address - - seq + - root + - rootIndex + - merkleContext properties: address: - $ref: '#/components/schemas/SerializablePubkey' - seq: + type: string + merkleContext: + $ref: '#/components/schemas/MerkleContextV2' + root: + type: string + rootIndex: + type: integer + format: uint16 + minimum: 0 + AddressQueueData: + type: object + required: + - addresses + - queueIndices + - nodes + - lowElementIndices + - lowElementValues + - lowElementNextIndices + - lowElementNextValues + - leavesHashChains + - initialRoot + - startIndex + - subtrees + - rootSeq + properties: + addresses: + type: array + items: + $ref: '#/components/schemas/SerializablePubkey' + initialRoot: + $ref: '#/components/schemas/Hash' + leavesHashChains: + type: array + items: + $ref: '#/components/schemas/Hash' + lowElementIndices: + type: array + items: + type: integer + format: uint64 + minimum: 0 + lowElementNextIndices: + type: array + items: + type: integer + format: uint64 + minimum: 0 + lowElementNextValues: + type: array + items: + $ref: '#/components/schemas/Hash' + lowElementValues: + type: array + items: + $ref: '#/components/schemas/Hash' + nodes: + type: array + items: + $ref: '#/components/schemas/Node' + description: Deduplicated tree nodes - clients reconstruct proofs from these using low_element_indices + queueIndices: + type: array + items: + type: integer + format: uint64 + minimum: 0 + rootSeq: type: integer format: uint64 minimum: 0 + startIndex: + type: integer + format: uint64 + minimum: 0 + subtrees: + type: array + items: + $ref: '#/components/schemas/Hash' additionalProperties: false AddressWithTree: type: object @@ -4578,14 +4883,17 @@ components: - c properties: a: - type: string - format: binary + type: array + items: + type: integer b: - type: string - format: binary + type: array + items: + type: integer c: - type: string - format: binary + type: array + items: + type: integer CompressedProofWithContext: type: object required: @@ -4625,36 +4933,19 @@ components: CompressedProofWithContextV2: type: object required: - - roots - - rootIndices - - leafIndices - - leaves - - merkleContexts + - accounts + - addresses properties: - compressedProof: - $ref: '#/components/schemas/CompressedProof' - leafIndices: + accounts: type: array items: - type: integer - format: uint32 - minimum: 0 - leaves: - type: array - items: - type: string - merkleContexts: - type: array - items: - $ref: '#/components/schemas/MerkleContextV2' - rootIndices: - type: array - items: - $ref: '#/components/schemas/RootIndex' - roots: + $ref: '#/components/schemas/AccountProofInputs' + addresses: type: array items: - type: string + $ref: '#/components/schemas/AddressProofInputs' + compressedProof: + $ref: '#/components/schemas/CompressedProof' CompressionInfoV2: type: object required: @@ -4758,44 +5049,52 @@ components: treeContext: $ref: '#/components/schemas/TreeContextInfo' additionalProperties: false - GetQueueElementsResponseValue: + Hash: + type: string + description: A 32-byte hash represented as a base58 string. + example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP + InputQueueData: type: object required: - - proof - - root - - leafIndex - - leaf - - tree - - rootSeq - - accountHash + - leafIndices + - accountHashes + - leaves + - txHashes + - nullifiers + - firstQueueIndex + - leavesHashChains properties: - accountHash: - $ref: '#/components/schemas/Hash' - leaf: - $ref: '#/components/schemas/Hash' - leafIndex: - type: integer - format: uint64 - minimum: 0 - proof: + accountHashes: type: array items: $ref: '#/components/schemas/Hash' - root: - $ref: '#/components/schemas/Hash' - rootSeq: + firstQueueIndex: type: integer format: uint64 minimum: 0 - tree: - $ref: '#/components/schemas/Hash' - txHash: - $ref: '#/components/schemas/Hash' + leafIndices: + type: array + items: + type: integer + format: uint64 + minimum: 0 + leaves: + type: array + items: + $ref: '#/components/schemas/Hash' + leavesHashChains: + type: array + items: + $ref: '#/components/schemas/Hash' + nullifiers: + type: array + items: + $ref: '#/components/schemas/Hash' + txHashes: + type: array + items: + $ref: '#/components/schemas/Hash' additionalProperties: false - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP Limit: type: integer format: uint64 @@ -4870,6 +5169,58 @@ components: format: uint64 minimum: 0 additionalProperties: false + Node: + type: object + description: A tree node with its encoded index and hash + required: + - index + - hash + properties: + hash: + $ref: '#/components/schemas/Hash' + index: + type: integer + format: uint64 + description: 'Encoded node index: (level << 56) | position' + minimum: 0 + additionalProperties: false + OutputQueueData: + type: object + required: + - leafIndices + - accountHashes + - leaves + - firstQueueIndex + - nextIndex + - leavesHashChains + properties: + accountHashes: + type: array + items: + $ref: '#/components/schemas/Hash' + firstQueueIndex: + type: integer + format: uint64 + minimum: 0 + leafIndices: + type: array + items: + type: integer + format: uint64 + minimum: 0 + leaves: + type: array + items: + $ref: '#/components/schemas/Hash' + leavesHashChains: + type: array + items: + $ref: '#/components/schemas/Hash' + nextIndex: + type: integer + format: uint64 + minimum: 0 + additionalProperties: false OwnerBalance: type: object required: @@ -4938,6 +5289,47 @@ components: type: array items: $ref: '#/components/schemas/SignatureInfo' + QueueInfo: + type: object + required: + - tree + - queue + - queueType + - queueSize + properties: + queue: + type: string + queueSize: + type: integer + format: uint64 + minimum: 0 + queueType: + type: integer + format: uint8 + minimum: 0 + tree: + type: string + QueueRequest: + type: object + description: Parameters for requesting queue elements + required: + - limit + properties: + limit: + type: integer + format: uint16 + minimum: 0 + startIndex: + type: integer + format: uint64 + nullable: true + minimum: 0 + zkpBatchSize: + type: integer + format: uint16 + nullable: true + minimum: 0 + additionalProperties: false RootIndex: type: object required: @@ -4953,8 +5345,8 @@ components: SerializablePubkey: type: string description: A Solana public key represented as a base58 string. - default: 111111131h1vYVSYuKP6AhS86fbRdMw9XHiZAvAaj - example: 111111131h1vYVSYuKP6AhS86fbRdMw9XHiZAvAaj + default: 111FJo4zLAGU9nzTWa6EnbV4VAmtG4FR8kcokrtZYr + example: 111FJo4zLAGU9nzTWa6EnbV4VAmtG4FR8kcokrtZYr SerializableSignature: type: string description: A Solana transaction signature. @@ -5007,6 +5399,53 @@ components: $ref: '#/components/schemas/SerializableSignature' slot: $ref: '#/components/schemas/UnsignedInteger' + SolanaAccountData: + type: object + description: Nested Solana account fields (matches getAccountInfo shape) + required: + - lamports + - data + - owner + - executable + - rentEpoch + - space + properties: + data: + $ref: '#/components/schemas/Base64String' + executable: + type: boolean + lamports: + $ref: '#/components/schemas/UnsignedInteger' + owner: + $ref: '#/components/schemas/SerializablePubkey' + rentEpoch: + $ref: '#/components/schemas/UnsignedInteger' + space: + $ref: '#/components/schemas/UnsignedInteger' + StateQueueData: + type: object + description: State queue data with shared tree nodes for output and input queues + required: + - initialRoot + - rootSeq + properties: + initialRoot: + $ref: '#/components/schemas/Hash' + inputQueue: + $ref: '#/components/schemas/InputQueueData' + nodes: + type: array + items: + $ref: '#/components/schemas/Node' + description: Shared deduplicated tree nodes for state queues (output + input) + outputQueue: + $ref: '#/components/schemas/OutputQueueData' + rootSeq: + type: integer + format: uint64 + description: Sequence number of the root + minimum: 0 + additionalProperties: false TokenAccount: type: object required: diff --git a/src/openapi/specs/getCompressedAccount.yaml b/src/openapi/specs/getCompressedAccount.yaml deleted file mode 100644 index 5c8a72c2..00000000 --- a/src/openapi/specs/getCompressedAccount.yaml +++ /dev/null @@ -1,165 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Account: - type: object - required: - - hash - - owner - - lamports - - tree - - leafIndex - - seq - - slotCreated - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - data: - $ref: '#/components/schemas/AccountData' - hash: - $ref: '#/components/schemas/Hash' - lamports: - $ref: '#/components/schemas/UnsignedInteger' - leafIndex: - $ref: '#/components/schemas/UnsignedInteger' - owner: - $ref: '#/components/schemas/SerializablePubkey' - seq: - $ref: '#/components/schemas/UnsignedInteger' - slotCreated: - $ref: '#/components/schemas/UnsignedInteger' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - AccountData: - type: object - required: - - discriminator - - data - - dataHash - properties: - data: - $ref: '#/components/schemas/Base64String' - dataHash: - $ref: '#/components/schemas/Hash' - discriminator: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - Base64String: - type: string - description: A base 64 encoded string. - default: SGVsbG8sIFdvcmxkIQ== - example: SGVsbG8sIFdvcmxkIQ== - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111112D1oxKts8YPdTJRG5FzxTNpMtWmq8hkVx3 - example: 11111112D1oxKts8YPdTJRG5FzxTNpMtWmq8hkVx3 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedAccountBalance.yaml b/src/openapi/specs/getCompressedAccountBalance.yaml deleted file mode 100644 index c81337be..00000000 --- a/src/openapi/specs/getCompressedAccountBalance.yaml +++ /dev/null @@ -1,117 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getCompressedAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedAccountProof.yaml b/src/openapi/specs/getCompressedAccountProof.yaml deleted file mode 100644 index 3fe5e364..00000000 --- a/src/openapi/specs/getCompressedAccountProof.yaml +++ /dev/null @@ -1,130 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - MerkleProofWithContext: - type: object - required: - - proof - - root - - leafIndex - - hash - - merkleTree - - rootSeq - properties: - hash: - $ref: '#/components/schemas/Hash' - leafIndex: - type: integer - format: int32 - minimum: 0 - merkleTree: - $ref: '#/components/schemas/SerializablePubkey' - proof: - type: array - items: - $ref: '#/components/schemas/Hash' - root: - $ref: '#/components/schemas/Hash' - rootSeq: - type: integer - format: int64 - minimum: 0 - additionalProperties: false - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111117353mdUKehx9GW6JNHznGt5oSZs9fWkVkB - example: 11111117353mdUKehx9GW6JNHznGt5oSZs9fWkVkB diff --git a/src/openapi/specs/getCompressedAccountsByOwner.yaml b/src/openapi/specs/getCompressedAccountsByOwner.yaml deleted file mode 100644 index fed347a9..00000000 --- a/src/openapi/specs/getCompressedAccountsByOwner.yaml +++ /dev/null @@ -1,787 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - dataSlice: - allOf: - - $ref: '#/components/schemas/DataSlice' - nullable: true - filters: - type: array - items: - $ref: '#/components/schemas/FilterSelector' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Account: - type: object - required: - - hash - - owner - - lamports - - tree - - leafIndex - - seq - - slotCreated - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - data: - $ref: '#/components/schemas/AccountData' - hash: - $ref: '#/components/schemas/Hash' - lamports: - $ref: '#/components/schemas/UnsignedInteger' - leafIndex: - $ref: '#/components/schemas/UnsignedInteger' - owner: - $ref: '#/components/schemas/SerializablePubkey' - seq: - $ref: '#/components/schemas/UnsignedInteger' - slotCreated: - $ref: '#/components/schemas/UnsignedInteger' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - AccountData: - type: object - required: - - discriminator - - data - - dataHash - properties: - data: - $ref: '#/components/schemas/Base64String' - dataHash: - $ref: '#/components/schemas/Hash' - discriminator: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - Base58String: - type: string - description: A base 58 encoded string. - default: 3J98t1WpEZ73CNm - example: 3J98t1WpEZ73CNm - Base64String: - type: string - description: A base 64 encoded string. - default: SGVsbG8sIFdvcmxkIQ== - example: SGVsbG8sIFdvcmxkIQ== - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - DataSlice: - type: object - required: - - offset - - length - properties: - length: - type: integer - minimum: 0 - offset: - type: integer - minimum: 0 - FilterSelector: - type: object - properties: - memcmp: - $ref: '#/components/schemas/Memcmp' - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - Limit: - type: integer - format: int64 - minimum: 0 - Memcmp: - type: object - required: - - offset - - bytes - properties: - bytes: - $ref: '#/components/schemas/Base58String' - offset: - type: integer - minimum: 0 - PaginatedAccountList: - type: object - required: - - items - properties: - cursor: - $ref: '#/components/schemas/Hash' - items: - type: array - items: - $ref: '#/components/schemas/Account' - additionalProperties: false - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111114d3RrygbPdAtMuFnDmzsN8T5fYKVQ7FVr7 - example: 11111114d3RrygbPdAtMuFnDmzsN8T5fYKVQ7FVr7 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedBalanceByOwner.yaml b/src/openapi/specs/getCompressedBalanceByOwner.yaml deleted file mode 100644 index 5262bc87..00000000 --- a/src/openapi/specs/getCompressedBalanceByOwner.yaml +++ /dev/null @@ -1,1143 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalance: - summary: getCompressedBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalanceByOwner: - summary: getCompressedBalanceByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalanceByOwner - params: - type: object - required: - - owner - properties: - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111113R2cuenjG5nFubqX9Wzuukdin2YfGQVzu5 - example: 11111113R2cuenjG5nFubqX9Wzuukdin2YfGQVzu5 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedMintTokenHolders.yaml b/src/openapi/specs/getCompressedMintTokenHolders.yaml deleted file mode 100644 index dcc1ad4a..00000000 --- a/src/openapi/specs/getCompressedMintTokenHolders.yaml +++ /dev/null @@ -1,140 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getCompressedMintTokenHolders - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedMintTokenHolders - params: - type: object - required: - - mint - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/OwnerBalanceList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Base58String: - type: string - description: A base 58 encoded string. - default: 3J98t1WpEZ73CNm - example: 3J98t1WpEZ73CNm - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - OwnerBalance: - type: object - required: - - owner - - balance - properties: - balance: - $ref: '#/components/schemas/UnsignedInteger' - owner: - $ref: '#/components/schemas/SerializablePubkey' - OwnerBalanceList: - type: object - required: - - items - properties: - cursor: - $ref: '#/components/schemas/Base58String' - items: - type: array - items: - $ref: '#/components/schemas/OwnerBalance' - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 111111152P2r5yt6odmBLPsFCLBrFisJ3aS7LqLAT - example: 111111152P2r5yt6odmBLPsFCLBrFisJ3aS7LqLAT - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedTokenAccountBalance.yaml b/src/openapi/specs/getCompressedTokenAccountBalance.yaml deleted file mode 100644 index e7e98873..00000000 --- a/src/openapi/specs/getCompressedTokenAccountBalance.yaml +++ /dev/null @@ -1,931 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 111111131h1vYVSYuKP6AhS86fbRdMw9XHiZAvAaj - example: 111111131h1vYVSYuKP6AhS86fbRdMw9XHiZAvAaj - TokenAccountBalance: - type: object - required: - - amount - properties: - amount: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedTokenAccountsByDelegate.yaml b/src/openapi/specs/getCompressedTokenAccountsByDelegate.yaml deleted file mode 100644 index 9f1e56d6..00000000 --- a/src/openapi/specs/getCompressedTokenAccountsByDelegate.yaml +++ /dev/null @@ -1,671 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Account: - type: object - required: - - hash - - owner - - lamports - - tree - - leafIndex - - seq - - slotCreated - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - data: - $ref: '#/components/schemas/AccountData' - hash: - $ref: '#/components/schemas/Hash' - lamports: - $ref: '#/components/schemas/UnsignedInteger' - leafIndex: - $ref: '#/components/schemas/UnsignedInteger' - owner: - $ref: '#/components/schemas/SerializablePubkey' - seq: - $ref: '#/components/schemas/UnsignedInteger' - slotCreated: - $ref: '#/components/schemas/UnsignedInteger' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - AccountData: - type: object - required: - - discriminator - - data - - dataHash - properties: - data: - $ref: '#/components/schemas/Base64String' - dataHash: - $ref: '#/components/schemas/Hash' - discriminator: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - AccountState: - type: string - enum: - - initialized - - frozen - Base58String: - type: string - description: A base 58 encoded string. - default: 3J98t1WpEZ73CNm - example: 3J98t1WpEZ73CNm - Base64String: - type: string - description: A base 64 encoded string. - default: SGVsbG8sIFdvcmxkIQ== - example: SGVsbG8sIFdvcmxkIQ== - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - Limit: - type: integer - format: int64 - minimum: 0 - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111116EPqoQskEM2Pddp8KTL9JdYEBZMGF3aq7V - example: 11111116EPqoQskEM2Pddp8KTL9JdYEBZMGF3aq7V - TokenAcccount: - type: object - required: - - account - - tokenData - properties: - account: - $ref: '#/components/schemas/Account' - tokenData: - $ref: '#/components/schemas/TokenData' - additionalProperties: false - TokenAccountList: - type: object - required: - - items - properties: - cursor: - $ref: '#/components/schemas/Base58String' - items: - type: array - items: - $ref: '#/components/schemas/TokenAcccount' - TokenData: - type: object - required: - - mint - - owner - - amount - - state - properties: - amount: - $ref: '#/components/schemas/UnsignedInteger' - delegate: - $ref: '#/components/schemas/SerializablePubkey' - mint: - $ref: '#/components/schemas/SerializablePubkey' - owner: - $ref: '#/components/schemas/SerializablePubkey' - state: - $ref: '#/components/schemas/AccountState' - tlv: - $ref: '#/components/schemas/Base64String' - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedTokenAccountsByOwner.yaml b/src/openapi/specs/getCompressedTokenAccountsByOwner.yaml deleted file mode 100644 index a7ec38b5..00000000 --- a/src/openapi/specs/getCompressedTokenAccountsByOwner.yaml +++ /dev/null @@ -1,552 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Account: - type: object - required: - - hash - - owner - - lamports - - tree - - leafIndex - - seq - - slotCreated - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - data: - $ref: '#/components/schemas/AccountData' - hash: - $ref: '#/components/schemas/Hash' - lamports: - $ref: '#/components/schemas/UnsignedInteger' - leafIndex: - $ref: '#/components/schemas/UnsignedInteger' - owner: - $ref: '#/components/schemas/SerializablePubkey' - seq: - $ref: '#/components/schemas/UnsignedInteger' - slotCreated: - $ref: '#/components/schemas/UnsignedInteger' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - AccountData: - type: object - required: - - discriminator - - data - - dataHash - properties: - data: - $ref: '#/components/schemas/Base64String' - dataHash: - $ref: '#/components/schemas/Hash' - discriminator: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - AccountState: - type: string - enum: - - initialized - - frozen - Base58String: - type: string - description: A base 58 encoded string. - default: 3J98t1WpEZ73CNm - example: 3J98t1WpEZ73CNm - Base64String: - type: string - description: A base 64 encoded string. - default: SGVsbG8sIFdvcmxkIQ== - example: SGVsbG8sIFdvcmxkIQ== - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - Limit: - type: integer - format: int64 - minimum: 0 - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9 - example: 11111115q4EpJaTXAZWpCg3J2zppWGSZ46KXozzo9 - TokenAcccount: - type: object - required: - - account - - tokenData - properties: - account: - $ref: '#/components/schemas/Account' - tokenData: - $ref: '#/components/schemas/TokenData' - additionalProperties: false - TokenAccountList: - type: object - required: - - items - properties: - cursor: - $ref: '#/components/schemas/Base58String' - items: - type: array - items: - $ref: '#/components/schemas/TokenAcccount' - TokenData: - type: object - required: - - mint - - owner - - amount - - state - properties: - amount: - $ref: '#/components/schemas/UnsignedInteger' - delegate: - $ref: '#/components/schemas/SerializablePubkey' - mint: - $ref: '#/components/schemas/SerializablePubkey' - owner: - $ref: '#/components/schemas/SerializablePubkey' - state: - $ref: '#/components/schemas/AccountState' - tlv: - $ref: '#/components/schemas/Base64String' - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedTokenBalancesByOwner.yaml b/src/openapi/specs/getCompressedTokenBalancesByOwner.yaml deleted file mode 100644 index 5ea55809..00000000 --- a/src/openapi/specs/getCompressedTokenBalancesByOwner.yaml +++ /dev/null @@ -1,1292 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalance: - summary: getCompressedBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalanceByOwner: - summary: getCompressedBalanceByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalanceByOwner - params: - type: object - required: - - owner - properties: - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenBalancesByOwner: - summary: getCompressedTokenBalancesByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenBalancesByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenBalanceList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Base58String: - type: string - description: A base 58 encoded string. - default: 3J98t1WpEZ73CNm - example: 3J98t1WpEZ73CNm - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111113pNDtm61yGF8j2ycAwLEPsuWQXobye5qDR - example: 11111113pNDtm61yGF8j2ycAwLEPsuWQXobye5qDR - TokenBalance: - type: object - required: - - mint - - balance - properties: - balance: - $ref: '#/components/schemas/UnsignedInteger' - mint: - $ref: '#/components/schemas/SerializablePubkey' - TokenBalanceList: - type: object - required: - - token_balances - properties: - cursor: - $ref: '#/components/schemas/Base58String' - token_balances: - type: array - items: - $ref: '#/components/schemas/TokenBalance' - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressedTokenBalancesByOwnerV2.yaml b/src/openapi/specs/getCompressedTokenBalancesByOwnerV2.yaml deleted file mode 100644 index 71d1dddc..00000000 --- a/src/openapi/specs/getCompressedTokenBalancesByOwnerV2.yaml +++ /dev/null @@ -1,144 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getCompressedTokenBalancesByOwnerV2 - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenBalancesByOwnerV2 - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenBalanceListV2' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Base58String: - type: string - description: A base 58 encoded string. - default: 3J98t1WpEZ73CNm - example: 3J98t1WpEZ73CNm - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111114DhpssPJgSi1YU7hCMfYt1BJ334YgsffXm - example: 11111114DhpssPJgSi1YU7hCMfYt1BJ334YgsffXm - TokenBalance: - type: object - required: - - mint - - balance - properties: - balance: - $ref: '#/components/schemas/UnsignedInteger' - mint: - $ref: '#/components/schemas/SerializablePubkey' - TokenBalanceListV2: - type: object - required: - - items - properties: - cursor: - $ref: '#/components/schemas/Base58String' - items: - type: array - items: - $ref: '#/components/schemas/TokenBalance' - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressionSignaturesForAccount.yaml b/src/openapi/specs/getCompressionSignaturesForAccount.yaml deleted file mode 100644 index e73a2d12..00000000 --- a/src/openapi/specs/getCompressionSignaturesForAccount.yaml +++ /dev/null @@ -1,1515 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalance: - summary: getCompressedBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalanceByOwner: - summary: getCompressedBalanceByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalanceByOwner - params: - type: object - required: - - owner - properties: - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenBalancesByOwner: - summary: getCompressedTokenBalancesByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenBalancesByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenBalanceList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAccount: - summary: getCompressionSignaturesForAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAccount - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/SignatureInfoList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getTransactionWithCompressionInfo: - summary: getTransactionWithCompressionInfo - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getTransactionWithCompressionInfo - params: - type: object - required: - - signature - properties: - signature: - $ref: '#/components/schemas/SerializableSignature' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - description: A Solana transaction with additional compression information - properties: - compression_info: - type: object - required: - - closed_accounts - - opened_accounts - properties: - closed_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - opened_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - transaction: - type: object - description: An encoded confirmed transaction with status meta - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - SerializableSignature: - type: string - description: A Solana transaction signature. - default: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - example: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - SignatureInfo: - type: object - required: - - signature - - slot - - blockTime - properties: - blockTime: - $ref: '#/components/schemas/UnixTimestamp' - signature: - $ref: '#/components/schemas/SerializableSignature' - slot: - $ref: '#/components/schemas/UnsignedInteger' - SignatureInfoList: - type: object - required: - - items - properties: - items: - type: array - items: - $ref: '#/components/schemas/SignatureInfo' - UnixTimestamp: - type: integer - description: An Unix timestamp (seconds) - default: 1714081554 - example: 1714081554 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressionSignaturesForAddress.yaml b/src/openapi/specs/getCompressionSignaturesForAddress.yaml deleted file mode 100644 index f3f9850c..00000000 --- a/src/openapi/specs/getCompressionSignaturesForAddress.yaml +++ /dev/null @@ -1,1637 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalance: - summary: getCompressedBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalanceByOwner: - summary: getCompressedBalanceByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalanceByOwner - params: - type: object - required: - - owner - properties: - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenBalancesByOwner: - summary: getCompressedTokenBalancesByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenBalancesByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenBalanceList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAccount: - summary: getCompressionSignaturesForAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAccount - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/SignatureInfoList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAddress: - summary: getCompressionSignaturesForAddress - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAddress - params: - type: object - required: - - address - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedSignatureInfoList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getTransactionWithCompressionInfo: - summary: getTransactionWithCompressionInfo - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getTransactionWithCompressionInfo - params: - type: object - required: - - signature - properties: - signature: - $ref: '#/components/schemas/SerializableSignature' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - description: A Solana transaction with additional compression information - properties: - compression_info: - type: object - required: - - closed_accounts - - opened_accounts - properties: - closed_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - opened_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - transaction: - type: object - description: An encoded confirmed transaction with status meta - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - PaginatedSignatureInfoList: - type: object - required: - - items - properties: - cursor: - type: string - nullable: true - items: - type: array - items: - $ref: '#/components/schemas/SignatureInfo' - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111119T6fgHG3unjQB6vpWozhBdiXDbQovvFVeF - example: 11111119T6fgHG3unjQB6vpWozhBdiXDbQovvFVeF - SerializableSignature: - type: string - description: A Solana transaction signature. - default: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - example: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - SignatureInfo: - type: object - required: - - signature - - slot - - blockTime - properties: - blockTime: - $ref: '#/components/schemas/UnixTimestamp' - signature: - $ref: '#/components/schemas/SerializableSignature' - slot: - $ref: '#/components/schemas/UnsignedInteger' - UnixTimestamp: - type: integer - description: An Unix timestamp (seconds) - default: 1714081554 - example: 1714081554 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressionSignaturesForOwner.yaml b/src/openapi/specs/getCompressionSignaturesForOwner.yaml deleted file mode 100644 index 5b18e040..00000000 --- a/src/openapi/specs/getCompressionSignaturesForOwner.yaml +++ /dev/null @@ -1,1750 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalance: - summary: getCompressedBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalanceByOwner: - summary: getCompressedBalanceByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalanceByOwner - params: - type: object - required: - - owner - properties: - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenBalancesByOwner: - summary: getCompressedTokenBalancesByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenBalancesByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenBalanceList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAccount: - summary: getCompressionSignaturesForAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAccount - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/SignatureInfoList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAddress: - summary: getCompressionSignaturesForAddress - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAddress - params: - type: object - required: - - address - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedSignatureInfoList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForOwner: - summary: getCompressionSignaturesForOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForOwner - params: - type: object - required: - - owner - properties: - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedSignatureInfoList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getTransactionWithCompressionInfo: - summary: getTransactionWithCompressionInfo - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getTransactionWithCompressionInfo - params: - type: object - required: - - signature - properties: - signature: - $ref: '#/components/schemas/SerializableSignature' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - description: A Solana transaction with additional compression information - properties: - compression_info: - type: object - required: - - closed_accounts - - opened_accounts - properties: - closed_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - opened_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - transaction: - type: object - description: An encoded confirmed transaction with status meta - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - PaginatedSignatureInfoList: - type: object - required: - - items - properties: - cursor: - type: string - nullable: true - items: - type: array - items: - $ref: '#/components/schemas/SignatureInfo' - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111119rSGfPZLcyCGzY4uYEL1fkzJr6fke9qKxb - example: 11111119rSGfPZLcyCGzY4uYEL1fkzJr6fke9qKxb - SerializableSignature: - type: string - description: A Solana transaction signature. - default: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - example: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - SignatureInfo: - type: object - required: - - signature - - slot - - blockTime - properties: - blockTime: - $ref: '#/components/schemas/UnixTimestamp' - signature: - $ref: '#/components/schemas/SerializableSignature' - slot: - $ref: '#/components/schemas/UnsignedInteger' - UnixTimestamp: - type: integer - description: An Unix timestamp (seconds) - default: 1714081554 - example: 1714081554 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getCompressionSignaturesForTokenOwner.yaml b/src/openapi/specs/getCompressionSignaturesForTokenOwner.yaml deleted file mode 100644 index b5407929..00000000 --- a/src/openapi/specs/getCompressionSignaturesForTokenOwner.yaml +++ /dev/null @@ -1,1863 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalance: - summary: getCompressedBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalanceByOwner: - summary: getCompressedBalanceByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalanceByOwner - params: - type: object - required: - - owner - properties: - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenBalancesByOwner: - summary: getCompressedTokenBalancesByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenBalancesByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenBalanceList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAccount: - summary: getCompressionSignaturesForAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAccount - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/SignatureInfoList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAddress: - summary: getCompressionSignaturesForAddress - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAddress - params: - type: object - required: - - address - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedSignatureInfoList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForOwner: - summary: getCompressionSignaturesForOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForOwner - params: - type: object - required: - - owner - properties: - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedSignatureInfoList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForTokenOwner: - summary: getCompressionSignaturesForTokenOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForTokenOwner - params: - type: object - required: - - owner - properties: - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedSignatureInfoList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getTransactionWithCompressionInfo: - summary: getTransactionWithCompressionInfo - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getTransactionWithCompressionInfo - params: - type: object - required: - - signature - properties: - signature: - $ref: '#/components/schemas/SerializableSignature' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - description: A Solana transaction with additional compression information - properties: - compression_info: - type: object - required: - - closed_accounts - - opened_accounts - properties: - closed_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - opened_accounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - transaction: - type: object - description: An encoded confirmed transaction with status meta - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - PaginatedSignatureInfoList: - type: object - required: - - items - properties: - cursor: - type: string - nullable: true - items: - type: array - items: - $ref: '#/components/schemas/SignatureInfo' - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 1111111AFmseVrdL9f9oyCzZefL9tG6UbvhMPRAGw - example: 1111111AFmseVrdL9f9oyCzZefL9tG6UbvhMPRAGw - SerializableSignature: - type: string - description: A Solana transaction signature. - default: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - example: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - SignatureInfo: - type: object - required: - - signature - - slot - - blockTime - properties: - blockTime: - $ref: '#/components/schemas/UnixTimestamp' - signature: - $ref: '#/components/schemas/SerializableSignature' - slot: - $ref: '#/components/schemas/UnsignedInteger' - UnixTimestamp: - type: integer - description: An Unix timestamp (seconds) - default: 1714081554 - example: 1714081554 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getIndexerHealth.yaml b/src/openapi/specs/getIndexerHealth.yaml deleted file mode 100644 index d40866cb..00000000 --- a/src/openapi/specs/getIndexerHealth.yaml +++ /dev/null @@ -1,69 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getIndexerHealth - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getIndexerHealth - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: string - description: ok if healthy - default: ok - enum: - - ok - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: {} diff --git a/src/openapi/specs/getIndexerSlot.yaml b/src/openapi/specs/getIndexerSlot.yaml deleted file mode 100644 index 29edaa6d..00000000 --- a/src/openapi/specs/getIndexerSlot.yaml +++ /dev/null @@ -1,67 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getIndexerSlot - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getIndexerSlot - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: integer - default: 100 - example: 100 - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: {} diff --git a/src/openapi/specs/getLatestCompressionSignatures.yaml b/src/openapi/specs/getLatestCompressionSignatures.yaml deleted file mode 100644 index 902f34b9..00000000 --- a/src/openapi/specs/getLatestCompressionSignatures.yaml +++ /dev/null @@ -1,139 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getLatestCompressionSignatures - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getLatestCompressionSignatures - params: - type: object - properties: - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedSignatureInfoList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - PaginatedSignatureInfoList: - type: object - required: - - items - properties: - cursor: - type: string - nullable: true - items: - type: array - items: - $ref: '#/components/schemas/SignatureInfo' - SerializableSignature: - type: string - description: A Solana transaction signature. - default: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - example: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - SignatureInfo: - type: object - required: - - signature - - slot - - blockTime - properties: - blockTime: - $ref: '#/components/schemas/UnixTimestamp' - signature: - $ref: '#/components/schemas/SerializableSignature' - slot: - $ref: '#/components/schemas/UnsignedInteger' - UnixTimestamp: - type: integer - description: An Unix timestamp (seconds) - default: 1714081554 - example: 1714081554 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getLatestNonVotingSignatures.yaml b/src/openapi/specs/getLatestNonVotingSignatures.yaml deleted file mode 100644 index 004c673a..00000000 --- a/src/openapi/specs/getLatestNonVotingSignatures.yaml +++ /dev/null @@ -1,139 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getLatestNonVotingSignatures - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getLatestNonVotingSignatures - params: - type: object - properties: - cursor: - type: string - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/SignatureInfoListWithError' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Limit: - type: integer - format: int64 - minimum: 0 - SerializableSignature: - type: string - description: A Solana transaction signature. - default: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - example: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - SignatureInfoListWithError: - type: object - required: - - items - properties: - items: - type: array - items: - $ref: '#/components/schemas/SignatureInfoWithError' - SignatureInfoWithError: - type: object - required: - - signature - - slot - - blockTime - properties: - blockTime: - $ref: '#/components/schemas/UnixTimestamp' - error: - type: string - nullable: true - signature: - $ref: '#/components/schemas/SerializableSignature' - slot: - $ref: '#/components/schemas/UnsignedInteger' - UnixTimestamp: - type: integer - description: An Unix timestamp (seconds) - default: 1714081554 - example: 1714081554 - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getMultipleCompressedAccountProofs.yaml b/src/openapi/specs/getMultipleCompressedAccountProofs.yaml deleted file mode 100644 index c520f8f9..00000000 --- a/src/openapi/specs/getMultipleCompressedAccountProofs.yaml +++ /dev/null @@ -1,129 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - MerkleProofWithContext: - type: object - required: - - proof - - root - - leafIndex - - hash - - merkleTree - - rootSeq - properties: - hash: - $ref: '#/components/schemas/Hash' - leafIndex: - type: integer - format: int32 - minimum: 0 - merkleTree: - $ref: '#/components/schemas/SerializablePubkey' - proof: - type: array - items: - $ref: '#/components/schemas/Hash' - root: - $ref: '#/components/schemas/Hash' - rootSeq: - type: integer - format: int64 - minimum: 0 - additionalProperties: false - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111117SQekjmcMtR25wEPPiL6m1Mb5586NkLL4X - example: 11111117SQekjmcMtR25wEPPiL6m1Mb5586NkLL4X diff --git a/src/openapi/specs/getMultipleCompressedAccounts.yaml b/src/openapi/specs/getMultipleCompressedAccounts.yaml deleted file mode 100644 index de54f52d..00000000 --- a/src/openapi/specs/getMultipleCompressedAccounts.yaml +++ /dev/null @@ -1,866 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Account: - type: object - required: - - hash - - owner - - lamports - - tree - - leafIndex - - seq - - slotCreated - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - data: - $ref: '#/components/schemas/AccountData' - hash: - $ref: '#/components/schemas/Hash' - lamports: - $ref: '#/components/schemas/UnsignedInteger' - leafIndex: - $ref: '#/components/schemas/UnsignedInteger' - owner: - $ref: '#/components/schemas/SerializablePubkey' - seq: - $ref: '#/components/schemas/UnsignedInteger' - slotCreated: - $ref: '#/components/schemas/UnsignedInteger' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - AccountData: - type: object - required: - - discriminator - - data - - dataHash - properties: - data: - $ref: '#/components/schemas/Base64String' - dataHash: - $ref: '#/components/schemas/Hash' - discriminator: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - AccountList: - type: object - required: - - items - properties: - items: - type: array - items: - allOf: - - $ref: '#/components/schemas/Account' - nullable: true - additionalProperties: false - Base64String: - type: string - description: A base 64 encoded string. - default: SGVsbG8sIFdvcmxkIQ== - example: SGVsbG8sIFdvcmxkIQ== - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo - example: 11111115RidqCHAoz6dzmXxGcfWLNzevYqNpaRAUo - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getMultipleNewAddressProofs.yaml b/src/openapi/specs/getMultipleNewAddressProofs.yaml deleted file mode 100644 index 95efb887..00000000 --- a/src/openapi/specs/getMultipleNewAddressProofs.yaml +++ /dev/null @@ -1,139 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getMultipleNewAddressProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleNewAddressProofs - params: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleContextWithNewAddressProof' - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - MerkleContextWithNewAddressProof: - type: object - required: - - root - - address - - lowerRangeAddress - - higherRangeAddress - - nextIndex - - proof - - merkleTree - - rootSeq - - lowElementLeafIndex - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - higherRangeAddress: - $ref: '#/components/schemas/SerializablePubkey' - lowElementLeafIndex: - type: integer - format: int32 - minimum: 0 - lowerRangeAddress: - $ref: '#/components/schemas/SerializablePubkey' - merkleTree: - $ref: '#/components/schemas/SerializablePubkey' - nextIndex: - type: integer - format: int32 - minimum: 0 - proof: - type: array - items: - $ref: '#/components/schemas/Hash' - root: - $ref: '#/components/schemas/Hash' - rootSeq: - type: integer - format: int64 - minimum: 0 - additionalProperties: false - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs - example: 11111117qkFjr4u54stuNNUR8fRF8dNhaP35yvANs diff --git a/src/openapi/specs/getMultipleNewAddressProofsV2.yaml b/src/openapi/specs/getMultipleNewAddressProofsV2.yaml deleted file mode 100644 index 399efde3..00000000 --- a/src/openapi/specs/getMultipleNewAddressProofsV2.yaml +++ /dev/null @@ -1,150 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getMultipleNewAddressProofsV2 - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleNewAddressProofsV2 - params: - type: array - items: - $ref: '#/components/schemas/AddressWithTree' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleContextWithNewAddressProof' - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - AddressWithTree: - type: object - required: - - address - - tree - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - MerkleContextWithNewAddressProof: - type: object - required: - - root - - address - - lowerRangeAddress - - higherRangeAddress - - nextIndex - - proof - - merkleTree - - rootSeq - - lowElementLeafIndex - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - higherRangeAddress: - $ref: '#/components/schemas/SerializablePubkey' - lowElementLeafIndex: - type: integer - format: int32 - minimum: 0 - lowerRangeAddress: - $ref: '#/components/schemas/SerializablePubkey' - merkleTree: - $ref: '#/components/schemas/SerializablePubkey' - nextIndex: - type: integer - format: int32 - minimum: 0 - proof: - type: array - items: - $ref: '#/components/schemas/Hash' - root: - $ref: '#/components/schemas/Hash' - rootSeq: - type: integer - format: int64 - minimum: 0 - additionalProperties: false - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111118F5rixNBnFLmioWZSYzjjFuAL5dyoDVzhD - example: 11111118F5rixNBnFLmioWZSYzjjFuAL5dyoDVzhD diff --git a/src/openapi/specs/getQueueElements.yaml b/src/openapi/specs/getQueueElements.yaml deleted file mode 100644 index bfe4aa0a..00000000 --- a/src/openapi/specs/getQueueElements.yaml +++ /dev/null @@ -1,89 +0,0 @@ -paths: - /: - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getQueueElements - params: - type: object - required: - - queue - - batch - - startOffset - - endOffset - properties: - queue: - $ref: '#/components/schemas/Hash' - batch: - $ref: '#/components/schemas/UnsignedInteger' - startOffset: - $ref: '#/components/schemas/UnsignedInteger' - endOffset: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/Hash' - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Hash: - type: string - description: A base58 encoded hash. - default: "11111111111111111111111111111111" - example: "11111111111111111111111111111111" \ No newline at end of file diff --git a/src/openapi/specs/getTransactionWithCompressionInfo.yaml b/src/openapi/specs/getTransactionWithCompressionInfo.yaml deleted file mode 100644 index a7e00abf..00000000 --- a/src/openapi/specs/getTransactionWithCompressionInfo.yaml +++ /dev/null @@ -1,1569 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /getCompressedAccount: - summary: getCompressedAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccount - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/Account' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountProof: - summary: getCompressedAccountProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountProof - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedAccountsByOwner: - summary: getCompressedAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/PaginatedAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalance: - summary: getCompressedBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedBalanceByOwner: - summary: getCompressedBalanceByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedBalanceByOwner - params: - type: object - required: - - owner - properties: - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/UnsignedInteger' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountBalance: - summary: getCompressedTokenAccountBalance - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountBalance - params: - type: object - description: Request for compressed account data - default: - address: null - hash: '11111111111111111111111111111111' - properties: - address: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hash: - allOf: - - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - address: null - hash: '11111111111111111111111111111111' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountBalance' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByDelegate: - summary: getCompressedTokenAccountsByDelegate - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByDelegate - params: - type: object - required: - - delegate - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - delegate: - $ref: '#/components/schemas/SerializablePubkey' - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenAccountsByOwner: - summary: getCompressedTokenAccountsByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenAccountsByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenAccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressedTokenBalancesByOwner: - summary: getCompressedTokenBalancesByOwner - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressedTokenBalancesByOwner - params: - type: object - required: - - owner - properties: - cursor: - allOf: - - $ref: '#/components/schemas/Base58String' - nullable: true - limit: - allOf: - - $ref: '#/components/schemas/Limit' - nullable: true - mint: - allOf: - - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - owner: - $ref: '#/components/schemas/SerializablePubkey' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/TokenBalanceList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getCompressionSignaturesForAccount: - summary: getCompressionSignaturesForAccount - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getCompressionSignaturesForAccount - params: - type: object - required: - - hash - properties: - hash: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/SignatureInfoList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccountProofs: - summary: getMultipleCompressedAccountProofs - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccountProofs - params: - type: array - items: - $ref: '#/components/schemas/Hash' - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - type: array - items: - $ref: '#/components/schemas/MerkleProofWithContext' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getMultipleCompressedAccounts: - summary: getMultipleCompressedAccounts - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getMultipleCompressedAccounts - params: - type: object - description: Request for compressed account data - default: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - properties: - addresses: - type: array - items: - $ref: '#/components/schemas/SerializablePubkey' - nullable: true - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - nullable: true - additionalProperties: false - example: - addresses: null - hashes: - - 1111111QLbz7JHiBTspS962RLKV8GndWFwiEaqKM - - 1111111ogCyDbaRMvkdsHB3qfdyFYaG1WtRUAfdh - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - context - - value - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/AccountList' - '400': - description: Invalid request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '401': - description: Unauthorized request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '403': - description: Request was forbidden. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '404': - description: The specified resource was not found. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string - /getTransactionWithCompressionInfo: - summary: getTransactionWithCompressionInfo - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getTransactionWithCompressionInfo - params: - type: object - required: - - signature - properties: - signature: - $ref: '#/components/schemas/SerializableSignature' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - description: A Solana transaction with additional compression information - properties: - compression_info: - type: object - required: - - closedAccounts - - openedAccounts - properties: - closedAccounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - openedAccounts: - type: array - items: - $ref: '#/components/schemas/AccountWithOptionalTokenData' - additionalProperties: false - transaction: - type: object - description: An encoded confirmed transaction with status meta - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - Account: - type: object - required: - - hash - - owner - - lamports - - tree - - leafIndex - - seq - - slotCreated - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - data: - $ref: '#/components/schemas/AccountData' - hash: - $ref: '#/components/schemas/Hash' - lamports: - $ref: '#/components/schemas/UnsignedInteger' - leafIndex: - $ref: '#/components/schemas/UnsignedInteger' - owner: - $ref: '#/components/schemas/SerializablePubkey' - seq: - $ref: '#/components/schemas/UnsignedInteger' - slotCreated: - $ref: '#/components/schemas/UnsignedInteger' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - AccountData: - type: object - required: - - discriminator - - data - - dataHash - properties: - data: - $ref: '#/components/schemas/Base64String' - dataHash: - $ref: '#/components/schemas/Hash' - discriminator: - $ref: '#/components/schemas/UnsignedInteger' - additionalProperties: false - AccountState: - type: string - enum: - - initialized - - frozen - AccountWithOptionalTokenData: - type: object - required: - - account - properties: - account: - $ref: '#/components/schemas/Account' - optionalTokenData: - $ref: '#/components/schemas/TokenData' - additionalProperties: false - Base64String: - type: string - description: A base 64 encoded string. - default: SGVsbG8sIFdvcmxkIQ== - example: SGVsbG8sIFdvcmxkIQ== - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111116djSnXB2wXVGT4xDLsfTnkp1p4cCxHAfRq - example: 11111116djSnXB2wXVGT4xDLsfTnkp1p4cCxHAfRq - SerializableSignature: - type: string - description: A Solana transaction signature. - default: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - example: 5J8H5sTvEhnGcB4R8K1n7mfoiWUD9RzPVGES7e3WxC7c - TokenData: - type: object - required: - - mint - - owner - - amount - - state - properties: - amount: - $ref: '#/components/schemas/UnsignedInteger' - delegate: - $ref: '#/components/schemas/SerializablePubkey' - mint: - $ref: '#/components/schemas/SerializablePubkey' - owner: - $ref: '#/components/schemas/SerializablePubkey' - state: - $ref: '#/components/schemas/AccountState' - tlv: - $ref: '#/components/schemas/Base64String' - UnsignedInteger: - type: integer - default: 100 - example: 100 diff --git a/src/openapi/specs/getValidityProof.yaml b/src/openapi/specs/getValidityProof.yaml deleted file mode 100644 index d2abd4eb..00000000 --- a/src/openapi/specs/getValidityProof.yaml +++ /dev/null @@ -1,169 +0,0 @@ -openapi: 3.0.3 -info: - title: photon-indexer - description: Solana indexer for general compression - license: - name: Apache-2.0 - version: 0.50.0 -servers: -- url: https://mainnet.helius-rpc.com?api-key= -paths: - /: - summary: getValidityProof - post: - requestBody: - content: - application/json: - schema: - type: object - required: - - jsonrpc - - id - - method - - params - properties: - id: - type: string - description: An ID to identify the request. - enum: - - test-account - jsonrpc: - type: string - description: The version of the JSON-RPC protocol. - enum: - - '2.0' - method: - type: string - description: The name of the method to invoke. - enum: - - getValidityProof - params: - type: object - properties: - hashes: - type: array - items: - $ref: '#/components/schemas/Hash' - newAddressesWithTrees: - type: array - items: - $ref: '#/components/schemas/AddressWithTree' - additionalProperties: false - required: true - responses: - '200': - description: '' - content: - application/json: - schema: - type: object - required: - - value - - context - properties: - context: - $ref: '#/components/schemas/Context' - value: - $ref: '#/components/schemas/CompressedProofWithContext' - additionalProperties: false - '429': - description: Exceeded rate limit. - content: - application/json: - schema: - type: object - properties: - error: - type: string - '500': - description: The server encountered an unexpected condition that prevented it from fulfilling the request. - content: - application/json: - schema: - type: object - properties: - error: - type: string -components: - schemas: - AddressWithTree: - type: object - required: - - address - - tree - properties: - address: - $ref: '#/components/schemas/SerializablePubkey' - tree: - $ref: '#/components/schemas/SerializablePubkey' - additionalProperties: false - CompressedProof: - type: object - required: - - a - - b - - c - properties: - a: - type: string - format: binary - b: - type: string - format: binary - c: - type: string - format: binary - CompressedProofWithContext: - type: object - required: - - compressedProof - - roots - - rootIndices - - leafIndices - - leaves - - merkleTrees - properties: - compressedProof: - $ref: '#/components/schemas/CompressedProof' - leafIndices: - type: array - items: - type: integer - format: int32 - minimum: 0 - leaves: - type: array - items: - type: string - merkleTrees: - type: array - items: - type: string - rootIndices: - type: array - items: - type: integer - format: int64 - minimum: 0 - roots: - type: array - items: - type: string - Context: - type: object - required: - - slot - properties: - slot: - type: integer - default: 100 - example: 100 - Hash: - type: string - description: A 32-byte hash represented as a base58 string. - example: 11111112cMQwSC9qirWGjZM6gLGwW69X22mqwLLGP - SerializablePubkey: - type: string - description: A Solana public key represented as a base58 string. - default: 11111118eRTi4fUVRoeYEeeTyL4DPAwxatvWT5q1Z - example: 11111118eRTi4fUVRoeYEeeTyL4DPAwxatvWT5q1Z diff --git a/src/openapi/specs/openapitools.json b/src/openapi/specs/openapitools.json deleted file mode 100644 index cfe74d51..00000000 --- a/src/openapi/specs/openapitools.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "$schema": "./node_modules/@openapitools/openapi-generator-cli/config.schema.json", - "spaces": 2, - "generator-cli": { - "version": "7.5.0" - } -} diff --git a/src/snapshot/loader/main.rs b/src/snapshot/loader/main.rs index fb44270e..482e0a7f 100644 --- a/src/snapshot/loader/main.rs +++ b/src/snapshot/loader/main.rs @@ -36,7 +36,7 @@ async fn main() -> anyhow::Result<()> { let http_client = reqwest::Client::new(); // Call the download snapshot endpoint let response = http_client - .get(&format!("{}/download", args.snapshot_server_url)) + .get(format!("{}/download", args.snapshot_server_url)) .send() .await .unwrap(); diff --git a/src/snapshot/mod.rs b/src/snapshot/mod.rs index 6493ca91..5ad7f985 100644 --- a/src/snapshot/mod.rs +++ b/src/snapshot/mod.rs @@ -1,7 +1,7 @@ use std::{ env::temp_dir, fs::{self, File, OpenOptions}, - io::{BufReader, Error, ErrorKind, Read, Write}, + io::{BufReader, Error, Read, Write}, path::PathBuf, pin::Pin, sync::Arc, @@ -157,8 +157,7 @@ impl R2DirectoryAdapter { pin_mut!(byte_stream); // Create a stream that converts `Result` to `Result, S3Error>` - let byte_stream = - byte_stream.map(|bytes| bytes.map_err(|e| Error::new(ErrorKind::Other, e))); + let byte_stream = byte_stream.map(|bytes| bytes.map_err(Error::other)); let mut stream_reader = StreamReader { stream: byte_stream, diff --git a/src/snapshot/snapshotter/main.rs b/src/snapshot/snapshotter/main.rs index 7abe3420..45ef5a6d 100644 --- a/src/snapshot/snapshotter/main.rs +++ b/src/snapshot/snapshotter/main.rs @@ -115,7 +115,7 @@ async fn stream_bytes( let byte_stream = byte_stream.map(|bytes| { bytes.map_err(|e| { error!("Error reading byte: {:?}", e); - io::Error::new(io::ErrorKind::Other, "Stream Error") + io::Error::other("Stream Error") }) }); diff --git a/src/tools/tree_validator/main.rs b/src/tools/tree_validator/main.rs index 45139460..e70729de 100644 --- a/src/tools/tree_validator/main.rs +++ b/src/tools/tree_validator/main.rs @@ -9,7 +9,6 @@ use photon_indexer::{ }; use solana_pubkey::Pubkey; use std::str::FromStr; -use tokio; #[derive(Parser)] struct Args { diff --git a/tests/integration_tests/batched_state_tree_tests.rs b/tests/integration_tests/batched_state_tree_tests.rs index 6a6dc3f3..0af34045 100644 --- a/tests/integration_tests/batched_state_tree_tests.rs +++ b/tests/integration_tests/batched_state_tree_tests.rs @@ -17,7 +17,7 @@ use photon_indexer::common::typedefs::serializable_pubkey::SerializablePubkey; use photon_indexer::common::typedefs::serializable_signature::SerializableSignature; use photon_indexer::common::typedefs::token_data::TokenData; use photon_indexer::common::typedefs::unsigned_integer::UnsignedInteger; -use photon_indexer::ingester::persist::COMPRESSED_TOKEN_PROGRAM; +use photon_indexer::ingester::persist::LIGHT_TOKEN_PROGRAM_ID; use serial_test::serial; use solana_pubkey::Pubkey; use solana_signature::Signature; @@ -392,21 +392,22 @@ async fn test_batched_tree_transactions( println!("pre input queue len {}", pre_input_len,); // Insert 1 batch. - let pre_output_queue = pre_output_queue_elements + if let Some(pre_output_queue) = pre_output_queue_elements .state_queue .as_ref() .and_then(|sq| sq.output_queue.as_ref()) - .unwrap(); - let slice_length = pre_output_queue.leaves.len().min(10); - for idx in 0..slice_length { - let leaf_index = pre_output_queue.leaf_indices[idx]; - let leaf_hash = &pre_output_queue.leaves[idx]; - let leaf = event_merkle_tree.leaf(leaf_index as usize); - if leaf == [0u8; 32] { - event_merkle_tree - .update(&leaf_hash.0, leaf_index as usize) - .unwrap(); - println!("append leaf index {}", leaf_index); + { + let slice_length = pre_output_queue.leaves.len().min(10); + for idx in 0..slice_length { + let leaf_index = pre_output_queue.leaf_indices[idx]; + let leaf_hash = &pre_output_queue.leaves[idx]; + let leaf = event_merkle_tree.leaf(leaf_index as usize); + if leaf == [0u8; 32] { + event_merkle_tree + .update(&leaf_hash.0, leaf_index as usize) + .unwrap(); + println!("append leaf index {}", leaf_index); + } } } } @@ -684,7 +685,7 @@ async fn test_batched_tree_token_transactions( assert_eq!(account.account.lamports, UnsignedInteger(1_000_000)); assert_eq!( account.account.owner, - SerializablePubkey::from(COMPRESSED_TOKEN_PROGRAM) + SerializablePubkey::from(LIGHT_TOKEN_PROGRAM_ID) ); assert_eq!(account.account.leaf_index.0, i as u64); assert_eq!(account.account.seq, None); diff --git a/tests/integration_tests/e2e_tests.rs b/tests/integration_tests/e2e_tests.rs index 63fad492..ca849f99 100644 --- a/tests/integration_tests/e2e_tests.rs +++ b/tests/integration_tests/e2e_tests.rs @@ -621,8 +621,9 @@ async fn test_get_latest_non_voting_signatures_with_failures( async fn test_nullfiier_and_address_queue_transactions( #[values(DatabaseBackend::Sqlite, DatabaseBackend::Postgres)] db_backend: DatabaseBackend, ) { + use light_sdk_types::constants::ADDRESS_TREE_V1; use photon_indexer::api::method::get_multiple_new_address_proofs::{ - AddressListWithTrees, AddressWithTree, ADDRESS_TREE_V1, + AddressListWithTrees, AddressWithTree, }; let name = trim_test_name(function_name!()); diff --git a/tests/integration_tests/mock_tests.rs b/tests/integration_tests/mock_tests.rs index dd268669..a319c050 100644 --- a/tests/integration_tests/mock_tests.rs +++ b/tests/integration_tests/mock_tests.rs @@ -566,7 +566,7 @@ async fn test_persist_token_data( lamports: Set(Decimal::from(10)), slot_created: Set(slot), leaf_index: Set(i as i64), - discriminator: Set(Some(Decimal::from(1))), + discriminator: Set(Some(Decimal::from(1u64))), data_hash: Set(Some(Hash::new_unique().to_vec())), tree: Set(Pubkey::new_unique().to_bytes().to_vec()), queue: Set(Some(Pubkey::new_unique().to_bytes().to_vec())), @@ -578,6 +578,7 @@ async fn test_persist_token_data( token_datas.push(EnrichedTokenAccount { hash, token_data: token_data.clone(), + ata_owner: None, }); } @@ -963,6 +964,13 @@ async fn test_persisted_state_trees( } } +/// Helper to create a 32-byte padded value from a single byte for AddressV2 tests +fn padded_value(val: u8) -> Vec { + let mut v = vec![0u8; 31]; + v.push(val); + v +} + #[named] #[rstest] #[tokio::test] @@ -981,7 +989,10 @@ async fn test_indexed_merkle_trees( .await .unwrap(); - let values = (0..num_nodes).map(|i| vec![i * 4 + 1]).collect(); + // Use 32-byte padded values for AddressV2 hash compatibility + let values: Vec> = (0..num_nodes) + .map(|i| padded_value((i * 4 + 1) as u8)) + .collect(); let tree_height = 33; // prev. 4 // Create tree info cache - convert SerializablePubkey to Pubkey @@ -1015,7 +1026,7 @@ async fn test_indexed_merkle_trees( &setup.db_conn.begin().await.unwrap(), tree.to_bytes_vec(), tree_height, - vec![3], + padded_value(3), ) .await .unwrap(); @@ -1023,9 +1034,9 @@ async fn test_indexed_merkle_trees( let expected_model = indexed_trees::Model { tree: tree.to_bytes_vec(), leaf_index: 1, - value: vec![1], + value: padded_value(1), next_index: 2, - next_value: vec![5], + next_value: padded_value(5), seq: Some(0), }; @@ -1035,7 +1046,7 @@ async fn test_indexed_merkle_trees( .await .unwrap(); - let values = vec![vec![3]]; + let values = vec![padded_value(3)]; multi_append( &txn, @@ -1056,7 +1067,7 @@ async fn test_indexed_merkle_trees( &setup.db_conn.begin().await.unwrap(), tree.to_bytes_vec(), tree_height, - vec![4], + padded_value(4), ) .await .unwrap(); @@ -1064,9 +1075,9 @@ async fn test_indexed_merkle_trees( let expected_model = indexed_trees::Model { tree: tree.to_bytes_vec(), leaf_index: 3, - value: vec![3], + value: padded_value(3), next_index: 2, - next_value: vec![5], + next_value: padded_value(5), seq: Some(1), }; @@ -1119,10 +1130,11 @@ async fn test_get_multiple_new_address_proofs( async fn test_get_multiple_new_address_proofs_interop( #[values(DatabaseBackend::Sqlite, DatabaseBackend::Postgres)] db_backend: DatabaseBackend, ) { + use light_sdk_types::constants::ADDRESS_TREE_V1; use photon_indexer::api::method::{ get_multiple_new_address_proofs::{ get_multiple_new_address_proofs, get_multiple_new_address_proofs_v2, AddressList, - AddressListWithTrees, AddressWithTree, ADDRESS_TREE_V1, + AddressListWithTrees, AddressWithTree, }, get_validity_proof::CompressedProof, }; @@ -1157,6 +1169,7 @@ async fn test_get_multiple_new_address_proofs_interop( let mut validity_proof = get_validity_proof( &setup.db_conn, &setup.prover_url, + None, GetValidityProofRequest { new_addresses: addresses.clone(), new_addresses_with_trees: vec![], @@ -1190,6 +1203,7 @@ async fn test_get_multiple_new_address_proofs_interop( let mut validity_proof_v2 = get_validity_proof_v2( &setup.db_conn, &setup.prover_url, + None, GetValidityProofRequestV2 { new_addresses_with_trees: addresses_with_trees.clone(), hashes: vec![], diff --git a/tests/integration_tests/prod_tests.rs b/tests/integration_tests/prod_tests.rs index f8eeece0..ef60ac61 100644 --- a/tests/integration_tests/prod_tests.rs +++ b/tests/integration_tests/prod_tests.rs @@ -29,7 +29,7 @@ async fn test_incorrect_root_bug() { let devnet_db = Arc::new(SqlxPostgresConnector::from_sqlx_postgres_pool(pool)); let rpc_client = get_rpc_client("https://api.devnet.solana.com"); let prover_url = "http://localhost:3001"; - let api = PhotonApi::new(devnet_db.clone(), rpc_client, prover_url.to_string()); + let api = PhotonApi::new(devnet_db.clone(), rpc_client, prover_url.to_string(), None); let response = api .get_compressed_accounts_by_owner(GetCompressedAccountsByOwnerRequest { @@ -55,7 +55,7 @@ async fn test_mainnet_fra_invalid_address_tree_bug() { let devnet_db = Arc::new(SqlxPostgresConnector::from_sqlx_postgres_pool(pool)); let rpc_client = get_rpc_client("https://api.mainnet-beta.solana.com"); let prover_url = "http://localhost:3001"; - let api = PhotonApi::new(devnet_db.clone(), rpc_client, prover_url.to_string()); + let api = PhotonApi::new(devnet_db.clone(), rpc_client, prover_url.to_string(), None); let response = api .get_multiple_new_address_proofs_v2(AddressListWithTrees(vec![AddressWithTree { diff --git a/tests/integration_tests/utils.rs b/tests/integration_tests/utils.rs index 766331f8..355fe967 100644 --- a/tests/integration_tests/utils.rs +++ b/tests/integration_tests/utils.rs @@ -108,7 +108,30 @@ pub async fn populate_test_tree_metadata(db: &DatabaseConnection) { 32, 2400, ), - // V2 Address Tree + // V2 State Trees (batched) - used by forester indexer_interface test + ( + "bmt1LryLZUMmF7ZtqESaw7wifBXLfXHQYoE4GAmrahU", + "oq1na8gojfdUhsfCpyjNt6h4JaDWtHf1yQj4koBWfto", + TreeType::StateV2, + 32, + 2400, + ), + ( + "bmt2UxoBxB9xWev4BkLvkGdapsz6sZGkzViPNph7VFi", + "oq2UkeMsJLfXt2QHzim242SUi3nvjJs8Pn7Eac9H9vg", + TreeType::StateV2, + 32, + 2400, + ), + // V2 State Tree - used by light-protocol default config (test_indexer_interface) + ( + "bmt5yU97jC88YXTuSukYHa8Z5Bi2ZDUtmzfkDTA2mG2", + "oq5oh5ZR3yGomuQgFduNDzjtGvVWfDRGLuDVjv9a96P", + TreeType::StateV2, + 32, + 2400, + ), + // V2 Address Trees ( "EzKE84aVTkCUhDHLELqyJaq1Y7UVVmqxXqZjVHwHY3rK", "EzKE84aVTkCUhDHLELqyJaq1Y7UVVmqxXqZjVHwHY3rK", @@ -225,7 +248,7 @@ pub async fn setup_with_options(name: String, opts: TestSetupOptions) -> TestSet }; let client = get_rpc_client(&rpc_url); let prover_url = "http://127.0.0.1:3001".to_string(); - let api = PhotonApi::new(db_conn.clone(), client.clone(), prover_url.clone()); + let api = PhotonApi::new(db_conn.clone(), client.clone(), prover_url.clone(), None); TestSetup { name, db_conn, @@ -560,6 +583,7 @@ pub async fn index_transaction( let state_update = parse_transaction(db_conn.as_ref(), &tx_info, 0, &mut resolver) .await .unwrap(); + persist_state_update_using_connection(db_conn.as_ref(), state_update) .await .unwrap(); From a7e022f150711e8c68d6bc71d0d32d73a4d43190 Mon Sep 17 00:00:00 2001 From: i-am-bert Date: Wed, 18 Mar 2026 10:30:39 -0700 Subject: [PATCH 02/16] fix: bump light-* deps for light-event 0.23.1 OOB panic fix (#341) Bumps all light-* dependencies to compatible versions: - light-event: 0.21 -> 0.23.1 (includes OOB panic fix) - light-concurrent-merkle-tree: 4 -> 5 - light-batched-merkle-tree: 0.10 -> 0.11 - light-merkle-tree-metadata: 0.10 -> 0.11 - light-compressed-account: 0.10.1 -> 0.11 - light-indexed-merkle-tree: 4 -> 5 - light-token-interface: 0.4 -> 0.5 - light-sdk-types: 0.20 -> 0.23 Fixes the index-out-of-bounds panic in create_nullifier_queue_indices() that halted both pitt and fra ingestors at slot 407265370. Upstream fix: https://github.com/Lightprotocol/light-protocol/pull/2353 cargo check passes. Co-authored-by: i-am-bert --- Cargo.lock | 2195 +++++++++++++++++++++++++++++----------------------- Cargo.toml | 16 +- 2 files changed, 1250 insertions(+), 961 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7b1d9aea..3e4f2814 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,9 +56,9 @@ dependencies = [ [[package]] name = "agave-feature-set" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6b71300ed93a9dff1c3231c3f1417e242e3da38529ebc32f828bc8560bf4a2a" +checksum = "4a36f13a213d45f45f8ff87ea9fc6b0a792a7997c76b7c5d6d4a2ebe741d19d0" dependencies = [ "ahash 0.8.12", "solana-epoch-schedule 3.0.0", @@ -70,9 +70,9 @@ dependencies = [ [[package]] name = "agave-reserved-account-keys" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac34d0410a2a015df7d45d092449c7ec59264081d05f18c7f305ccf7c81bd3b7" +checksum = "6e4dbcc14290a572b94f8793561f74f87e8dd1efb6c28c883d79a84242ee9633" dependencies = [ "agave-feature-set", "solana-pubkey 3.0.0", @@ -85,7 +85,7 @@ version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "once_cell", "version_check", ] @@ -126,7 +126,7 @@ checksum = "48a526ec4434d531d488af59fe866f36b310fe8906691c75dffa664450a3800a" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -161,9 +161,9 @@ dependencies = [ [[package]] name = "anstream" -version = "0.6.21" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ "anstyle", "anstyle-parse", @@ -176,15 +176,15 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.13" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] name = "anstyle-parse" -version = "0.2.7" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ "utf8parse", ] @@ -211,15 +211,61 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.100" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "anza-quinn" +version = "0.11.9-rustsec20260037" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a23eb6b1614318a8071c9b2521f36b424b2c83db5eb3a0fead4a6c0809af6e61" +checksum = "91bfa08f6e7e4187354ff4f793b81cc08218a6a95cc48f5de7616d44452bf6e0" +dependencies = [ + "anza-quinn-proto", + "bytes", + "cfg_aliases", + "pin-project-lite", + "quinn-udp", + "rustc-hash 2.1.1", + "rustls 0.23.37", + "socket2 0.6.3", + "thiserror 2.0.18", + "tokio", + "tracing", + "web-time", +] + +[[package]] +name = "anza-quinn-proto" +version = "0.11.13-rustsec20260037" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d00a4d8cf8d72ee56e0ee20d3b4eef4785ce1b05299c4982c6de7f251c458efe" +dependencies = [ + "bytes", + "fastbloom", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.2", + "ring 0.17.14", + "rustc-hash 2.1.1", + "rustls 0.23.37", + "rustls-pki-types", + "rustls-platform-verifier", + "slab", + "thiserror 2.0.18", + "tinyvec", + "tracing", + "web-time", +] [[package]] name = "arc-swap" -version = "1.7.1" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69f7f8c3906b62b754cd5326047894316021dcfe5a194c8ea52bdd94934a3457" +checksum = "f9f3647c145568cec02c42054e07bdf9a5a698e15b466fb2341bfc393cd24aa5" +dependencies = [ + "rustversion", +] [[package]] name = "ark-bn254" @@ -338,7 +384,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" dependencies = [ "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -364,7 +410,7 @@ dependencies = [ "num-traits", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -439,7 +485,7 @@ checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -568,22 +614,21 @@ dependencies = [ [[package]] name = "async-compression" -version = "0.4.33" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93c1f86859c1af3d514fa19e8323147ff10ea98684e6c7b307912509f50e67b2" +checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" dependencies = [ "compression-codecs", "compression-core", - "futures-core", "pin-project-lite", "tokio", ] [[package]] name = "async-executor" -version = "1.13.3" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "497c00e0fd83a72a79a39fcbd8e3e2f055d6f6c7e025f3b3d91f4f8e76527fb8" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" dependencies = [ "async-task", "concurrent-queue", @@ -629,9 +674,9 @@ dependencies = [ [[package]] name = "async-lock" -version = "3.4.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5fd03604047cee9b6ce9de9f70c6cd540a0520c813cbd49bae61f33ab80ed1dc" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ "event-listener 5.4.1", "event-listener-strategy", @@ -684,7 +729,7 @@ checksum = "c7c24de15d275a1ecfd47a380fb4d5ec9bfe0933f309ed5e705b775596a3574d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -701,7 +746,7 @@ checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -787,14 +832,14 @@ dependencies = [ [[package]] name = "axum" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b098575ebe77cb6d14fc7f32749631a6e44edbef6b796f89b020e99ba20d425" +checksum = "8b52af3cb4058c895d37317bb27508dccc8e5f2d39454016b297bf4a400597b8" dependencies = [ "axum-core", "bytes", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "itoa", @@ -805,20 +850,20 @@ dependencies = [ "pin-project-lite", "serde_core", "sync_wrapper 1.0.2", - "tower 0.5.2", + "tower 0.5.3", "tower-layer", "tower-service", ] [[package]] name = "axum-core" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59446ce19cd142f8833f856eb31f3eb097812d1479ab224f54d72428ca21ea22" +checksum = "08c78f31d7b1291f7ee735c1c6780ccde7785daae9a9206026862dab7d8792d1" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "mime", @@ -867,9 +912,9 @@ checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "beef" @@ -897,9 +942,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.10.0" +version = "2.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" dependencies = [ "serde_core", ] @@ -918,15 +963,16 @@ dependencies = [ [[package]] name = "blake3" -version = "1.8.2" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" +checksum = "2468ef7d57b3fb7e16b576e8377cdbde2320c60e1491e961d11da40fc4f02a2d" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", + "cpufeatures", "digest 0.10.7", ] @@ -973,11 +1019,12 @@ dependencies = [ [[package]] name = "borsh" -version = "1.5.7" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad8646f98db542e39fc66e68a20b2144f6a732636df7c2354e74645faaa433ce" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" dependencies = [ - "borsh-derive 1.5.7", + "borsh-derive 1.6.1", + "bytes", "cfg_aliases", ] @@ -996,15 +1043,15 @@ dependencies = [ [[package]] name = "borsh-derive" -version = "1.5.7" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fdd1d3c0c2f5833f22386f252fe8ed005c7f59fdcddeef025c01b4c3b9fd9ac3" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" dependencies = [ "once_cell", - "proc-macro-crate 3.4.0", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1098,9 +1145,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.19.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bv" @@ -1136,9 +1183,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.24.0" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] @@ -1151,7 +1198,7 @@ checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1162,27 +1209,27 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.11.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b35204fbdc0b3f4446b89fc1ac2cf84a8a68971995d0bf2e925ec7cd960f9cb3" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" dependencies = [ "serde", ] [[package]] name = "cadence" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3075f133bee430b7644c54fb629b9b4420346ffa275a45c81a6babe8b09b4f51" +checksum = "d7aff0c323415907f37007d645d7499c378df47efb3e33ffc1f397fa4e549b2e" dependencies = [ "crossbeam-channel", ] [[package]] name = "cadence-macros" -version = "1.6.0" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33521416213ffba7559ea8e0190ab2690e286c2a1e04d63d18fe4498aefefed6" +checksum = "410850e760ee40689d87bf9029a715155e67dfa946b56ae1182ac45e6f9faf05" dependencies = [ "cadence", ] @@ -1198,9 +1245,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.2.47" +version = "1.2.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd405d82c84ff7f35739f175f67d8b9fb7687a0e84ccdc78bd3568839827cf07" +checksum = "7a0dd1ca384932ff3641c8718a02769f1698e7563dc6974ffd03346116310423" dependencies = [ "find-msvc-tools", "jobserver", @@ -1234,14 +1281,14 @@ checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "chrono" -version = "0.4.42" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ "iana-time-zone", "js-sys", @@ -1280,23 +1327,23 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.53" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9e340e012a1bf4935f5282ed1436d1489548e8f72308207ea5df0e23d2d03f8" +checksum = "b193af5b67834b676abd72466a96c1024e6a6ad978a1f484bd90b85c94041351" dependencies = [ "clap_builder", - "clap_derive 4.5.49", + "clap_derive 4.6.0", ] [[package]] name = "clap_builder" -version = "4.5.53" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d76b5d13eaa18c901fd2f7fca939fefe3a0727a953561fefdf3b2922b8569d00" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" dependencies = [ "anstream", "anstyle", - "clap_lex 0.7.6", + "clap_lex 1.1.0", "strsim 0.11.1", ] @@ -1315,14 +1362,14 @@ dependencies = [ [[package]] name = "clap_derive" -version = "4.5.49" +version = "4.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a0b5487afeab2deb2ff4e03a807ad1a03ac532ff5a2cee5d86884440c7f7671" +checksum = "1110bd8a634a1ab8cb04345d8d878267d57c3cf1b38d91b71af6686408bbca6a" dependencies = [ "heck 0.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1336,9 +1383,9 @@ dependencies = [ [[package]] name = "clap_lex" -version = "0.7.6" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d728cc89cf3aee9ff92b05e62b19ee65a02b5702cff7d5a377e32c6ae29d8d" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" [[package]] name = "cloud-storage" @@ -1365,9 +1412,9 @@ dependencies = [ [[package]] name = "colorchoice" -version = "1.0.4" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" @@ -1394,9 +1441,9 @@ dependencies = [ [[package]] name = "compression-codecs" -version = "0.4.32" +version = "0.4.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "680dc087785c5230f8e8843e2e57ac7c1c90488b6a91b88caa265410568f441b" +checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" dependencies = [ "brotli 8.0.2", "compression-core", @@ -1406,9 +1453,9 @@ dependencies = [ [[package]] name = "compression-core" -version = "0.4.30" +version = "0.4.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a9b614a5787ef0c8802a55766480563cb3a93b435898c422ed2a359cf811582" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" [[package]] name = "concurrent-queue" @@ -1433,13 +1480,12 @@ dependencies = [ [[package]] name = "console" -version = "0.16.1" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b430743a6eb14e9764d4260d4c0d8123087d504eeb9c48f2b2a5e810dd369df4" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" dependencies = [ "encode_unicode", "libc", - "once_cell", "unicode-width", "windows-sys 0.61.2", ] @@ -1485,16 +1531,16 @@ version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f9d839f2a20b0aee515dc581a6172f2321f96cab76c1a38a4c584a194955390e" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "once_cell", "tiny-keccak", ] [[package]] name = "constant_time_eq" -version = "0.3.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "core-foundation" @@ -1533,9 +1579,9 @@ dependencies = [ [[package]] name = "crc" -version = "3.3.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9710d3b3739c2e349eb44fe848ad0b7c8cb1e42bd87ee49371df2f7acaf3e675" +checksum = "5eb8a2a1cd12ab0d987a5d5e825195d372001a4094a0376319d5a0ad71c1ba0d" dependencies = [ "crc-catalog", ] @@ -1650,7 +1696,7 @@ checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1659,8 +1705,18 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + +[[package]] +name = "darling" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" +dependencies = [ + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] @@ -1674,7 +1730,20 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.11.1", - "syn 2.0.110", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim 0.11.1", + "syn 2.0.117", ] [[package]] @@ -1683,9 +1752,20 @@ version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" dependencies = [ - "darling_core", + "darling_core 0.21.3", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" +dependencies = [ + "darling_core 0.23.0", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1703,9 +1783,9 @@ dependencies = [ [[package]] name = "data-encoding" -version = "2.9.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "der" @@ -1733,9 +1813,9 @@ dependencies = [ [[package]] name = "deranged" -version = "0.5.5" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ececcb659e7ba858fb4f10388c250a7252eb0a27373f1a72b8748afdd248e587" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", "serde_core", @@ -1827,7 +1907,7 @@ checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1850,7 +1930,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1908,7 +1988,7 @@ dependencies = [ "enum-ordinalize", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -1952,7 +2032,7 @@ checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -2000,9 +2080,9 @@ dependencies = [ [[package]] name = "fastbloom" -version = "0.14.0" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18c1ddb9231d8554c2d6bdf4cfaabf0c59251658c68b6c95cd52dd0c513a912a" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" dependencies = [ "getrandom 0.3.4", "libm", @@ -2030,9 +2110,9 @@ checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" [[package]] name = "find-msvc-tools" -version = "0.1.5" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a3076410a55c90011c298b04d0cfa770b00fa04e1e3c97d3f6c9de105a03844" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" [[package]] name = "five8" @@ -2090,9 +2170,9 @@ checksum = "1d674e81391d1e1ab681a28d99df07927c6d4aa5b027d7da16ba32d1d21ecd99" [[package]] name = "flate2" -version = "1.1.5" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfe33edd8e85a12a67454e37f8c75e730830d83e313556ab9ebf9ee7fbeb3bfb" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", @@ -2169,9 +2249,9 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" [[package]] name = "futures" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65bc07b1a8bc7c85c5f2e110c476c7389b4554ba72af57d8445ea63a576b0876" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -2184,9 +2264,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dff15bf788c671c1934e366d07e30c1814a8ef514e1af724a602e8a2fbe1b10" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -2194,15 +2274,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e28d1d997f585e54aebc3f97d39e72338912123a67330d723fdbb564d646c9f" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -2222,9 +2302,9 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e5c1b78ca4aae1ac06c48a526a655760685149f0d465d21f37abfe57ce075c6" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-lite" @@ -2241,26 +2321,26 @@ dependencies = [ [[package]] name = "futures-macro" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "162ee34ebcb7c64a8abebc059ce0fee27c2262618d7b60ed8faf72fef13c3650" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e575fab7d1e0dcb8d0c7bcf9a63ee213816ab51902e6d244a95819acacf1d4f7" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f90f7dce0722e95104fcb095585910c0977252f286e354b5e3bd38902cd99988" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" [[package]] name = "futures-timer" @@ -2270,9 +2350,9 @@ checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.31" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fa08315bb612088cc391249efdc3bc77536f16c91f6cf495e6fbe85b20a4a81" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -2282,7 +2362,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -2319,9 +2398,9 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", @@ -2339,11 +2418,24 @@ dependencies = [ "cfg-if", "js-sys", "libc", - "r-efi", + "r-efi 5.3.0", "wasip2", "wasm-bindgen", ] +[[package]] +name = "getrandom" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" +dependencies = [ + "cfg-if", + "libc", + "r-efi 6.0.0", + "wasip2", + "wasip3", +] + [[package]] name = "glob" version = "0.3.3" @@ -2422,7 +2514,7 @@ dependencies = [ "futures-sink", "futures-util", "http 0.2.12", - "indexmap 2.12.1", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -2431,17 +2523,17 @@ dependencies = [ [[package]] name = "h2" -version = "0.4.12" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3c0b69cfcb4e1b9f1bf2f53f95f766e4661169728ec61cd3fe5a0166f2d1386" +checksum = "2f44da3a8150a6703ed5d34e164b875fd14c2cdab9af1252a9a1020bde2bdc54" dependencies = [ "atomic-waker", "bytes", "fnv", "futures-core", "futures-sink", - "http 1.3.1", - "indexmap 2.12.1", + "http 1.4.0", + "indexmap 2.13.0", "slab", "tokio", "tokio-util", @@ -2612,12 +2704,11 @@ dependencies = [ [[package]] name = "http" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4a85d31aea989eead29a3aaf9e1115a180df8282431156e533de47660892565" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" dependencies = [ "bytes", - "fnv", "itoa", ] @@ -2639,7 +2730,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" dependencies = [ "bytes", - "http 1.3.1", + "http 1.4.0", ] [[package]] @@ -2650,7 +2741,7 @@ checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", "futures-core", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "pin-project-lite", ] @@ -2707,8 +2798,8 @@ dependencies = [ "bytes", "futures-channel", "futures-core", - "h2 0.4.12", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "httparse", "httpdate", @@ -2726,15 +2817,15 @@ version = "0.27.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3c93eb611681b207e1fe55d5a71ecf91572ec8a6705cdb6857f7d8d5242cf58" dependencies = [ - "http 1.3.1", + "http 1.4.0", "hyper 1.8.1", "hyper-util", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", "tower-service", - "webpki-roots 1.0.4", + "webpki-roots 1.0.6", ] [[package]] @@ -2781,24 +2872,23 @@ dependencies = [ [[package]] name = "hyper-util" -version = "0.1.18" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e9a2a24dc5c6821e71a7030e1e14b7b632acac55c40e9d2e082c621261bb56" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ "base64 0.22.1", "bytes", "futures-channel", - "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", "hyper 1.8.1", "ipnet", "libc", "percent-encoding", "pin-project-lite", - "socket2 0.6.1", - "system-configuration 0.6.1", + "socket2 0.6.3", + "system-configuration 0.7.0", "tokio", "tower-service", "tracing", @@ -2807,9 +2897,9 @@ dependencies = [ [[package]] name = "iana-time-zone" -version = "0.1.64" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33e57f83510bb73707521ebaffa789ec8caf86f9657cad665b092b581d40e9fb" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", @@ -2877,9 +2967,9 @@ checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" [[package]] name = "icu_properties" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e93fcd3157766c0c8da2f8cff6ce651a31f0810eaa1c51ec363ef790bbb5fb99" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" dependencies = [ "icu_collections", "icu_locale_core", @@ -2891,9 +2981,9 @@ dependencies = [ [[package]] name = "icu_properties_data" -version = "2.1.1" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02845b3647bb045f1100ecd6480ff52f34c35f82d9880e029d329c21d1054899" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" [[package]] name = "icu_provider" @@ -2910,6 +3000,12 @@ dependencies = [ "zerovec", ] +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + [[package]] name = "ident_case" version = "1.0.1" @@ -2949,9 +3045,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.12.1" +version = "2.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ad4bb2b565bca0645f4d68c5c9af97fba094e9791da685bf83cb5f3ce74acf2" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" dependencies = [ "equivalent", "hashbrown 0.16.1", @@ -2961,11 +3057,11 @@ dependencies = [ [[package]] name = "indicatif" -version = "0.18.3" +version = "0.18.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9375e112e4b463ec1b1c6c011953545c65a30164fbab5b581df32b3abf0dcb88" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" dependencies = [ - "console 0.16.1", + "console 0.16.3", "portable-atomic", "unicode-width", "unit-prefix", @@ -2983,14 +3079,15 @@ dependencies = [ [[package]] name = "insta" -version = "1.44.1" +version = "1.46.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e8732d3774162a0851e3f2b150eb98f31a9885dd75985099421d393385a01dfd" +checksum = "e82db8c87c7f1ccecb34ce0c24399b8a73081427f3c7c50a5d597925356115e4" dependencies = [ "console 0.15.11", "once_cell", "serde", "similar", + "tempfile", ] [[package]] @@ -3004,9 +3101,9 @@ dependencies = [ [[package]] name = "ipnet" -version = "2.11.0" +version = "2.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "469fb0b9cefa57e3ef31275ee7cacb78f2fdca44e4765491884a2b119d4eb130" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" [[package]] name = "iri-string" @@ -3019,9 +3116,9 @@ dependencies = [ [[package]] name = "iri-string" -version = "0.7.9" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4f867b9d1d896b67beb18518eda36fdb77a32ea590de864f1325b294a6d14397" +checksum = "c91338f0783edbd6195decb37bae672fd3b165faffb89bf7b9e6942f8b1a731a" dependencies = [ "memchr", "serde", @@ -3071,9 +3168,9 @@ dependencies = [ [[package]] name = "itoa" -version = "1.0.15" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jni" @@ -3109,9 +3206,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.82" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b011eec8cc36da2aab2d5cff675ec18454fad408585853910a202391cf9f8e65" +checksum = "b49715b7073f385ba4bc528e5747d02e66cb39c6146efb66b781f131f0fb399c" dependencies = [ "once_cell", "wasm-bindgen", @@ -3246,14 +3343,14 @@ dependencies = [ "ring 0.17.14", "serde", "serde_json", - "simple_asn1 0.6.3", + "simple_asn1 0.6.4", ] [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ "cpufeatures", ] @@ -3273,27 +3370,34 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + [[package]] name = "libc" -version = "0.2.177" +version = "0.2.183" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976" +checksum = "b5b646652bf6661599e1da8901b3b9522896f01e736bad5f723fe7a3a27f899d" [[package]] name = "libm" -version = "0.2.15" +version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" [[package]] name = "libredox" -version = "0.1.10" +version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "416f7e718bdb06000964960ffa43b4335ad4012ae8b99060261aa4a8088d5ccb" +checksum = "1744e39d1d6a9948f4f388969627434e31128196de472883b39f148769bfe30a" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "libc", - "redox_syscall 0.5.18", + "plain", + "redox_syscall 0.7.3", ] [[package]] @@ -3359,7 +3463,7 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34d74dd13535c6014abb4cac694e14083b206a7f6cf1bbbc9611aa5c2e11cdd1" dependencies = [ - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3373,9 +3477,9 @@ dependencies = [ [[package]] name = "light-batched-merkle-tree" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb07ef41d9d99db94072d556767a93d774323bc34940db349555abc4504de015" +checksum = "3702b96798a1cc93c9d4b0d9eb6ee980481beb147ab663cfd260c71ec258c5f0" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -3387,7 +3491,7 @@ dependencies = [ "light-merkle-tree-metadata", "light-verifier", "light-zero-copy", - "thiserror 2.0.17", + "thiserror 2.0.18", "zerocopy", ] @@ -3400,7 +3504,7 @@ dependencies = [ "bitvec", "num-bigint 0.4.6", "solana-nostd-keccak", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3416,9 +3520,9 @@ dependencies = [ [[package]] name = "light-compressed-account" -version = "0.10.1" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adab5a8dddd9675306b0a808900578ed60b40b5c5457e330e28c9cb51361118d" +checksum = "c2ce168f42dab1a4c01ad83993d68b17cd2dc1bb31ced8ab4edecaf5b666a8ad" dependencies = [ "borsh 0.10.4", "bytemuck", @@ -3426,16 +3530,16 @@ dependencies = [ "light-macros", "light-program-profiler", "light-zero-copy", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "zerocopy", ] [[package]] name = "light-compressible" -version = "0.5.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0905b52848daea4cb7edbc9ddca0a8d5c4f1d864e89eff0aca3b6fc2a9edbb2" +checksum = "54745d82dab271a4178b48c48d5768ff54af0a6e01aae62425003c25ed394fc5" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -3449,35 +3553,35 @@ dependencies = [ "pinocchio-pubkey", "solana-pubkey 2.4.0", "solana-rent 2.2.1", - "thiserror 2.0.17", + "thiserror 2.0.18", "zerocopy", ] [[package]] name = "light-concurrent-merkle-tree" -version = "4.0.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0123e37a6796ca82cca864f00f160cf73652deac17a3e625007f184f7e95e62b" +checksum = "db96f47253a0907aaa46dac15cecb27b5510130e48da0b36690dcd2e99a6d558" dependencies = [ "borsh 0.10.4", "light-bounded-vec", "light-hasher", "memoffset", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "light-event" -version = "0.21.0" +version = "0.23.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae607b61749246439e9e302a75dc565c98d6b9a81efcb1c6dd5e755a24b427ab" +checksum = "cd0c2e68b31f5fc890eb0e0c43bc7d5007cd2e02f4b46f3d601f3a91b4c7262c" dependencies = [ "borsh 0.10.4", "light-compressed-account", "light-hasher", "light-token-interface", "light-zero-copy", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3493,7 +3597,7 @@ dependencies = [ "num-bigint 0.4.6", "sha2 0.10.9", "sha3", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", ] @@ -3506,14 +3610,14 @@ dependencies = [ "light-hasher", "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "light-indexed-merkle-tree" -version = "4.0.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b717eb0e72d96490c294f05fa9fbcc9a83253a1a0f8932de2fcad1aaae0502c" +checksum = "0824755289075f28de2820fc7d4ec4e6b9e99d404e033c07338b91cce8c71fb8" dependencies = [ "light-bounded-vec", "light-concurrent-merkle-tree", @@ -3521,7 +3625,7 @@ dependencies = [ "light-merkle-tree-reference", "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3534,19 +3638,19 @@ dependencies = [ "proc-macro2", "quote", "solana-pubkey 2.4.0", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "light-merkle-tree-metadata" -version = "0.10.0" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7623246ad0015345f6a88471f554381e24635b770fe4b15b38384daddf1d2f5f" +checksum = "ee2ef127f8b968a22203515fca1822cb54bb8f0bd84de392fcb9fb0b77855393" dependencies = [ "borsh 0.10.4", "bytemuck", "light-compressed-account", - "thiserror 2.0.17", + "thiserror 2.0.18", "zerocopy", ] @@ -3560,7 +3664,7 @@ dependencies = [ "light-indexed-array", "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3595,7 +3699,7 @@ checksum = "0a8be18fe4de58a6f754caa74a3fbc6d8a758a26f1f3c24d5b0f5b55df5f5408" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -3609,9 +3713,9 @@ dependencies = [ [[package]] name = "light-sdk-types" -version = "0.20.0" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d60036a8f1af0d3aa651780aa57ae2cdca3fa0f16acecda71c98f81a53e37c9" +checksum = "efbd944a80033d928d0abf6152595d2e69aa1af07a3dd0e5b86f0b7e4fc9f484" dependencies = [ "borsh 0.10.4", "bytemuck", @@ -3621,14 +3725,14 @@ dependencies = [ "light-hasher", "light-macros", "solana-msg 2.2.1", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "light-token-interface" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77a457179188d9b6b7208a8a63a1fea851f818adfde3faaa262474bdcd3e3c7d" +checksum = "b14661b6592711d90b1cac2402fa10310d90e0517e035c6b1f47c30a14883461" dependencies = [ "aligned-sized", "borsh 0.10.4", @@ -3646,20 +3750,20 @@ dependencies = [ "solana-pubkey 2.4.0", "spl-pod 0.5.1", "spl-token-2022", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "zerocopy", ] [[package]] name = "light-verifier" -version = "9.0.0" +version = "10.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "65a33dc6b302f2cfb7319006f1234f1d86c992ac1991ade7c97653828b7f1735" +checksum = "0d829f997b17c7c65198bb93f0d645a4b2818aed2bd14bf2716e36171d4a9f3f" dependencies = [ "groth16-solana", "light-compressed-account", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -3681,14 +3785,14 @@ dependencies = [ "lazy_static", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "linux-raw-sys" -version = "0.11.0" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "litemap" @@ -3707,9 +3811,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.28" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34080505efa8e45a4b816c349525ebe327ceaa8559756f0356cba97ef3bf7432" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" dependencies = [ "value-bag", ] @@ -3743,7 +3847,7 @@ checksum = "5cf92c10c7e361d6b99666ec1c6f9805b0bea2c3bd8c78dc6fe98ac5bd78db11" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -3764,9 +3868,9 @@ checksum = "490cc448043f947bae3cbee9c203358d62dbee0db12107a74be5c30ccfd09771" [[package]] name = "memchr" -version = "2.7.6" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memoffset" @@ -3832,9 +3936,9 @@ dependencies = [ [[package]] name = "mio" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "69d83b0086dc8ecf3ce9ae2874b2d1290252e2a30720bea58a5c6639b0092873" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" dependencies = [ "libc", "wasi 0.11.1+wasi-snapshot-preview1", @@ -3849,9 +3953,9 @@ checksum = "1d87ecb2933e8aeadb3e3a02b828fed80a7528047e68b4f424523a0981a3a084" [[package]] name = "native-tls" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87de3442987e9dbec73158d5c715e7ad9072fda936bb03d19d7fa10e00520f0e" +checksum = "465500e14ea162429d264d44189adc38b199b62b1c21eea9f69e4b73cb03bbf2" dependencies = [ "libc", "log", @@ -3859,7 +3963,7 @@ dependencies = [ "openssl-probe", "openssl-sys", "schannel", - "security-framework 2.11.1", + "security-framework", "security-framework-sys", "tempfile", ] @@ -3870,7 +3974,7 @@ version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "cfg_aliases", "libc", @@ -3955,9 +4059,9 @@ dependencies = [ [[package]] name = "num-conv" -version = "0.1.0" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" +checksum = "cf97ec579c3c42f953ef76dbf8d55ac91fb219dde70e49aa4a6b7d74e9919050" [[package]] name = "num-derive" @@ -3967,7 +4071,7 @@ checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -4023,9 +4127,9 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ "num_enum_derive", "rustversion", @@ -4033,14 +4137,14 @@ dependencies = [ [[package]] name = "num_enum_derive" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "proc-macro-crate 3.4.0", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -4054,9 +4158,9 @@ dependencies = [ [[package]] name = "once_cell" -version = "1.21.3" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" @@ -4072,11 +4176,11 @@ checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "openssl" -version = "0.10.75" +version = "0.10.76" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08838db121398ad17ab8531ce9de97b244589089e290a384c900cb9ff7434328" +checksum = "951c002c75e16ea2c65b8c7e4d3d51d5530d8dfa7d060b4776828c88cfb18ecf" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg-if", "foreign-types", "libc", @@ -4093,20 +4197,20 @@ checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "openssl-probe" -version = "0.1.6" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d05e27ee213611ffe7d6348b942e8f942b37114c00cc03cec254295a4a17852e" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] name = "openssl-sys" -version = "0.9.111" +version = "0.9.112" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82cab2d520aa75e3c58898289429321eb788c3106963d0dc886ec7a5f4adc321" +checksum = "57d55af3b3e226502be1526dfdba67ab0e9c96fc293004e79576b2b9edb0dbdb" dependencies = [ "cc", "libc", @@ -4219,6 +4323,12 @@ version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" +[[package]] +name = "pastey" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" + [[package]] name = "pbkdf2" version = "0.11.0" @@ -4275,12 +4385,13 @@ dependencies = [ [[package]] name = "petgraph" -version = "0.7.1" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3672b37090dbd86368a4145bc067582552b29c27377cad4e0a306c97f9bd7772" +checksum = "8701b58ea97060d5e5b155d383a69952a60943f0e6dfe30b04c287beb0b27455" dependencies = [ "fixedbitset", - "indexmap 2.12.1", + "hashbrown 0.15.2", + "indexmap 2.13.0", ] [[package]] @@ -4296,13 +4407,13 @@ dependencies = [ "base64 0.21.7", "bincode", "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.1", "bs58 0.4.0", "byteorder", "bytes", "cadence", "cadence-macros", - "clap 4.5.53", + "clap 4.6.0", "cloud-storage", "dirs 5.0.1", "function_name", @@ -4333,7 +4444,7 @@ dependencies = [ "num_enum", "once_cell", "rand 0.8.5", - "reqwest 0.12.24", + "reqwest 0.12.28", "rstest", "rust-s3", "sea-orm", @@ -4341,15 +4452,15 @@ dependencies = [ "serde", "serde_json", "serial_test", - "solana-account 3.2.0", - "solana-bn254 3.1.2", + "solana-account 3.4.0", + "solana-bn254 3.2.1", "solana-client", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-commitment-config", - "solana-program-option 3.0.0", - "solana-program-pack 3.0.0", + "solana-program-option 3.0.1", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-transaction", "solana-transaction-status", "spl-token-interface", @@ -4367,29 +4478,29 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.10" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "pin-project-lite" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pin-utils" @@ -4399,9 +4510,9 @@ checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" [[package]] name = "pinocchio" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b971851087bc3699b001954ad02389d50c41405ece3548cbcafc88b3e20017a" +checksum = "b8afe4f39c0e25cc471b35b89963312791a5162d45a86578cbeaad9e5e7d1b3b" [[package]] name = "pinocchio-pubkey" @@ -4416,9 +4527,9 @@ dependencies = [ [[package]] name = "piper" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +checksum = "c835479a4443ded371d6c535cbfd8d31ad92c5d23ae9770a61bc155e4992a3c1" dependencies = [ "atomic-waker", "fastrand", @@ -4441,6 +4552,12 @@ version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +[[package]] +name = "plain" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" + [[package]] name = "polling" version = "3.11.0" @@ -4469,9 +4586,9 @@ dependencies = [ [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" [[package]] name = "potential_utf" @@ -4504,7 +4621,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -4528,11 +4645,11 @@ dependencies = [ [[package]] name = "proc-macro-crate" -version = "3.4.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.23.7", + "toml_edit 0.25.5+spec-1.1.0", ] [[package]] @@ -4561,18 +4678,18 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.103" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] [[package]] name = "prost" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7231bd9b3d3d33c86b58adbac74b5ec0ad9f496b19d22801d773636feaa95f3d" +checksum = "d2ea70524a2f82d518bce41317d0fae74151505651af45faf1ffbd6fd33f0568" dependencies = [ "bytes", "prost-derive", @@ -4580,15 +4697,14 @@ dependencies = [ [[package]] name = "prost-build" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac6c3320f9abac597dcbc668774ef006702672474aad53c6d596b62e487b40b1" +checksum = "343d3bd7056eda839b03204e68deff7d1b13aba7af2b2fd16890697274262ee7" dependencies = [ "heck 0.5.0", "itertools 0.14.0", "log", "multimap", - "once_cell", "petgraph", "prettyplease", "prost", @@ -4596,28 +4712,28 @@ dependencies = [ "pulldown-cmark", "pulldown-cmark-to-cmark", "regex", - "syn 2.0.110", + "syn 2.0.117", "tempfile", ] [[package]] name = "prost-derive" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9120690fafc389a67ba3803df527d0ec9cbbc9cc45e4cc20b332996dfb672425" +checksum = "27c6023962132f4b30eb4c172c91ce92d933da334c59c23cddee82358ddafb0b" dependencies = [ "anyhow", "itertools 0.14.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "prost-types" -version = "0.14.1" +version = "0.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9b4db3d6da204ed77bb26ba83b6122a73aeb2e87e25fbf7ad2e84c4ccbf8f72" +checksum = "8991c4cbdb8bc5b11f0b074ffe286c30e523de90fee5ba8132f1399f23cb3dd7" dependencies = [ "prost", ] @@ -4653,20 +4769,20 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.13.0" +version = "0.13.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e8bbe1a966bd2f362681a44f6edce3c2310ac21e4d5067a6e7ec396297a6ea0" +checksum = "83c41efbf8f90ac44de7f3a868f0867851d261b56291732d0cbf7cceaaeb55a6" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "memchr", "unicase", ] [[package]] name = "pulldown-cmark-to-cmark" -version = "21.1.0" +version = "22.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8246feae3db61428fd0bb94285c690b460e4517d83152377543ca802357785f1" +checksum = "50793def1b900256624a709439404384204a5dc3a6ec580281bfaac35e882e90" dependencies = [ "pulldown-cmark", ] @@ -4717,9 +4833,9 @@ dependencies = [ "quinn-proto", "quinn-udp", "rustc-hash 2.1.1", - "rustls 0.23.35", - "socket2 0.6.1", - "thiserror 2.0.17", + "rustls 0.23.37", + "socket2 0.6.3", + "thiserror 2.0.18", "tokio", "tracing", "web-time", @@ -4727,22 +4843,20 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.11.13" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1906b49b0c3bc04b5fe5d86a77925ae6524a19b816ae38ce1e426255f1d8a31" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", - "fastbloom", "getrandom 0.3.4", "lru-slab", "rand 0.9.2", "ring 0.17.14", "rustc-hash 2.1.1", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-pki-types", - "rustls-platform-verifier", "slab", - "thiserror 2.0.17", + "thiserror 2.0.18", "tinyvec", "tracing", "web-time", @@ -4757,16 +4871,16 @@ dependencies = [ "cfg_aliases", "libc", "once_cell", - "socket2 0.6.1", + "socket2 0.6.3", "tracing", "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.42" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] @@ -4777,6 +4891,12 @@ version = "5.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" +[[package]] +name = "r-efi" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" + [[package]] name = "radium" version = "0.7.0" @@ -4814,7 +4934,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db2770f06117d490610c7488547d543617b21bfa07796d7a12f6f1bd53850d1" dependencies = [ "rand_chacha 0.9.0", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4844,7 +4964,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ "ppv-lite86", - "rand_core 0.9.3", + "rand_core 0.9.5", ] [[package]] @@ -4862,14 +4982,14 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", ] [[package]] name = "rand_core" -version = "0.9.3" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99d9a13982dcf210057a8a78572b2217b667c3beacbf3a0d8b454f6f82837d38" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" dependencies = [ "getrandom 0.3.4", ] @@ -4889,7 +5009,7 @@ version = "11.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", ] [[package]] @@ -4927,7 +5047,16 @@ version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce70a74e890531977d37e532c34d45e9055d2409ed08ddba14529471ed0be16" +dependencies = [ + "bitflags 2.11.0", ] [[package]] @@ -4936,16 +5065,16 @@ version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ba009ff324d1fc1b900bd1fdb31564febe58a8ccc8a6fdbb93b543d33b13ca43" dependencies = [ - "getrandom 0.2.16", + "getrandom 0.2.17", "libredox", "thiserror 1.0.69", ] [[package]] name = "regex" -version = "1.12.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -4955,9 +5084,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.13" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -4966,9 +5095,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.8" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "relative-path" @@ -5029,19 +5158,18 @@ dependencies = [ [[package]] name = "reqwest" -version = "0.12.24" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d0946410b9f7b082a427e4ef5c8ff541a88b357bc6c637c40db3a68ac70a36f" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "async-compression 0.4.33", "base64 0.22.1", "bytes", "encoding_rs", "futures-channel", "futures-core", "futures-util", - "h2 0.4.12", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -5055,7 +5183,7 @@ dependencies = [ "percent-encoding", "pin-project-lite", "quinn", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-pki-types", "serde", "serde_json", @@ -5065,15 +5193,15 @@ dependencies = [ "tokio-native-tls", "tokio-rustls 0.26.4", "tokio-util", - "tower 0.5.2", - "tower-http 0.6.6", + "tower 0.5.3", + "tower-http 0.6.8", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "wasm-streams", "web-sys", - "webpki-roots 1.0.4", + "webpki-roots 1.0.6", ] [[package]] @@ -5084,8 +5212,8 @@ checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" dependencies = [ "anyhow", "async-trait", - "http 1.3.1", - "reqwest 0.12.24", + "http 1.4.0", + "reqwest 0.12.28", "serde", "thiserror 1.0.69", "tower-service", @@ -5114,7 +5242,7 @@ checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", "cfg-if", - "getrandom 0.2.16", + "getrandom 0.2.17", "libc", "untrusted 0.9.0", "windows-sys 0.52.0", @@ -5122,9 +5250,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9008cd6385b9e161d8229e1f6549dd23c3d022f132a2ea37ac3a10ac4935779b" +checksum = "2297bf9c81a3f0dc96bc9521370b88f054168c29826a75e89c55ff196e7ed6a1" dependencies = [ "bitvec", "bytecheck", @@ -5140,9 +5268,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.7.45" +version = "0.7.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "503d1d27590a2b0a3a4ca4c94755aa2875657196ecbf401a42eff41d7de532c0" +checksum = "84d7b42d4b8d06048d3ac8db0eb31bcb942cbeb709f0b5f2b2ebde398d3038f5" dependencies = [ "proc-macro2", "quote", @@ -5174,7 +5302,7 @@ dependencies = [ "regex", "relative-path", "rustc_version", - "syn 2.0.110", + "syn 2.0.117", "unicode-ident", ] @@ -5227,12 +5355,12 @@ dependencies = [ [[package]] name = "rust_decimal" -version = "1.39.0" +version = "1.40.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "35affe401787a9bd846712274d97654355d21b2a2c092a3139aabe31e9022282" +checksum = "61f703d19852dbf87cbc513643fa81428361eb6940f1ac14fd58155d295a3eb0" dependencies = [ "arrayvec", - "borsh 1.5.7", + "borsh 1.6.1", "bytes", "num-traits", "rand 0.8.5", @@ -5243,9 +5371,9 @@ dependencies = [ [[package]] name = "rustc-demangle" -version = "0.1.26" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" @@ -5279,11 +5407,11 @@ dependencies = [ [[package]] name = "rustix" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd15f8a2c5551a84d56efdc1cd049089e409ac19a3072d5037a17fd70719ff3e" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "errno", "libc", "linux-raw-sys", @@ -5304,9 +5432,9 @@ dependencies = [ [[package]] name = "rustls" -version = "0.23.35" +version = "0.23.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "533f54bc6a7d4f647e46ad909549eda97bf5afc1585190ef692b4286b198bd8f" +checksum = "758025cb5fccfd3bc2fd74708fd4682be41d99e5dff73c377c0646c6012c73a4" dependencies = [ "log", "once_cell", @@ -5319,14 +5447,14 @@ dependencies = [ [[package]] name = "rustls-native-certs" -version = "0.8.2" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9980d917ebb0c0536119ba501e90834767bffc3d60641457fd84a1f3fd337923" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", "rustls-pki-types", "schannel", - "security-framework 3.5.1", + "security-framework", ] [[package]] @@ -5340,9 +5468,9 @@ dependencies = [ [[package]] name = "rustls-pki-types" -version = "1.13.0" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94182ad936a0c91c324cd46c6511b9510ed16af436d7b5bab34beab0afd55f7a" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ "web-time", "zeroize", @@ -5359,11 +5487,11 @@ dependencies = [ "jni", "log", "once_cell", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-native-certs", "rustls-platform-verifier-android", "rustls-webpki", - "security-framework 3.5.1", + "security-framework", "security-framework-sys", "webpki-root-certs", "windows-sys 0.61.2", @@ -5377,9 +5505,9 @@ checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" [[package]] name = "rustls-webpki" -version = "0.103.8" +version = "0.103.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ffdfa2f5286e2247234e03f680868ac2815974dc39e00ea15adc445d0aafe52" +checksum = "d7df23109aa6c1567d1c575b9952556388da57401e4ace1d15f79eedad0d8f53" dependencies = [ "ring 0.17.14", "rustls-pki-types", @@ -5411,9 +5539,9 @@ checksum = "22a197350ece202f19a166d1ad6d9d6de145e1d2a8ef47db299abe164dbd7530" [[package]] name = "ryu" -version = "1.0.20" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -5426,9 +5554,9 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.28" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "891d81b926048e76efe18581bf793546b4c0eaf8448d72be8de2bbee5fd166e1" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ "windows-sys 0.61.2", ] @@ -5617,24 +5745,11 @@ checksum = "1c107b6f4780854c8b126e228ea8869f4d7b71260f962fefb57b996b8959ba6b" [[package]] name = "security-framework" -version = "2.11.1" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "897b2245f0b511c87893af39b033e5ca9cce68824c4d7e7630b5a1d339658d02" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 2.10.0", - "core-foundation 0.9.4", - "core-foundation-sys", - "libc", - "security-framework-sys", -] - -[[package]] -name = "security-framework" -version = "3.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b3297343eaf830f66ede390ea39da1d462b6b0c1b000f420d0a83f898bbbe6ef" -dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.10.1", "core-foundation-sys", "libc", @@ -5643,9 +5758,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.15.0" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc1f0cbffaac4852523ce30d8bd3c5cdc873501d96ff467ca09b6767bb8cd5c0" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -5703,20 +5818,20 @@ checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "serde_json" -version = "1.0.145" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "402a6f66d8c709116cf22f558eab210f5a50187f702eb4d7e5ef38d9a7f1c79c" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", "serde", "serde_core", + "zmij", ] [[package]] @@ -5733,9 +5848,9 @@ dependencies = [ [[package]] name = "serde_with" -version = "3.16.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10574371d41b0d9b2cff89418eda27da52bcaff2cc8741db26382a77c29131f1" +checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" dependencies = [ "serde_core", "serde_with_macros", @@ -5743,14 +5858,14 @@ dependencies = [ [[package]] name = "serde_with_macros" -version = "3.16.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08a72d8216842fdd57820dc78d840bef99248e35fb2554ff923319e60f2d686b" +checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" dependencies = [ - "darling", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -5759,7 +5874,7 @@ version = "0.9.34+deprecated" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "itoa", "ryu", "serde", @@ -5788,7 +5903,7 @@ checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -5872,10 +5987,11 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signal-hook-registry" -version = "1.4.6" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -5890,9 +6006,9 @@ dependencies = [ [[package]] name = "simd-adler32" -version = "0.3.7" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d66dc143e6b11c1eddc06d5c423cfc97062865baf299914ab64caa38182078fe" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" [[package]] name = "simdutf8" @@ -5919,27 +6035,27 @@ dependencies = [ [[package]] name = "simple_asn1" -version = "0.6.3" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "297f631f50729c8c99b84667867963997ec0b50f32b2a7dbcab828ef0541e8bb" +checksum = "0d585997b0ac10be3c5ee635f1bab02d512760d14b7c468801ac8a01d9ae5f1d" dependencies = [ "num-bigint 0.4.6", "num-traits", - "thiserror 2.0.17", + "thiserror 2.0.18", "time", ] [[package]] name = "siphasher" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" [[package]] name = "slab" -version = "0.4.11" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a2ae44ef20feb57a68b23d846850f861394c2e02dc425a50098ae8c90267589" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" @@ -5970,12 +6086,12 @@ dependencies = [ [[package]] name = "socket2" -version = "0.6.1" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17129e116933cf371d018bb80ae557e889637989d8638274fb25622827b03881" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.60.2", + "windows-sys 0.61.2", ] [[package]] @@ -6001,7 +6117,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" dependencies = [ "solana-account-info 2.3.0", - "solana-clock 2.2.2", + "solana-clock 2.2.3", "solana-instruction 2.3.3", "solana-pubkey 2.4.0", "solana-sdk-ids 2.2.1", @@ -6009,27 +6125,27 @@ dependencies = [ [[package]] name = "solana-account" -version = "3.2.0" +version = "3.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "014dcb9293341241dd153b35f89ea906e4170914f4a347a95e7fb07ade47cd6f" +checksum = "efc0ed36decb689413b9da5d57f2be49eea5bebb3cf7897015167b0c4336e731" dependencies = [ "bincode", "serde", "serde_bytes", "serde_derive", "solana-account-info 3.1.0", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-instruction-error", - "solana-pubkey 3.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids 3.1.0", - "solana-sysvar 3.1.0", + "solana-sysvar 3.1.1", ] [[package]] name = "solana-account-decoder" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5aae985e56861992eb615aa0bcc84275ad3a83f3b56c33033c5bce8edb7740c6" +checksum = "57fcc1c9e2a2d82c9aa09e0d34940b6c5a43c2fd5eea38c7caed0f6b177e27a8" dependencies = [ "Inflector", "base64 0.22.1", @@ -6038,46 +6154,46 @@ dependencies = [ "bv", "serde", "serde_json", - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-account-decoder-client-types", - "solana-address-lookup-table-interface 3.0.0", - "solana-clock 3.0.0", + "solana-address-lookup-table-interface 3.0.1", + "solana-clock 3.0.1", "solana-config-interface", "solana-epoch-schedule 3.0.0", - "solana-fee-calculator 3.0.0", - "solana-instruction 3.1.0", + "solana-fee-calculator 3.1.0", + "solana-instruction 3.2.0", "solana-loader-v3-interface 6.1.0", - "solana-nonce 3.0.0", - "solana-program-option 3.0.0", - "solana-program-pack 3.0.0", + "solana-nonce 3.1.0", + "solana-program-option 3.0.1", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", - "solana-rent 3.0.0", + "solana-rent 3.1.0", "solana-sdk-ids 3.1.0", - "solana-slot-hashes 3.0.0", + "solana-slot-hashes 3.0.1", "solana-slot-history 3.0.0", - "solana-stake-interface 2.0.1", - "solana-sysvar 3.1.0", + "solana-stake-interface 2.0.2", + "solana-sysvar 3.1.1", "solana-vote-interface 4.0.4", "spl-generic-token", "spl-token-2022-interface", "spl-token-group-interface 0.7.1", "spl-token-interface", "spl-token-metadata-interface 0.8.0", - "thiserror 2.0.17", + "thiserror 2.0.18", "zstd", ] [[package]] name = "solana-account-decoder-client-types" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81aff309863e7083b95a6552e76f0b3c7ef73b640dc061b69a69f3b2c946cd98" +checksum = "43e62ffb8742a71d3e8b5263ba892cdc65b24b063fa5b5f414205350b031a730" dependencies = [ "base64 0.22.1", "bs58 0.5.1", "serde", "serde_json", - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-pubkey 3.0.0", "zstd", ] @@ -6101,7 +6217,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.3.0", "solana-program-error 3.0.0", "solana-program-memory 3.1.0", ] @@ -6112,16 +6228,16 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.3.0", ] [[package]] name = "solana-address" -version = "2.0.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e37320fd2945c5d654b2c6210624a52d66c3f1f73b653ed211ab91a703b35bdd" +checksum = "500b83d41bda401b84ebff6033e2e7bc828870ea444805112d15fc0a3e470b9c" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "bytemuck", "bytemuck_derive", "curve25519-dalek", @@ -6129,11 +6245,13 @@ dependencies = [ "five8_const 1.0.0", "serde", "serde_derive", - "solana-atomic-u64 3.0.0", - "solana-define-syscall 4.0.1", + "sha2-const-stable", + "solana-atomic-u64 3.0.1", + "solana-define-syscall 5.0.0", "solana-program-error 3.0.0", "solana-sanitize 3.0.1", "solana-sha256-hasher 3.1.0", + "wincode", ] [[package]] @@ -6146,7 +6264,7 @@ dependencies = [ "bytemuck", "serde", "serde_derive", - "solana-clock 2.2.2", + "solana-clock 2.2.3", "solana-instruction 2.3.3", "solana-pubkey 2.4.0", "solana-sdk-ids 2.2.1", @@ -6155,20 +6273,20 @@ dependencies = [ [[package]] name = "solana-address-lookup-table-interface" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2f56cac5e70517a2f27d05e5100b20de7182473ffd0035b23ea273307905987" +checksum = "5e8df0b083c10ce32490410f3795016b1b5d9b4d094658c0a5e496753645b7cd" dependencies = [ "bincode", "bytemuck", "serde", "serde_derive", - "solana-clock 3.0.0", - "solana-instruction 3.1.0", + "solana-clock 3.0.1", + "solana-instruction 3.2.0", "solana-instruction-error", - "solana-pubkey 3.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids 3.1.0", - "solana-slot-hashes 3.0.0", + "solana-slot-hashes 3.0.1", ] [[package]] @@ -6182,9 +6300,9 @@ dependencies = [ [[package]] name = "solana-atomic-u64" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a933ff1e50aff72d02173cfcd7511bd8540b027ee720b75f353f594f834216d0" +checksum = "085db4906d89324cef2a30840d59eaecf3d4231c560ec7c9f6614a93c652f501" dependencies = [ "parking_lot 0.12.5", ] @@ -6235,22 +6353,22 @@ dependencies = [ "ark-serialize 0.4.2", "bytemuck", "solana-define-syscall 2.3.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "solana-bn254" -version = "3.1.2" +version = "3.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d08583be08d2d5f19aa21efbb6fbdb968ba7fd0de74562441437a7d776772bf" +checksum = "62ff13a8867fcc7b0f1114764e1bf6191b4551dcaf93729ddc676cd4ec6abc9f" dependencies = [ - "ark-bn254 0.4.0", - "ark-ec 0.4.2", - "ark-ff 0.4.2", - "ark-serialize 0.4.2", + "ark-bn254 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", "bytemuck", - "solana-define-syscall 3.0.0", - "thiserror 2.0.17", + "solana-define-syscall 5.0.0", + "thiserror 2.0.18", ] [[package]] @@ -6260,44 +6378,44 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" dependencies = [ "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.1", ] [[package]] name = "solana-borsh" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc402b16657abbfa9991cd5cbfac5a11d809f7e7d28d3bb291baeb088b39060e" +checksum = "be4a37fc44f0633779a619840b5117c2a895996cec57eb3dc10597fac7867875" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", ] [[package]] name = "solana-client" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c3cdae0844cd6c656def9f3b353045035acd83f46f939a5304bb128a1befe1a" +checksum = "56cdbbecbda755254a0c11010472a53036ff6fccdf5d7e908b92c95f04ff2497" dependencies = [ + "anza-quinn", "async-trait", "bincode", "dashmap", "futures", "futures-util", - "indexmap 2.12.1", + "indexmap 2.13.0", "indicatif", "log", - "quinn", "rayon", - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-client-traits", "solana-commitment-config", "solana-connection-cache", "solana-epoch-info", "solana-hash 3.1.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-keypair", "solana-measure", - "solana-message 3.0.1", + "solana-message 3.1.0", "solana-net-utils", "solana-pubkey 3.0.0", "solana-pubsub-client", @@ -6306,16 +6424,16 @@ dependencies = [ "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-signer 3.0.0", "solana-streamer", "solana-time-utils", "solana-tpu-client", "solana-transaction", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-udp-client", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", ] @@ -6326,26 +6444,26 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08618ed587e128105510c54ae3e456b9a06d674d8640db75afe66dad65cb4e02" dependencies = [ - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-commitment-config", "solana-epoch-info", "solana-hash 3.1.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-keypair", - "solana-message 3.0.1", + "solana-message 3.1.0", "solana-pubkey 3.0.0", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-signer 3.0.0", "solana-system-interface 2.0.0", "solana-transaction", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", ] [[package]] name = "solana-clock" -version = "2.2.2" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bb482ab70fced82ad3d7d3d87be33d466a3498eb8aa856434ff3c0dfc2e2e31" +checksum = "f8584296123df8fe229b95e2ebfd37ae637fe9db9b7d4dd677ac5a78e80dbfce" dependencies = [ "serde", "serde_derive", @@ -6356,31 +6474,31 @@ dependencies = [ [[package]] name = "solana-clock" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" +checksum = "95cf11109c3b6115cc510f1e31f06fdd52f504271bc24ef5f1249fbbcae5f9f3" dependencies = [ "serde", "serde_derive", "solana-sdk-ids 3.1.0", - "solana-sdk-macro 3.0.0", + "solana-sdk-macro 3.0.1", "solana-sysvar-id 3.1.0", ] [[package]] name = "solana-cluster-type" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7692fa6bf10a1a86b450c4775526f56d7e0e2116a53313f2533b5694abea64" +checksum = "3a494cf8eda7d98d9f0144b288bb409c88308d2e86f15cc1045aa77b83304718" dependencies = [ - "solana-hash 3.1.0", + "solana-hash 4.2.0", ] [[package]] name = "solana-commitment-config" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2e41a3917076a8b5375809078ae3a6fb76a53e364b596ef8c4265e7f410876f3" +checksum = "1517aa49dcfa9cb793ef90e7aac81346d62ca4a546bb1a754030a033e3972e1c" dependencies = [ "serde", "serde_derive", @@ -6395,25 +6513,25 @@ dependencies = [ "bincode", "serde", "serde_derive", - "solana-account 3.2.0", - "solana-instruction 3.1.0", + "solana-account 3.4.0", + "solana-instruction 3.2.0", "solana-pubkey 3.0.0", "solana-sdk-ids 3.1.0", - "solana-short-vec 3.1.0", + "solana-short-vec 3.2.0", "solana-system-interface 2.0.0", ] [[package]] name = "solana-connection-cache" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c105365f6d26b218788d21b9bfcdcec6e149cc9c53c36c76fb1afd39aada614f" +checksum = "efbacf3640794251ba0efa0bc13fbbaeac90f0e02c15dd723da1b7fec058f3b2" dependencies = [ "async-trait", "bincode", "crossbeam-channel", "futures-util", - "indexmap 2.12.1", + "indexmap 2.13.0", "log", "rand 0.8.5", "rayon", @@ -6421,8 +6539,8 @@ dependencies = [ "solana-measure", "solana-metrics", "solana-time-utils", - "solana-transaction-error 3.0.0", - "thiserror 2.0.17", + "solana-transaction-error 3.1.0", + "thiserror 2.0.18", "tokio", ] @@ -6448,10 +6566,10 @@ checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" dependencies = [ "solana-account-info 3.1.0", "solana-define-syscall 4.0.1", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-program-error 3.0.0", - "solana-pubkey 4.0.0", - "solana-stable-layout 3.0.0", + "solana-pubkey 4.1.0", + "solana-stable-layout 3.0.1", ] [[package]] @@ -6465,21 +6583,21 @@ dependencies = [ "curve25519-dalek", "solana-define-syscall 2.3.0", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "solana-curve25519" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "134f67bd3031223df4aba035c503e4d14acacfc4cf19af10d10ec9c2605bb84f" +checksum = "f3d7e1177e6006823b91e0a930d94992ed74f8a6327d54ee50a9457ff72e625a" dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek", "solana-define-syscall 3.0.0", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -6509,6 +6627,12 @@ version = "4.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" +[[package]] +name = "solana-define-syscall" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "03aacdd7a61e2109887a7a7f046caebafce97ddf1150f33722eeac04f9039c73" + [[package]] name = "solana-derivation-path" version = "2.2.1" @@ -6557,15 +6681,15 @@ dependencies = [ [[package]] name = "solana-epoch-rewards" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" +checksum = "f5e7b0ba210593ba8ddd39d6d234d81795d1671cebf3026baa10d5dc23ac42f0" dependencies = [ "serde", "serde_derive", - "solana-hash 3.1.0", + "solana-hash 4.2.0", "solana-sdk-ids 3.1.0", - "solana-sdk-macro 3.0.0", + "solana-sdk-macro 3.0.1", "solana-sysvar-id 3.1.0", ] @@ -6591,7 +6715,7 @@ dependencies = [ "serde", "serde_derive", "solana-sdk-ids 3.1.0", - "solana-sdk-macro 3.0.0", + "solana-sdk-macro 3.0.1", "solana-sysvar-id 3.1.0", ] @@ -6604,7 +6728,7 @@ dependencies = [ "serde", "serde_derive", "solana-address-lookup-table-interface 2.2.2", - "solana-clock 2.2.2", + "solana-clock 2.2.3", "solana-hash 2.3.0", "solana-instruction 2.3.3", "solana-keccak-hasher", @@ -6613,7 +6737,7 @@ dependencies = [ "solana-pubkey 2.4.0", "solana-sdk-ids 2.2.1", "solana-system-interface 1.0.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -6637,14 +6761,14 @@ dependencies = [ [[package]] name = "solana-feature-gate-interface" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7347ab62e6d47a82e340c865133795b394feea7c2b2771d293f57691c6544c3f" +checksum = "75ca9b5cbb6f500f7fd73db5bd95640f71a83f04d6121a0e59a43b202dca2731" dependencies = [ "serde", "serde_derive", "solana-program-error 3.0.0", - "solana-pubkey 3.0.0", + "solana-pubkey 4.1.0", "solana-sdk-ids 3.1.0", ] @@ -6661,9 +6785,9 @@ dependencies = [ [[package]] name = "solana-fee-calculator" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a73cc03ca4bed871ca174558108835f8323e85917bb38b9c81c7af2ab853efe" +checksum = "4b2a5675b2cf8d407c672dc1776492b1f382337720ddf566645ae43237a3d8c3" dependencies = [ "log", "serde", @@ -6676,7 +6800,7 @@ version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "bytemuck", "bytemuck_derive", "five8 0.2.1", @@ -6694,23 +6818,24 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" dependencies = [ - "solana-hash 4.0.1", + "solana-hash 4.2.0", ] [[package]] name = "solana-hash" -version = "4.0.1" +version = "4.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6a5d48a6ee7b91fc7b998944ab026ed7b3e2fc8ee3bc58452644a86c2648152f" +checksum = "8064ea1d591ec791be95245058ca40f4f5345d390c200069d0f79bbf55bfae55" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "bytemuck", "bytemuck_derive", "five8 1.0.0", "serde", "serde_derive", - "solana-atomic-u64 3.0.0", + "solana-atomic-u64 3.0.1", "solana-sanitize 3.0.1", + "wincode", ] [[package]] @@ -6726,8 +6851,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bab5682934bd1f65f8d2c16f21cb532526fcc1a09f796e2cacdb091eee5774ad" dependencies = [ "bincode", - "borsh 1.5.7", - "getrandom 0.2.16", + "borsh 1.6.1", + "getrandom 0.2.17", "js-sys", "num-traits", "serde", @@ -6740,24 +6865,24 @@ dependencies = [ [[package]] name = "solana-instruction" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee1b699a2c1518028a9982e255e0eca10c44d90006542d9d7f9f40dbce3f7c78" +checksum = "c6a6d22d0a6fdf345be294bb9afdcd40c296cdc095e64e7ceaa3bb3c2f608c1c" dependencies = [ "bincode", - "borsh 1.5.7", + "borsh 1.6.1", "serde", "serde_derive", - "solana-define-syscall 4.0.1", + "solana-define-syscall 5.0.0", "solana-instruction-error", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] name = "solana-instruction-error" -version = "2.1.0" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b04259e03c05faf38a8c24217b5cfe4c90572ae6184ab49cddb1584fdd756d3f" +checksum = "7d3d048edaaeef5a3dc8c01853e585539a74417e4c2d43a9e2c161270045b838" dependencies = [ "num-traits", "serde", @@ -6771,7 +6896,7 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "solana-account-info 2.3.0", "solana-instruction 2.3.3", "solana-program-error 2.2.2", @@ -6788,15 +6913,15 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "solana-account-info 3.1.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-instruction-error", "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "solana-sanitize 3.0.1", "solana-sdk-ids 3.1.0", - "solana-serialize-utils 3.1.0", + "solana-serialize-utils 3.1.1", "solana-sysvar-id 3.1.0", ] @@ -6814,16 +6939,17 @@ dependencies = [ [[package]] name = "solana-keypair" -version = "3.1.0" +version = "3.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ac8be597c9e231b0cab2928ce3bc3e4ee77d9c0ad92977b9d901f3879f25a7a" +checksum = "263d614c12aa267a3278703175fd6440552ca61bc960b5a02a4482720c53438b" dependencies = [ "ed25519-dalek", "five8 1.0.0", - "rand 0.8.5", - "solana-address 2.0.0", + "five8_core 1.0.0", + "rand 0.9.2", + "solana-address 2.3.0", "solana-seed-phrase 3.0.0", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-signer 3.0.0", ] @@ -6849,7 +6975,7 @@ dependencies = [ "serde", "serde_derive", "solana-sdk-ids 3.1.0", - "solana-sdk-macro 3.0.0", + "solana-sdk-macro 3.0.1", "solana-sysvar-id 3.1.0", ] @@ -6876,7 +7002,7 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-pubkey 3.0.0", "solana-sdk-ids 3.1.0", ] @@ -6905,7 +7031,7 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-pubkey 3.0.0", "solana-sdk-ids 3.1.0", "solana-system-interface 2.0.0", @@ -6928,9 +7054,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f96102f7c7c9f21cba06453b2274a55f279f5c4a0201ddef63df940db9c7bf61" +checksum = "1ee6df5d71fbc041b3badfd014753b76c643f5fcb9bba2498aae2a30d40616d0" [[package]] name = "solana-message" @@ -6957,38 +7083,38 @@ dependencies = [ [[package]] name = "solana-message" -version = "3.0.1" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85666605c9fd727f865ed381665db0a8fc29f984a030ecc1e40f43bfb2541623" +checksum = "0448b1fd891c5f46491e5dc7d9986385ba3c852c340db2911dd29faa01d2b08d" dependencies = [ "bincode", "blake3", "lazy_static", "serde", "serde_derive", - "solana-address 1.1.0", - "solana-hash 3.1.0", - "solana-instruction 3.1.0", + "solana-address 2.3.0", + "solana-hash 4.2.0", + "solana-instruction 3.2.0", "solana-sanitize 3.0.1", "solana-sdk-ids 3.1.0", - "solana-short-vec 3.1.0", - "solana-transaction-error 3.0.0", + "solana-short-vec 3.2.0", + "solana-transaction-error 3.1.0", ] [[package]] name = "solana-metrics" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6aabf25b3b0eb42d2bd6aee7b9c7a345975212a135781de42b3164978b28df0" +checksum = "bb0f05dfe08e1b14429eb35feb15f89455d7c75d8a1704ee8da1f0ebf0993d42" dependencies = [ "crossbeam-channel", "gethostname", "log", - "reqwest 0.12.24", + "reqwest 0.12.28", "solana-cluster-type", "solana-sha256-hasher 3.1.0", "solana-time-utils", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -7002,11 +7128,11 @@ dependencies = [ [[package]] name = "solana-msg" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "264275c556ea7e22b9d3f87d56305546a38d4eee8ec884f3b126236cb7dcbbb4" +checksum = "726b7cbbc6be6f1c6f29146ac824343b9415133eee8cce156452ad1db93f8008" dependencies = [ - "solana-define-syscall 3.0.0", + "solana-define-syscall 5.0.0", ] [[package]] @@ -7017,9 +7143,9 @@ checksum = "61515b880c36974053dd499c0510066783f0cc6ac17def0c7ef2a244874cf4a9" [[package]] name = "solana-net-utils" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24116f6bd91038a99b79701d452eadd6f0dfb445311380658ab082491ea716c4" +checksum = "5ed12c06e326edff1a26380f18b01d1c9ec4723aeed2c0d6dec1035d9eacb1fa" dependencies = [ "anyhow", "bincode", @@ -7031,7 +7157,7 @@ dependencies = [ "nix", "rand 0.8.5", "serde", - "socket2 0.6.1", + "socket2 0.6.3", "solana-serde", "solana-svm-type-overrides", "tokio", @@ -7054,15 +7180,15 @@ dependencies = [ [[package]] name = "solana-nonce" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "abbdc6c8caf1c08db9f36a50967539d0f72b9f1d4aea04fec5430f532e5afadc" +checksum = "cbc469152a63284ef959b80c59cda015262a021da55d3b8fe42171d89c4b64f8" dependencies = [ "serde", "serde_derive", - "solana-fee-calculator 3.0.0", - "solana-hash 3.1.0", - "solana-pubkey 3.0.0", + "solana-fee-calculator 3.1.0", + "solana-hash 4.2.0", + "solana-pubkey 4.1.0", "solana-sha256-hasher 3.1.0", ] @@ -7082,7 +7208,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6edf2f25743c95229ac0fdc32f8f5893ef738dbf332c669e9861d33ddb0f469d" dependencies = [ "bincode", - "bitflags 2.10.0", + "bitflags 2.11.0", "cfg_eval", "serde", "serde_derive", @@ -7091,9 +7217,9 @@ dependencies = [ [[package]] name = "solana-perf" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "853368b085bfbf1775dec3d4cce628a7c045218a84f2e235469906cd8e1478f4" +checksum = "cae20efb5ec6c98b3932d6755d5df962ab51344f099d704317a79af2faa42403" dependencies = [ "ahash 0.8.12", "bincode", @@ -7110,14 +7236,14 @@ dependencies = [ "rayon", "serde", "solana-hash 3.1.0", - "solana-message 3.0.1", + "solana-message 3.1.0", "solana-metrics", "solana-packet", "solana-pubkey 3.0.0", "solana-rayon-threadlimit", "solana-sdk-ids 3.1.0", - "solana-short-vec 3.1.0", - "solana-signature 3.1.0", + "solana-short-vec 3.2.0", + "solana-signature 3.3.0", "solana-time-utils", "solana-transaction-context", ] @@ -7131,12 +7257,12 @@ dependencies = [ "bincode", "blake3", "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.1", "bs58 0.5.1", "bytemuck", "console_error_panic_hook", "console_log", - "getrandom 0.2.16", + "getrandom 0.2.17", "lazy_static", "log", "memoffset", @@ -7154,7 +7280,7 @@ dependencies = [ "solana-bincode", "solana-blake3-hasher", "solana-borsh 2.2.1", - "solana-clock 2.2.2", + "solana-clock 2.2.3", "solana-cpi 2.2.1", "solana-decode-error", "solana-define-syscall 2.3.0", @@ -7198,7 +7324,7 @@ dependencies = [ "solana-sysvar 2.3.0", "solana-sysvar-id 2.2.1", "solana-vote-interface 2.2.6", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasm-bindgen", ] @@ -7223,7 +7349,7 @@ dependencies = [ "solana-account-info 3.1.0", "solana-define-syscall 4.0.1", "solana-program-error 3.0.0", - "solana-pubkey 4.0.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -7232,7 +7358,7 @@ version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "num-traits", "serde", "serde_derive", @@ -7248,7 +7374,7 @@ version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", ] [[package]] @@ -7277,9 +7403,9 @@ checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" [[package]] name = "solana-program-option" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e7b4ddb464f274deb4a497712664c3b612e3f5f82471d4e47710fc4ab1c3095" +checksum = "362279f6e8020e4cf11313233789bf619420ad8835ebc91963ee5cec91bb05da" [[package]] name = "solana-program-pack" @@ -7292,9 +7418,9 @@ dependencies = [ [[package]] name = "solana-program-pack" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c169359de21f6034a63ebf96d6b380980307df17a8d371344ff04a883ec4e9d0" +checksum = "3d7701cb15b90667ae1c89ef4ac35a59c61e66ce58ddee13d729472af7f41d59" dependencies = [ "solana-program-error 3.0.0", ] @@ -7306,13 +7432,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" dependencies = [ "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.1", "bytemuck", "bytemuck_derive", "curve25519-dalek", "five8 0.2.1", "five8_const 0.1.4", - "getrandom 0.2.16", + "getrandom 0.2.17", "js-sys", "num-traits", "serde", @@ -7336,18 +7462,18 @@ dependencies = [ [[package]] name = "solana-pubkey" -version = "4.0.0" +version = "4.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6f7104d456b58e1418c21a8581e89810278d1190f70f27ece7fc0b2c9282a57" +checksum = "1b06bd918d60111ee1f97de817113e2040ca0cedb740099ee8d646233f6b906c" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.3.0", ] [[package]] name = "solana-pubsub-client" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06c39e4d0918c573095cb5c004aa6e915e0af76ff9cc7e33f97dc1df52bdfeb7" +checksum = "320923e8c430d05c515f2f413dee50afa0da421b4fe37dc4b76fd9f28b7409a7" dependencies = [ "crossbeam-channel", "futures-util", @@ -7357,11 +7483,11 @@ dependencies = [ "serde", "serde_json", "solana-account-decoder-client-types", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-pubkey 3.0.0", "solana-rpc-client-types", - "solana-signature 3.1.0", - "thiserror 2.0.17", + "solana-signature 3.3.0", + "thiserror 2.0.18", "tokio", "tokio-stream", "tokio-tungstenite", @@ -7371,18 +7497,18 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02ed60f78f9a56f67b059edf34b2a4a1afd1eaf165402be9dc511581a7ec569f" +checksum = "4ede9c4da2447500b05c2fdc8b238c703b33943604a927dc197733bc91ac2a1f" dependencies = [ + "anza-quinn", + "anza-quinn-proto", "async-lock", "async-trait", "futures", "itertools 0.12.1", "log", - "quinn", - "quinn-proto", - "rustls 0.23.35", + "rustls 0.23.37", "solana-connection-cache", "solana-keypair", "solana-measure", @@ -7394,8 +7520,8 @@ dependencies = [ "solana-signer 3.0.0", "solana-streamer", "solana-tls-utils", - "solana-transaction-error 3.0.0", - "thiserror 2.0.17", + "solana-transaction-error 3.1.0", + "thiserror 2.0.18", "tokio", ] @@ -7410,9 +7536,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19142fd63c774e0b4b3a25098f68683128db44bc7d86986400b98d8544417385" +checksum = "09d48133891ea0e717d845059429b98d03bab34f3ec4e2b58bfe78248a898017" dependencies = [ "log", "num_cpus", @@ -7433,14 +7559,14 @@ dependencies = [ [[package]] name = "solana-rent" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b702d8c43711e3c8a9284a4f1bbc6a3de2553deb25b0c8142f9a44ef0ce5ddc1" +checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" dependencies = [ "serde", "serde_derive", "solana-sdk-ids 3.1.0", - "solana-sdk-macro 3.0.0", + "solana-sdk-macro 3.0.1", "solana-sysvar-id 3.1.0", ] @@ -7456,9 +7582,9 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ee9e21cb2a6b56ebe30ed4730c367018ead598a3a7a99fcc4bbb29681ff9670" +checksum = "29f7447f65aacd7ef752393bec2a9082d0313983b804f92d06fe72caf44e8cd6" dependencies = [ "async-trait", "base64 0.22.1", @@ -7467,27 +7593,27 @@ dependencies = [ "futures", "indicatif", "log", - "reqwest 0.12.24", + "reqwest 0.12.28", "reqwest-middleware", "semver", "serde", "serde_json", - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-account-decoder", "solana-account-decoder-client-types", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-commitment-config", "solana-epoch-info", "solana-epoch-schedule 3.0.0", - "solana-feature-gate-interface 3.0.0", + "solana-feature-gate-interface 3.1.0", "solana-hash 3.1.0", - "solana-instruction 3.1.0", - "solana-message 3.0.1", + "solana-instruction 3.2.0", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client-api", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-transaction", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-version", "solana-vote-interface 4.0.4", @@ -7496,67 +7622,67 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ce31a0c56989efe7bf05f03303c44f8cd67788c7c5ace5352270a414d715dd3" +checksum = "841d953ce18f99a07c8101e071dd54d2a99b80835ad2ea1566913c55d4bce2ef" dependencies = [ "anyhow", "jsonrpc-core", - "reqwest 0.12.24", + "reqwest 0.12.28", "reqwest-middleware", "serde", "serde_json", "solana-account-decoder-client-types", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-rpc-client-types", "solana-signer 3.0.0", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ede5005bd6f29d131fdaeae736348b5c6dc238a4be42550ade03d27d32ebf676" +checksum = "b0e7777237c3791d40039ab1274d346949497f9be48cd688717ff001cb740cf9" dependencies = [ - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-commitment-config", "solana-hash 3.1.0", - "solana-message 3.0.1", - "solana-nonce 3.0.0", + "solana-message 3.1.0", + "solana-nonce 3.1.0", "solana-pubkey 3.0.0", "solana-rpc-client", "solana-sdk-ids 3.1.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "solana-rpc-client-types" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1d9dda2ecfac8ab5835a8b42b08605d0696a9deb28ad3269db4d8f9dbaf31ef" +checksum = "095c430a4ff4ddb10b7399f8d3d26eafeaccb84f8802568594f6f5941c60dff5" dependencies = [ "base64 0.22.1", "bs58 0.5.1", "semver", "serde", "serde_json", - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-account-decoder-client-types", "solana-address 1.1.0", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-commitment-config", - "solana-fee-calculator 3.0.0", + "solana-fee-calculator 3.1.0", "solana-inflation", "solana-reward-info", "solana-transaction", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-version", "spl-generic-token", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -7582,7 +7708,7 @@ dependencies = [ "hash32", "log", "rustc-demangle", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -7600,7 +7726,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.3.0", ] [[package]] @@ -7612,19 +7738,19 @@ dependencies = [ "bs58 0.5.1", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "solana-sdk-macro" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" +checksum = "8765316242300c48242d84a41614cb3388229ec353ba464f6fe62a733e41806f" dependencies = [ "bs58 0.5.1", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -7635,7 +7761,7 @@ checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" dependencies = [ "libsecp256k1", "solana-define-syscall 2.3.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -7707,9 +7833,9 @@ dependencies = [ [[package]] name = "solana-serde-varint" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e5174c57d5ff3c1995f274d17156964664566e2cde18a07bba1586d35a70d3b" +checksum = "950e5b83e839dc0f92c66afc124bb8f40e89bc90f0579e8ec5499296d27f54e3" dependencies = [ "serde", ] @@ -7727,12 +7853,12 @@ dependencies = [ [[package]] name = "solana-serialize-utils" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56e41dd8feea239516c623a02f0a81c2367f4b604d7965237fed0751aeec33ed" +checksum = "5d7cc401931d178472358e6b78dc72d031dc08f752d7410f0e8bd259dd6f02fa" dependencies = [ "solana-instruction-error", - "solana-pubkey 3.0.0", + "solana-pubkey 4.1.0", "solana-sanitize 3.0.1", ] @@ -7755,7 +7881,7 @@ checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" dependencies = [ "sha2 0.10.9", "solana-define-syscall 4.0.1", - "solana-hash 4.0.1", + "solana-hash 4.2.0", ] [[package]] @@ -7769,9 +7895,9 @@ dependencies = [ [[package]] name = "solana-short-vec" -version = "3.1.0" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79fb1809a32cfcf7d9c47b7070a92fa17cdb620ab5829e9a8a9ff9d138a7a175" +checksum = "de3bd991c2cc415291c86bb0b6b4d53e93d13bb40344e4c5a2884e0e4f5fa93f" dependencies = [ "serde_core", ] @@ -7788,16 +7914,17 @@ dependencies = [ [[package]] name = "solana-signature" -version = "3.1.0" +version = "3.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bb8057cc0e9f7b5e89883d49de6f407df655bb6f3a71d0b7baf9986a2218fd9" +checksum = "132a93134f1262aa832f1849b83bec6c9945669b866da18661a427943b9e801e" dependencies = [ "ed25519-dalek", - "five8 0.2.1", + "five8 1.0.0", "serde", "serde-big-array", "serde_derive", "solana-sanitize 3.0.1", + "wincode", ] [[package]] @@ -7818,8 +7945,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" dependencies = [ "solana-pubkey 3.0.0", - "solana-signature 3.1.0", - "solana-transaction-error 3.0.0", + "solana-signature 3.3.0", + "solana-transaction-error 3.1.0", ] [[package]] @@ -7837,13 +7964,13 @@ dependencies = [ [[package]] name = "solana-slot-hashes" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" +checksum = "2585f70191623887329dfb5078da3a00e15e3980ea67f42c2e10b07028419f43" dependencies = [ "serde", "serde_derive", - "solana-hash 3.1.0", + "solana-hash 4.2.0", "solana-sdk-ids 3.1.0", "solana-sysvar-id 3.1.0", ] @@ -7886,12 +8013,12 @@ dependencies = [ [[package]] name = "solana-stable-layout" -version = "3.0.0" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" +checksum = "c9f6a291ba063a37780af29e7db14bdd3dc447584d8ba5b3fc4b88e2bbc982fa" dependencies = [ - "solana-instruction 3.1.0", - "solana-pubkey 3.0.0", + "solana-instruction 3.2.0", + "solana-pubkey 4.1.0", ] [[package]] @@ -7901,11 +8028,11 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" dependencies = [ "borsh 0.10.4", - "borsh 1.5.7", + "borsh 1.6.1", "num-traits", "serde", "serde_derive", - "solana-clock 2.2.2", + "solana-clock 2.2.3", "solana-cpi 2.2.1", "solana-decode-error", "solana-instruction 2.3.3", @@ -7917,29 +8044,31 @@ dependencies = [ [[package]] name = "solana-stake-interface" -version = "2.0.1" +version = "2.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f6f912ae679b683365348dea482dbd9468d22ff258b554fd36e3d3683c2122e3" +checksum = "b9bc26191b533f9a6e5a14cca05174119819ced680a80febff2f5051a713f0db" dependencies = [ "num-traits", "serde", "serde_derive", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-cpi 3.1.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "solana-system-interface 2.0.0", - "solana-sysvar 3.1.0", + "solana-sysvar 3.1.1", "solana-sysvar-id 3.1.0", ] [[package]] name = "solana-streamer" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3b8157f227922e5a5ba31569dea9759432fe276f20182ce0ce3ee6f5275e0e8" +checksum = "e9c9d1d759bb2d08119e45dcb0ff6834038086cc7b2d1f4e279f2ac340d77bce" dependencies = [ + "anza-quinn", + "anza-quinn-proto", "arc-swap", "bytes", "crossbeam-channel", @@ -7948,7 +8077,7 @@ dependencies = [ "futures-util", "governor", "histogram", - "indexmap 2.12.1", + "indexmap 2.13.0", "itertools 0.12.1", "libc", "log", @@ -7956,12 +8085,10 @@ dependencies = [ "num_cpus", "pem 1.1.1", "percentage", - "quinn", - "quinn-proto", "rand 0.8.5", - "rustls 0.23.35", + "rustls 0.23.37", "smallvec", - "socket2 0.6.1", + "socket2 0.6.3", "solana-keypair", "solana-measure", "solana-metrics", @@ -7970,13 +8097,13 @@ dependencies = [ "solana-perf", "solana-pubkey 3.0.0", "solana-quic-definitions", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-signer 3.0.0", "solana-time-utils", "solana-tls-utils", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", "solana-transaction-metrics-tracker", - "thiserror 2.0.17", + "thiserror 2.0.18", "tokio", "tokio-util", "x509-parser", @@ -7984,15 +8111,15 @@ dependencies = [ [[package]] name = "solana-svm-feature-set" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d848a90245dbaffeb8c43492eb902c2b988200a1b59b3959435d17abcea3eb3d" +checksum = "62a20c4fc8d409780c4592c17ac3e01b6f3dc949e6ffd3acbda6d2a21e67b53a" [[package]] name = "solana-svm-type-overrides" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cddcdb9981c7838ceb16bb97929c5cab015b0bdcb12243720000f8e44c9a5af2" +checksum = "51b2ea7c2f849cd6d190e2607c2af779d3dad2792784cc13c0e9342e429c87a1" dependencies = [ "rand 0.8.5", ] @@ -8022,8 +8149,8 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-instruction 3.1.0", - "solana-msg 3.0.0", + "solana-instruction 3.2.0", + "solana-msg 3.1.0", "solana-program-error 3.0.0", "solana-pubkey 3.0.0", ] @@ -8042,7 +8169,7 @@ dependencies = [ "serde", "serde_derive", "solana-account-info 2.3.0", - "solana-clock 2.2.2", + "solana-clock 2.2.3", "solana-define-syscall 2.3.0", "solana-epoch-rewards 2.2.1", "solana-epoch-schedule 2.2.1", @@ -8067,9 +8194,9 @@ dependencies = [ [[package]] name = "solana-sysvar" -version = "3.1.0" +version = "3.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3205cc7db64a0f1a20b7eb2405773fa64e45f7fe0fc7a73e50e90eca6b2b0be7" +checksum = "6690d3dd88f15c21edff68eb391ef8800df7a1f5cec84ee3e8d1abf05affdf74" dependencies = [ "base64 0.22.1", "bincode", @@ -8077,22 +8204,22 @@ dependencies = [ "serde", "serde_derive", "solana-account-info 3.1.0", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-define-syscall 4.0.1", - "solana-epoch-rewards 3.0.0", + "solana-epoch-rewards 3.0.1", "solana-epoch-schedule 3.0.0", - "solana-fee-calculator 3.0.0", - "solana-hash 4.0.1", - "solana-instruction 3.1.0", + "solana-fee-calculator 3.1.0", + "solana-hash 4.2.0", + "solana-instruction 3.2.0", "solana-last-restart-slot 3.0.0", "solana-program-entrypoint 3.1.1", "solana-program-error 3.0.0", "solana-program-memory 3.1.0", - "solana-pubkey 4.0.0", - "solana-rent 3.0.0", + "solana-pubkey 4.1.0", + "solana-rent 3.1.0", "solana-sdk-ids 3.1.0", - "solana-sdk-macro 3.0.0", - "solana-slot-hashes 3.0.0", + "solana-sdk-macro 3.0.1", + "solana-slot-hashes 3.0.1", "solana-slot-history 3.0.0", "solana-sysvar-id 3.1.0", ] @@ -8113,7 +8240,7 @@ version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" dependencies = [ - "solana-address 2.0.0", + "solana-address 2.3.0", "solana-sdk-ids 3.1.0", ] @@ -8125,11 +8252,11 @@ checksum = "0ced92c60aa76ec4780a9d93f3bd64dfa916e1b998eacc6f1c110f3f444f02c9" [[package]] name = "solana-tls-utils" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f31ba4cf689b1adfd392370de1998bb5d8cdcd07c11efa8e08aa2dabeac7be7" +checksum = "05b5c952335b378c92ad47286a7dee28acfd0b0ce1ac89562f51b4dcb33210ea" dependencies = [ - "rustls 0.23.35", + "rustls 0.23.37", "solana-keypair", "solana-pubkey 3.0.0", "solana-signer 3.0.0", @@ -8138,73 +8265,73 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b618992d02477c0300e89ad2fe0d109bcd2a20392f2c11c106d9f208a2124682" +checksum = "d331918bac33058ac2acd923c4cf646a8b7bc77fd7463d886da9f24b9e2787c1" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 2.12.1", + "indexmap 2.13.0", "indicatif", "log", "rayon", "solana-client-traits", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-commitment-config", "solana-connection-cache", "solana-epoch-schedule 3.0.0", "solana-measure", - "solana-message 3.0.1", + "solana-message 3.1.0", "solana-net-utils", "solana-pubkey 3.0.0", "solana-pubsub-client", "solana-quic-definitions", "solana-rpc-client", "solana-rpc-client-api", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-signer 3.0.0", "solana-transaction", - "solana-transaction-error 3.0.0", - "thiserror 2.0.17", + "solana-transaction-error 3.1.0", + "thiserror 2.0.18", "tokio", ] [[package]] name = "solana-transaction" -version = "3.0.2" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ceb2efbf427a91b884709ffac4dac29117752ce1e37e9ae04977e450aa0bb76" +checksum = "96697cff5075a028265324255efed226099f6d761ca67342b230d09f72cc48d2" dependencies = [ "bincode", "serde", "serde_derive", - "solana-address 2.0.0", - "solana-hash 4.0.1", - "solana-instruction 3.1.0", + "solana-address 2.3.0", + "solana-hash 4.2.0", + "solana-instruction 3.2.0", "solana-instruction-error", - "solana-message 3.0.1", + "solana-message 3.1.0", "solana-sanitize 3.0.1", "solana-sdk-ids 3.1.0", - "solana-short-vec 3.1.0", - "solana-signature 3.1.0", + "solana-short-vec 3.2.0", + "solana-signature 3.3.0", "solana-signer 3.0.0", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", ] [[package]] name = "solana-transaction-context" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bd55fe81fbc36ee00fde8233764b1f60c141e93a069932f126b707a515b8199" +checksum = "be7c191d89fb883fef0b4bb4225121f7ad14eb5664d5dc9707b4af661e21924c" dependencies = [ "bincode", "serde", - "solana-account 3.2.0", - "solana-instruction 3.1.0", + "solana-account 3.4.0", + "solana-instruction 3.2.0", "solana-instructions-sysvar 3.0.0", "solana-pubkey 3.0.0", - "solana-rent 3.0.0", + "solana-rent 3.1.0", "solana-sbpf", "solana-sdk-ids 3.1.0", ] @@ -8221,9 +8348,9 @@ dependencies = [ [[package]] name = "solana-transaction-error" -version = "3.0.0" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4222065402340d7e6aec9dc3e54d22992ddcf923d91edcd815443c2bfca3144a" +checksum = "8396904805b0b385b9de115a652fe80fd01e5b98ce0513f4fcd8184ada9bb792" dependencies = [ "serde", "serde_derive", @@ -8233,9 +8360,9 @@ dependencies = [ [[package]] name = "solana-transaction-metrics-tracker" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2255338b7be49a8d49009771daca0391c76a0cf18f8053cb411bf304302c063" +checksum = "257ae75d68fe879753baef265a0d1bfcf9274b212dfc44ffea177ce0f1271508" dependencies = [ "base64 0.22.1", "bincode", @@ -8243,42 +8370,42 @@ dependencies = [ "rand 0.8.5", "solana-packet", "solana-perf", - "solana-short-vec 3.1.0", - "solana-signature 3.1.0", + "solana-short-vec 3.2.0", + "solana-signature 3.3.0", ] [[package]] name = "solana-transaction-status" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6cd9bfed22fcef7bd3c5a2ddde81eeeb1f300df73a6f11366d27621333da80c" +checksum = "81283f595988fccb91f1697addde2efd074aea4e7b2853e4415e06a8754ff8ee" dependencies = [ "Inflector", "agave-reserved-account-keys", "base64 0.22.1", "bincode", - "borsh 1.5.7", + "borsh 1.6.1", "bs58 0.5.1", "log", "serde", "serde_json", "solana-account-decoder", - "solana-address-lookup-table-interface 3.0.0", - "solana-clock 3.0.0", + "solana-address-lookup-table-interface 3.0.1", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-loader-v2-interface 3.0.0", "solana-loader-v3-interface 6.1.0", - "solana-message 3.0.1", - "solana-program-option 3.0.0", + "solana-message 3.1.0", + "solana-program-option 3.0.1", "solana-pubkey 3.0.0", "solana-reward-info", "solana-sdk-ids 3.1.0", - "solana-signature 3.1.0", - "solana-stake-interface 2.0.1", + "solana-signature 3.3.0", + "solana-stake-interface 2.0.2", "solana-system-interface 2.0.0", "solana-transaction", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", "solana-transaction-status-client-types", "solana-vote-interface 4.0.4", "spl-associated-token-account-interface", @@ -8287,14 +8414,14 @@ dependencies = [ "spl-token-group-interface 0.7.1", "spl-token-interface", "spl-token-metadata-interface 0.8.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "solana-transaction-status-client-types" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3a1d4fd9ba4f6a301bb4dae9411bfab458e1b3ba66c3a6bc7333a14d35ca5d9" +checksum = "3a02265337e99bf3e446de1d8133b2d28556f06780e9ab516870317688f332e0" dependencies = [ "base64 0.22.1", "bincode", @@ -8303,45 +8430,45 @@ dependencies = [ "serde_json", "solana-account-decoder-client-types", "solana-commitment-config", - "solana-instruction 3.1.0", - "solana-message 3.0.1", + "solana-instruction 3.2.0", + "solana-message 3.1.0", "solana-pubkey 3.0.0", "solana-reward-info", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-transaction", "solana-transaction-context", - "solana-transaction-error 3.0.0", - "thiserror 2.0.17", + "solana-transaction-error 3.1.0", + "thiserror 2.0.18", ] [[package]] name = "solana-udp-client" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8de6ebded5eca0efa5ff2246a3599c3b1f9da20a01bb171668d502c733e8208" +checksum = "3f55aab86699ab277347e7086157a1a7c599ce3817c0a8bb07b62bbe3a113f44" dependencies = [ "async-trait", "solana-connection-cache", "solana-keypair", "solana-net-utils", "solana-streamer", - "solana-transaction-error 3.0.0", - "thiserror 2.0.17", + "solana-transaction-error 3.1.0", + "thiserror 2.0.18", "tokio", ] [[package]] name = "solana-version" -version = "3.1.1" +version = "3.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d40d18d0807743a5fbd8f6c328d39cfb9bdcd63d196b9d168efdbfe27447315e" +checksum = "17a9c5d23a31d8f34aac59812099c9d8d76203a447d04b65824f5c913ced9072" dependencies = [ "agave-feature-set", "rand 0.8.5", "semver", "serde", "solana-sanitize 3.0.1", - "solana-serde-varint 3.0.0", + "solana-serde-varint 3.0.1", ] [[package]] @@ -8355,7 +8482,7 @@ dependencies = [ "num-traits", "serde", "serde_derive", - "solana-clock 2.2.2", + "solana-clock 2.2.3", "solana-decode-error", "solana-hash 2.3.0", "solana-instruction 2.3.3", @@ -8381,16 +8508,16 @@ dependencies = [ "serde", "serde_derive", "serde_with", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-instruction-error", "solana-pubkey 3.0.0", - "solana-rent 3.0.0", + "solana-rent 3.1.0", "solana-sdk-ids 3.1.0", - "solana-serde-varint 3.0.0", - "solana-serialize-utils 3.1.0", - "solana-short-vec 3.1.0", + "solana-serde-varint 3.0.1", + "solana-serialize-utils 3.1.1", + "solana-short-vec 3.2.0", "solana-system-interface 2.0.0", ] @@ -8425,7 +8552,7 @@ dependencies = [ "solana-signature 2.3.0", "solana-signer 2.2.1", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasm-bindgen", "zeroize", ] @@ -8442,7 +8569,7 @@ dependencies = [ "bytemuck", "bytemuck_derive", "curve25519-dalek", - "getrandom 0.2.16", + "getrandom 0.2.17", "itertools 0.12.1", "js-sys", "merlin", @@ -8454,15 +8581,15 @@ dependencies = [ "serde_json", "sha3", "solana-derivation-path 3.0.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-pubkey 3.0.0", "solana-sdk-ids 3.1.0", "solana-seed-derivable 3.0.0", "solana-seed-phrase 3.0.0", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-signer 3.0.0", "subtle", - "thiserror 2.0.17", + "thiserror 2.0.18", "wasm-bindgen", "zeroize", ] @@ -8507,8 +8634,8 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e6433917b60441d68d99a17e121d9db0ea15a9a69c0e5afa34649cf5ba12612f" dependencies = [ - "borsh 1.5.7", - "solana-instruction 3.1.0", + "borsh 1.6.1", + "solana-instruction 3.2.0", "solana-pubkey 3.0.0", ] @@ -8544,7 +8671,7 @@ checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -8556,7 +8683,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.110", + "syn 2.0.117", "thiserror 1.0.69", ] @@ -8603,7 +8730,7 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d4e2aedd58f858337fa609af5ad7100d4a243fdaf6a40d6eb4c28c5f19505d3" dependencies = [ - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-pubkey 3.0.0", ] @@ -8613,7 +8740,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "bytemuck", "bytemuck_derive", "num-derive", @@ -8624,26 +8751,26 @@ dependencies = [ "solana-program-option 2.2.1", "solana-pubkey 2.4.0", "solana-zk-sdk 2.3.13", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] name = "spl-pod" -version = "0.7.1" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1233fdecd7461611d69bb87bc2e95af742df47291975d21232a0be8217da9de" +checksum = "d6f3df240f67bea453d4bc5749761e45436d14b9457ed667e0300555d5c271f3" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "bytemuck", "bytemuck_derive", "num-derive", "num-traits", "num_enum", "solana-program-error 3.0.0", - "solana-program-option 3.0.0", + "solana-program-option 3.0.1", "solana-pubkey 3.0.0", "solana-zk-sdk 4.0.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8668,7 +8795,7 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.9", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -8733,7 +8860,7 @@ dependencies = [ "spl-token-metadata-interface 0.6.0", "spl-transfer-hook-interface", "spl-type-length-value 0.7.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8748,20 +8875,20 @@ dependencies = [ "num-traits", "num_enum", "solana-account-info 3.1.0", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-program-error 3.0.0", - "solana-program-option 3.0.0", - "solana-program-pack 3.0.0", + "solana-program-option 3.0.1", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", "solana-sdk-ids 3.1.0", "solana-zk-sdk 4.0.0", - "spl-pod 0.7.1", + "spl-pod 0.7.2", "spl-token-confidential-transfer-proof-extraction 0.5.1", "spl-token-confidential-transfer-proof-generation 0.5.1", "spl-token-group-interface 0.7.1", "spl-token-metadata-interface 0.8.0", "spl-type-length-value 0.9.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8787,7 +8914,7 @@ dependencies = [ "solana-program", "solana-zk-sdk 2.3.13", "spl-pod 0.5.1", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8798,16 +8925,16 @@ checksum = "879a9ebad0d77383d3ea71e7de50503554961ff0f4ef6cbca39ad126e6f6da3a" dependencies = [ "bytemuck", "solana-account-info 3.1.0", - "solana-curve25519 3.1.1", - "solana-instruction 3.1.0", + "solana-curve25519 3.1.10", + "solana-instruction 3.2.0", "solana-instructions-sysvar 3.0.0", - "solana-msg 3.0.0", + "solana-msg 3.1.0", "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "solana-sdk-ids 3.1.0", "solana-zk-sdk 4.0.0", - "spl-pod 0.7.1", - "thiserror 2.0.17", + "spl-pod 0.7.2", + "thiserror 2.0.18", ] [[package]] @@ -8818,7 +8945,7 @@ checksum = "0e3597628b0d2fe94e7900fd17cdb4cfbb31ee35c66f82809d27d86e44b2848b" dependencies = [ "curve25519-dalek", "solana-zk-sdk 2.3.13", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8829,7 +8956,7 @@ checksum = "a0cd59fce3dc00f563c6fa364d67c3f200d278eae681f4dc250240afcfe044b1" dependencies = [ "curve25519-dalek", "solana-zk-sdk 4.0.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8861,12 +8988,12 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "spl-discriminator 0.5.1", - "spl-pod 0.7.1", - "thiserror 2.0.17", + "spl-pod 0.7.2", + "thiserror 2.0.18", ] [[package]] @@ -8880,13 +9007,13 @@ dependencies = [ "num-derive", "num-traits", "num_enum", - "solana-instruction 3.1.0", + "solana-instruction 3.2.0", "solana-program-error 3.0.0", - "solana-program-option 3.0.0", - "solana-program-pack 3.0.0", + "solana-program-option 3.0.1", + "solana-program-pack 3.1.0", "solana-pubkey 3.0.0", "solana-sdk-ids 3.1.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8895,7 +9022,7 @@ version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "num-derive", "num-traits", "solana-borsh 2.2.1", @@ -8916,17 +9043,17 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9c467c7c3bd056f8fe60119e7ec34ddd6f23052c2fa8f1f51999098063b72676" dependencies = [ - "borsh 1.5.7", + "borsh 1.6.1", "num-derive", "num-traits", - "solana-borsh 3.0.0", - "solana-instruction 3.1.0", + "solana-borsh 3.0.1", + "solana-instruction 3.2.0", "solana-program-error 3.0.0", "solana-pubkey 3.0.0", "spl-discriminator 0.5.1", - "spl-pod 0.7.1", + "spl-pod 0.7.2", "spl-type-length-value 0.9.0", - "thiserror 2.0.17", + "thiserror 2.0.18", ] [[package]] @@ -8983,11 +9110,11 @@ dependencies = [ "num-traits", "num_enum", "solana-account-info 3.1.0", - "solana-msg 3.0.0", + "solana-msg 3.1.0", "solana-program-error 3.0.0", "spl-discriminator 0.5.1", - "spl-pod 0.7.1", - "thiserror 2.0.17", + "spl-pod 0.7.2", + "thiserror 2.0.18", ] [[package]] @@ -9158,9 +9285,9 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.110" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", @@ -9202,7 +9329,7 @@ checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -9218,11 +9345,11 @@ dependencies = [ [[package]] name = "system-configuration" -version = "0.6.1" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c879d448e9d986b661742763247d3693ed13609438cf3d006f51f5368a5ba6b" +checksum = "a13f3d0daba03132c0aa9767f98351b3488edc2c100cda2d2ec2b04f3d8d3c8b" dependencies = [ - "bitflags 2.10.0", + "bitflags 2.11.0", "core-foundation 0.9.4", "system-configuration-sys 0.6.0", ] @@ -9255,12 +9382,12 @@ checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" [[package]] name = "tempfile" -version = "3.23.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2d31c77bdf42a745371d260a26ca7163f1e0924b64afa0b688e61b5a9fa02f16" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ "fastrand", - "getrandom 0.3.4", + "getrandom 0.4.2", "once_cell", "rustix", "windows-sys 0.61.2", @@ -9292,11 +9419,11 @@ dependencies = [ [[package]] name = "thiserror" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "thiserror-impl 2.0.17", + "thiserror-impl 2.0.18", ] [[package]] @@ -9307,18 +9434,18 @@ checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "2.0.17" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -9332,30 +9459,30 @@ dependencies = [ [[package]] name = "time" -version = "0.3.44" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e7d9e3bb61134e77bde20dd4825b97c010155709965fedf0f49bb138e52a9d" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.6" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "40868e7c1d2f0b8d73e4a8c7f0ff63af4f6d19be117e90bd73eb1d62cf831c6b" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.24" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30cfb0125f12d9c277f35663a0a33f8c30190f4e4574868a330595412d34ebf3" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ "num-conv", "time-core", @@ -9382,9 +9509,9 @@ dependencies = [ [[package]] name = "tinyvec" -version = "1.10.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -9397,9 +9524,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.48.0" +version = "1.50.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff360e02eab121e0bc37a2d3b4d4dc622e6eda3a8e5253d5435ecf5bd4c68408" +checksum = "27ad5e34374e03cfffefc301becb44e9dc3c17584f414349ebe29ed26661822d" dependencies = [ "bytes", "libc", @@ -9407,20 +9534,20 @@ dependencies = [ "parking_lot 0.12.5", "pin-project-lite", "signal-hook-registry", - "socket2 0.6.1", + "socket2 0.6.3", "tokio-macros", "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.6.0" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +checksum = "5c55a2eff8b69ce66c84f85e1da1c233edc36ceb85a2058d11b0d6a3c7e7569c" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -9450,15 +9577,15 @@ version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" dependencies = [ - "rustls 0.23.35", + "rustls 0.23.37", "tokio", ] [[package]] name = "tokio-stream" -version = "0.1.17" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eca58d7bba4a75707817a2c44174253f9236b2d5fbd055602e9d5c07c139a047" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -9474,7 +9601,7 @@ checksum = "d25a406cddcc431a75d3d9afc6a7c0f7428d4891dd973e4d54c56b46127bf857" dependencies = [ "futures-util", "log", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-pki-types", "tokio", "tokio-rustls 0.26.4", @@ -9484,9 +9611,9 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.17" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2efa149fe76073d6e8fd97ef4f4eca7b67f599660115591483572e406e165594" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", @@ -9514,9 +9641,9 @@ checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" [[package]] name = "toml_datetime" -version = "0.7.3" +version = "1.0.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cdb639ebbc97961c51720f858597f7f24c4fc295327923af55b74c3c724533" +checksum = "9b320e741db58cac564e26c607d3cc1fdc4a88fd36c879568c07856ed83ff3e9" dependencies = [ "serde_core", ] @@ -9527,45 +9654,45 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "toml_datetime 0.6.11", "winnow 0.5.40", ] [[package]] name = "toml_edit" -version = "0.23.7" +version = "0.25.5+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6485ef6d0d9b5d0ec17244ff7eb05310113c3f316f2d14200d4de56b3cb98f8d" +checksum = "8ca1a40644a28bce036923f6a431df0b34236949d111cc07cb6dca830c9ef2e1" dependencies = [ - "indexmap 2.12.1", - "toml_datetime 0.7.3", + "indexmap 2.13.0", + "toml_datetime 1.0.1+spec-1.1.0", "toml_parser", - "winnow 0.7.13", + "winnow 1.0.0", ] [[package]] name = "toml_parser" -version = "1.0.4" +version = "1.0.10+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0cbe268d35bdb4bb5a56a2de88d0ad0eb70af5384a99d648cd4b3d04039800e" +checksum = "7df25b4befd31c4816df190124375d5a20c6b6921e2cad937316de3fccd63420" dependencies = [ - "winnow 0.7.13", + "winnow 1.0.0", ] [[package]] name = "tonic" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb7613188ce9f7df5bfe185db26c5814347d110db17920415cf2fbcad85e7203" +checksum = "fec7c61a0695dc1887c1b53952990f3ad2e3a31453e1f49f10e75424943a93ec" dependencies = [ "async-trait", "axum", "base64 0.22.1", "bytes", "flate2", - "h2 0.4.12", - "http 1.3.1", + "h2 0.4.13", + "http 1.4.0", "http-body 1.0.1", "http-body-util", "hyper 1.8.1", @@ -9574,12 +9701,12 @@ dependencies = [ "percent-encoding", "pin-project", "rustls-native-certs", - "socket2 0.6.1", + "socket2 0.6.3", "sync_wrapper 1.0.2", "tokio", "tokio-rustls 0.26.4", "tokio-stream", - "tower 0.5.2", + "tower 0.5.3", "tower-layer", "tower-service", "tracing", @@ -9588,21 +9715,21 @@ dependencies = [ [[package]] name = "tonic-build" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c40aaccc9f9eccf2cd82ebc111adc13030d23e887244bc9cfa5d1d636049de3" +checksum = "1882ac3bf5ef12877d7ed57aad87e75154c11931c2ba7e6cde5e22d63522c734" dependencies = [ "prettyplease", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "tonic-health" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a82868bf299e0a1d2e8dce0dc33a46c02d6f045b2c1f1d6cc8dc3d0bf1812ef" +checksum = "f4ff0636fef47afb3ec02818f5bceb4377b8abb9d6a386aeade18bd6212f8eb7" dependencies = [ "prost", "tokio", @@ -9613,9 +9740,9 @@ dependencies = [ [[package]] name = "tonic-prost" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "66bd50ad6ce1252d87ef024b3d64fe4c3cf54a86fb9ef4c631fdd0ded7aeaa67" +checksum = "a55376a0bbaa4975a3f10d009ad763d8f4108f067c7c2e74f3001fb49778d309" dependencies = [ "bytes", "prost", @@ -9624,16 +9751,16 @@ dependencies = [ [[package]] name = "tonic-prost-build" -version = "0.14.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4a16cba4043dc3ff43fcb3f96b4c5c154c64cbd18ca8dce2ab2c6a451d058a2" +checksum = "f3144df636917574672e93d0f56d7edec49f90305749c668df5101751bb8f95a" dependencies = [ "prettyplease", "proc-macro2", "prost-build", "prost-types", "quote", - "syn 2.0.110", + "syn 2.0.117", "tempfile", "tonic-build", ] @@ -9661,13 +9788,13 @@ dependencies = [ [[package]] name = "tower" -version = "0.5.2" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d039ad9159c98b70ecfd540b2573b97f7f52c3e8d9f8ad57a24b916a536975f9" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" dependencies = [ "futures-core", "futures-util", - "indexmap 2.12.1", + "indexmap 2.13.0", "pin-project-lite", "slab", "sync_wrapper 1.0.2", @@ -9710,18 +9837,23 @@ dependencies = [ [[package]] name = "tower-http" -version = "0.6.6" +version = "0.6.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adc82fd73de2a9722ac5da747f12383d2bfdb93591ee6c58486e0097890f05f2" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" dependencies = [ - "bitflags 2.10.0", + "async-compression 0.4.41", + "bitflags 2.11.0", "bytes", + "futures-core", "futures-util", - "http 1.3.1", + "http 1.4.0", "http-body 1.0.1", - "iri-string 0.7.9", + "http-body-util", + "iri-string 0.7.10", "pin-project-lite", - "tower 0.5.2", + "tokio", + "tokio-util", + "tower 0.5.3", "tower-layer", "tower-service", ] @@ -9740,9 +9872,9 @@ checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.41" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "784e0ac535deb450455cbfa28a6f0df145ea1bb7ae51b821cf5e7927fdcfbdd0" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -9752,20 +9884,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.30" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "81383ab64e72a7a8b8e13130c49e3dab29def6d0c7d76a03087b3cf71c5c6903" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "tracing-core" -version = "0.1.34" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9d12581f227e93f094d3af2ae690a574abb8a2b9b7a96e7cfe9647b2b617678" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -9794,9 +9926,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.20" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2054a14f5307d601f88daf0553e1cbf472acc4f2c51afab632431cdcd72124d5" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "matchers", "nu-ansi-term", @@ -9827,14 +9959,14 @@ checksum = "8628dcc84e5a09eb3d8423d6cb682965dea9133204e8fb3efee74c2a0c259442" dependencies = [ "bytes", "data-encoding", - "http 1.3.1", + "http 1.4.0", "httparse", "log", "rand 0.9.2", - "rustls 0.23.35", + "rustls 0.23.37", "rustls-pki-types", "sha1", - "thiserror 2.0.17", + "thiserror 2.0.18", "utf-8", "webpki-roots 0.26.11", ] @@ -9847,9 +9979,9 @@ checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[package]] name = "unicase" -version = "2.8.1" +version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75b844d17643ee918803943289730bec8aac480150456169e647ed0b576ba539" +checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142" [[package]] name = "unicode-bidi" @@ -9859,9 +9991,9 @@ checksum = "5c1cb5db39152898a79168971543b1cb5020dff7fe43c8dc468b0885f5e29df5" [[package]] name = "unicode-ident" -version = "1.0.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-normalization" @@ -9957,9 +10089,9 @@ dependencies = [ [[package]] name = "url" -version = "2.5.7" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08bc136a29a3d1758e07a9cca267be308aeebf5cfd5a10f3f67ab2097683ef5b" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", @@ -9991,7 +10123,7 @@ version = "4.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c5afb1a60e207dca502682537fefcfd9921e71d0b83e9576060f09abc6efab23" dependencies = [ - "indexmap 2.12.1", + "indexmap 2.13.0", "serde", "serde_json", "serde_yaml", @@ -10007,18 +10139,18 @@ dependencies = [ "proc-macro-error", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] name = "uuid" -version = "1.18.1" +version = "1.22.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f87b8aa10b915a06587d0dec516c282ff295b475d94abf425d62b57710070a2" +checksum = "a68d3c8f01c0cfa54a75291d83601161799e4a89a39e0929f4b0354d88757a37" dependencies = [ - "getrandom 0.3.4", + "getrandom 0.4.2", "js-sys", - "serde", + "serde_core", "wasm-bindgen", ] @@ -10085,9 +10217,18 @@ checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] name = "wasip2" -version = "1.0.1+wasi-0.2.4" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" dependencies = [ "wit-bindgen", ] @@ -10100,9 +10241,9 @@ checksum = "b8dad83b4f25e74f184f64c43b150b91efe7647395b42289f38e50566d82855b" [[package]] name = "wasm-bindgen" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da95793dfc411fbbd93f5be7715b0578ec61fe87cb1a42b12eb625caa5c5ea60" +checksum = "6532f9a5c1ece3798cb1c2cfdba640b9b3ba884f5db45973a6f442510a87d38e" dependencies = [ "cfg-if", "once_cell", @@ -10113,11 +10254,12 @@ dependencies = [ [[package]] name = "wasm-bindgen-futures" -version = "0.4.55" +version = "0.4.64" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551f88106c6d5e7ccc7cd9a16f312dd3b5d36ea8b4954304657d5dfba115d4a0" +checksum = "e9c5522b3a28661442748e09d40924dfb9ca614b21c00d3fd135720e48b67db8" dependencies = [ "cfg-if", + "futures-util", "js-sys", "once_cell", "wasm-bindgen", @@ -10126,9 +10268,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04264334509e04a7bf8690f2384ef5265f05143a4bff3889ab7a3269adab59c2" +checksum = "18a2d50fcf105fb33bb15f00e7a77b772945a2ee45dcf454961fd843e74c18e6" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -10136,26 +10278,48 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "420bc339d9f322e562942d52e115d57e950d12d88983a14c79b86859ee6c7ebc" +checksum = "03ce4caeaac547cdf713d280eda22a730824dd11e6b8c3ca9e42247b25c631e3" dependencies = [ "bumpalo", "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.105" +version = "0.2.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76f218a38c84bcb33c25ec7059b07847d465ce0e0a76b995e134a45adcb6af76" +checksum = "75a326b8c223ee17883a4251907455a2431acc2791c98c26279376490c378c16" dependencies = [ "unicode-ident", ] +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap 2.13.0", + "wasm-encoder", + "wasmparser", +] + [[package]] name = "wasm-streams" version = "0.4.2" @@ -10169,11 +10333,23 @@ dependencies = [ "web-sys", ] +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.2", + "indexmap 2.13.0", + "semver", +] + [[package]] name = "web-sys" -version = "0.3.82" +version = "0.3.91" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3a1f95c0d03a47f4ae1f7a64643a6bb97465d9b740f0fa8f90ea33915c99a9a1" +checksum = "854ba17bb104abfb26ba36da9729addc7ce7f06f5c0f90f3c391f8461cca21f9" dependencies = [ "js-sys", "wasm-bindgen", @@ -10201,9 +10377,9 @@ dependencies = [ [[package]] name = "webpki-root-certs" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee3e3b5f5e80bc89f30ce8d0343bf4e5f12341c51f3e26cbeecbc7c85443e85b" +checksum = "804f18a4ac2676ffb4e8b5b5fa9ae38af06df08162314f96a68d2a363e21a8ca" dependencies = [ "rustls-pki-types", ] @@ -10223,14 +10399,14 @@ version = "0.26.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" dependencies = [ - "webpki-roots 1.0.4", + "webpki-roots 1.0.6", ] [[package]] name = "webpki-roots" -version = "1.0.4" +version = "1.0.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2878ef029c47c6e8cf779119f20fcf52bde7ad42a731b2a304bc221df17571e" +checksum = "22cfaf3c063993ff62e73cb4311efde4db1efb31ab78a3e5c457939ad5cc0bed" dependencies = [ "rustls-pki-types", ] @@ -10277,6 +10453,31 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wincode" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc91ddd8c932a38bbec58ed536d9e93ce9cd01b6af9b6de3c501132cf98ddec6" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.18", + "wincode-derive", +] + +[[package]] +name = "wincode-derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca057fc9a13dd19cdb64ef558635d43c42667c0afa1ae7915ea1fa66993fd1a" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-core" version = "0.62.2" @@ -10298,7 +10499,7 @@ checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -10309,7 +10510,7 @@ checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -10655,9 +10856,9 @@ dependencies = [ [[package]] name = "winnow" -version = "0.7.13" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" +checksum = "a90e88e4667264a994d34e6d1ab2d26d398dcdca8b7f52bec8668957517fc7d8" dependencies = [ "memchr", ] @@ -10674,9 +10875,91 @@ dependencies = [ [[package]] name = "wit-bindgen" -version = "0.46.0" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck 0.5.0", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck 0.5.0", + "indexmap 2.13.0", + "prettyplease", + "syn 2.0.117", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn 2.0.117", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap 2.13.0", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap 2.13.0", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] [[package]] name = "writeable" @@ -10713,13 +10996,13 @@ dependencies = [ [[package]] name = "yellowstone-grpc-client" -version = "10.1.1" +version = "10.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a79834bb0660b17e27c32c84778d661fb406f9fe382670ea628f01062b26ae1a" +checksum = "4e3475e3027f8832589b573fb5253a8c304532999b427d3d4c9de6f6912a7162" dependencies = [ "bytes", "futures", - "thiserror 2.0.17", + "thiserror 2.0.18", "tonic", "tonic-health", "yellowstone-grpc-proto", @@ -10736,16 +11019,16 @@ dependencies = [ "prost", "prost-types", "protobuf-src", - "solana-account 3.2.0", + "solana-account 3.4.0", "solana-account-decoder", - "solana-clock 3.0.0", + "solana-clock 3.0.1", "solana-hash 3.1.0", - "solana-message 3.0.1", + "solana-message 3.1.0", "solana-pubkey 3.0.0", - "solana-signature 3.1.0", + "solana-signature 3.3.0", "solana-transaction", "solana-transaction-context", - "solana-transaction-error 3.0.0", + "solana-transaction-error 3.1.0", "solana-transaction-status", "tonic", "tonic-build", @@ -10772,28 +11055,28 @@ checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", "synstructure 0.13.2", ] [[package]] name = "zerocopy" -version = "0.8.28" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43fa6694ed34d6e57407afbccdeecfa268c470a7d2a5b0cf49ce9fcc345afb90" +checksum = "f2578b716f8a7a858b7f02d5bd870c14bf4ddbbcf3a4c05414ba6503640505e3" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.8.28" +version = "0.8.42" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c640b22cd9817fae95be82f0d2f90b11f7605f6c319d16705c459b27ac2cbc26" +checksum = "7e6cc098ea4d3bd6246687de65af3f920c430e236bee1e3bf2e441463f08a02f" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -10813,7 +11096,7 @@ checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", "synstructure 0.13.2", ] @@ -10828,13 +11111,13 @@ dependencies = [ [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] [[package]] @@ -10867,9 +11150,15 @@ checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.110", + "syn 2.0.117", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + [[package]] name = "zstd" version = "0.13.3" diff --git a/Cargo.toml b/Cargo.toml index 22e8fa03..577f768e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,17 +91,17 @@ spl-token-interface = "2.0.0" light-zero-copy = { version = "0.6", default-features = false} -light-concurrent-merkle-tree = {version = "4", default-features = false } -light-batched-merkle-tree = { version = "0.10", default-features = false} -light-merkle-tree-metadata = { version = "0.10", default-features = false } -light-compressed-account = { version = "0.10.1", default-features = false } +light-concurrent-merkle-tree = {version = "5", default-features = false } +light-batched-merkle-tree = { version = "0.11", default-features = false} +light-merkle-tree-metadata = { version = "0.11", default-features = false } +light-compressed-account = { version = "0.11", default-features = false } light-hasher = { version = "5", features = ["poseidon", "keccak", "sha256"], default-features = false} light-poseidon = "0.4.0" -light-indexed-merkle-tree = { version = "4", default-features = false } -light-event = "0.21" +light-indexed-merkle-tree = { version = "5", default-features = false } +light-event = "0.23.1" -light-token-interface = "0.4" -light-sdk-types = "0.20" +light-token-interface = "0.5" +light-sdk-types = "0.23" sqlx = { version = "0.6.2", features = [ From 3f82b926be6717a07bd41aedb84b4d9e6b0ab0d3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Swen=20Sch=C3=A4ferjohann?= Date: Wed, 18 Mar 2026 17:48:17 +0000 Subject: [PATCH 03/16] replace buildjet with default gh runner (#338) --- .github/workflows/ci.yml | 2 +- .github/workflows/publish_crate.yaml | 2 +- .github/workflows/publish_dockerfile.yaml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 56c2e92e..fb41bfb1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ on: jobs: test: name: Run tests - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 services: postgres: image: postgres:16 diff --git a/.github/workflows/publish_crate.yaml b/.github/workflows/publish_crate.yaml index b5abe572..efbe9ee1 100644 --- a/.github/workflows/publish_crate.yaml +++ b/.github/workflows/publish_crate.yaml @@ -5,7 +5,7 @@ on: jobs: manual-job: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - name: Check out repository code uses: actions/checkout@v4 diff --git a/.github/workflows/publish_dockerfile.yaml b/.github/workflows/publish_dockerfile.yaml index 8dd3413e..4fb3aaf0 100644 --- a/.github/workflows/publish_dockerfile.yaml +++ b/.github/workflows/publish_dockerfile.yaml @@ -7,7 +7,7 @@ on: jobs: build: - runs-on: buildjet-16vcpu-ubuntu-2204 + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v3 # Count the number of commits on the current branch From 863c9b093f426becb9401e9ab88051676e9ee0f0 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Wed, 4 Mar 2026 19:21:23 +0000 Subject: [PATCH 04/16] feat: discover unknown trees during ingestion via RPC When the indexer encounters a tree not in tree_metadata during transaction parsing, fetch the tree's on-chain account via RPC, add it to tree_metadata, and proceed with indexing instead of skipping. This prevents data gaps for legitimate trees created after startup. --- src/api/method/get_validity_proof/prover/gnark.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/api/method/get_validity_proof/prover/gnark.rs b/src/api/method/get_validity_proof/prover/gnark.rs index e15dd53a..a7f4b23e 100644 --- a/src/api/method/get_validity_proof/prover/gnark.rs +++ b/src/api/method/get_validity_proof/prover/gnark.rs @@ -2,7 +2,7 @@ use crate::api::error::PhotonApiError; use crate::api::method::get_validity_proof::prover::structs::{CompressedProof, ProofABC}; use ark_serialize::{CanonicalDeserialize, CanonicalSerialize, Compress, Validate}; use solana_bn254::compression::prelude::{ - alt_bn128_g1_compress, alt_bn128_g2_compress, convert_endianness, + alt_bn128_g1_compress_be, alt_bn128_g2_compress_be, convert_endianness, }; use std::ops::Neg; @@ -31,11 +31,11 @@ pub fn negate_g1(g1_be: &[u8; 64]) -> Result<[u8; 64], PhotonApiError> { } pub fn compress_proof(proof: &ProofABC) -> Result { - let proof_a = alt_bn128_g1_compress(&proof.a) + let proof_a = alt_bn128_g1_compress_be(&proof.a) .map_err(|_| PhotonApiError::UnexpectedError("Failed to compress G1 proof".to_string()))?; - let proof_b = alt_bn128_g2_compress(&proof.b) + let proof_b = alt_bn128_g2_compress_be(&proof.b) .map_err(|_| PhotonApiError::UnexpectedError("Failed to compress G2 proof".to_string()))?; - let proof_c = alt_bn128_g1_compress(&proof.c) + let proof_c = alt_bn128_g1_compress_be(&proof.c) .map_err(|_| PhotonApiError::UnexpectedError("Failed to compress G1 proof".to_string()))?; Ok(CompressedProof { From b5e4080c8cbb14b83a82757efe0d95795e1dcf5a Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 3 Mar 2026 14:10:01 +0000 Subject: [PATCH 05/16] feat: infrastructure updates - migrations, ingester, prover API key, DAO schema, monitor, CLI args, dep updates - Add prover_api_key parameter to PhotonApi and validity proof methods - Add max_connections parameter to run_server - Add new migrations: onchain_pubkey, ata_owner, backfill_mint, ata_owner_index - Update ingester with startup cleanup, improved parsing, and persist logic - Update DAO generated models (accounts, token_accounts, queue_hash_chains, transactions) - Update monitor with queue monitoring and tree metadata sync improvements - Consolidate OpenAPI specs into single api.yaml - Fix OpenAPI AllOf handling and iterator usage - Update dependencies in Cargo.toml/Cargo.lock - Add token_layout module and update token_data types - Update snapshot loader/snapshotter and tree validator --- src/api/method/utils.rs | 6 + src/common/token_layout.rs | 5 + ...210_000001_backfill_mint_onchain_pubkey.rs | 131 ++++++++++++++++++ src/migration/migrations/standard/mod.rs | 2 + 4 files changed, 144 insertions(+) create mode 100644 src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs diff --git a/src/api/method/utils.rs b/src/api/method/utils.rs index 1cf78467..56240c5d 100644 --- a/src/api/method/utils.rs +++ b/src/api/method/utils.rs @@ -35,6 +35,12 @@ pub fn parse_decimal(value: Decimal) -> Result { .map_err(|_| PhotonApiError::UnexpectedError("Invalid decimal value".to_string())) } +pub fn parse_account_discriminator( + discriminator: Option, +) -> Result, PhotonApiError> { + discriminator.map(parse_decimal).transpose() +} + pub(crate) fn parse_leaf_index(leaf_index: i64) -> Result { leaf_index .try_into() diff --git a/src/common/token_layout.rs b/src/common/token_layout.rs index 3310bce5..e061f522 100644 --- a/src/common/token_layout.rs +++ b/src/common/token_layout.rs @@ -4,6 +4,8 @@ pub const SPL_TOKEN_ACCOUNT_BASE_LEN: usize = 165; /// Account type marker byte offset in token/mint account data. pub const TOKEN_ACCOUNT_TYPE_OFFSET: usize = SPL_TOKEN_ACCOUNT_BASE_LEN; +/// 1-indexed equivalent for SQL substring functions. +pub const TOKEN_ACCOUNT_TYPE_OFFSET_SQL: usize = TOKEN_ACCOUNT_TYPE_OFFSET + 1; /// AccountType::Mint discriminator value. pub const ACCOUNT_TYPE_MINT: u8 = 1; @@ -12,3 +14,6 @@ pub const ACCOUNT_TYPE_MINT: u8 = 1; pub const LIGHT_MINT_PDA_OFFSET: usize = 84; pub const LIGHT_MINT_PDA_LEN: usize = 32; pub const LIGHT_MINT_PDA_END: usize = LIGHT_MINT_PDA_OFFSET + LIGHT_MINT_PDA_LEN; +/// Aliases used by the backfill migration (SQL 1-indexed). +pub const COMPRESSED_MINT_PDA_OFFSET_SQL: usize = LIGHT_MINT_PDA_OFFSET + 1; +pub const COMPRESSED_MINT_PDA_LEN: usize = LIGHT_MINT_PDA_LEN; diff --git a/src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs b/src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs new file mode 100644 index 00000000..eb4e0474 --- /dev/null +++ b/src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs @@ -0,0 +1,131 @@ +use sea_orm_migration::{ + prelude::*, + sea_orm::{ConnectionTrait, DatabaseBackend, Statement}, +}; + +use crate::common::token_layout::{ + COMPRESSED_MINT_PDA_LEN, COMPRESSED_MINT_PDA_OFFSET_SQL, TOKEN_ACCOUNT_TYPE_OFFSET, + TOKEN_ACCOUNT_TYPE_OFFSET_SQL, +}; + +#[derive(DeriveMigrationName)] +pub struct Migration; + +/// Raw 32-byte pubkey for cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m +const LIGHT_TOKEN_PROGRAM_ID_HEX: &str = + "0915a35723794e8fb65d075b6b72699c38dd02e5948b75b0e5a0418e80975b44"; + +fn backfill_mint_onchain_pubkey_sql(backend: DatabaseBackend) -> Result { + match backend { + DatabaseBackend::Postgres => Ok(format!( + "UPDATE accounts \ + SET onchain_pubkey = substring(data from {COMPRESSED_MINT_PDA_OFFSET_SQL} for {COMPRESSED_MINT_PDA_LEN}) \ + WHERE onchain_pubkey IS NULL \ + AND spent = false \ + AND data IS NOT NULL \ + AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ + AND substring(data from {TOKEN_ACCOUNT_TYPE_OFFSET_SQL} for 1) = E'\\\\x01' \ + AND owner = E'\\\\x{LIGHT_TOKEN_PROGRAM_ID_HEX}'" + )), + DatabaseBackend::Sqlite => Ok(format!( + "UPDATE accounts \ + SET onchain_pubkey = substr(data, {COMPRESSED_MINT_PDA_OFFSET_SQL}, {COMPRESSED_MINT_PDA_LEN}) \ + WHERE onchain_pubkey IS NULL \ + AND spent = 0 \ + AND data IS NOT NULL \ + AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ + AND substr(data, {TOKEN_ACCOUNT_TYPE_OFFSET_SQL}, 1) = X'01' \ + AND owner = X'{LIGHT_TOKEN_PROGRAM_ID_HEX}'" + )), + _ => Err(DbErr::Custom("Unsupported database backend".to_string())), + } +} + +fn clear_backfilled_mint_onchain_pubkey_sql(backend: DatabaseBackend) -> Result { + match backend { + DatabaseBackend::Postgres => Ok(format!( + "UPDATE accounts \ + SET onchain_pubkey = NULL \ + WHERE onchain_pubkey IS NOT NULL \ + AND spent = false \ + AND data IS NOT NULL \ + AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ + AND substring(data from {TOKEN_ACCOUNT_TYPE_OFFSET_SQL} for 1) = E'\\\\x01' \ + AND owner = E'\\\\x{LIGHT_TOKEN_PROGRAM_ID_HEX}' \ + AND onchain_pubkey = substring(data from {COMPRESSED_MINT_PDA_OFFSET_SQL} for {COMPRESSED_MINT_PDA_LEN})" + )), + DatabaseBackend::Sqlite => Ok(format!( + "UPDATE accounts \ + SET onchain_pubkey = NULL \ + WHERE onchain_pubkey IS NOT NULL \ + AND spent = 0 \ + AND data IS NOT NULL \ + AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ + AND substr(data, {TOKEN_ACCOUNT_TYPE_OFFSET_SQL}, 1) = X'01' \ + AND owner = X'{LIGHT_TOKEN_PROGRAM_ID_HEX}' \ + AND onchain_pubkey = substr(data, {COMPRESSED_MINT_PDA_OFFSET_SQL}, {COMPRESSED_MINT_PDA_LEN})" + )), + _ => Err(DbErr::Custom("Unsupported database backend".to_string())), + } +} + +#[async_trait::async_trait] +impl MigrationTrait for Migration { + async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let backend = manager.get_database_backend(); + + // Backfill onchain_pubkey for compressed mint accounts. + // Compressed mints have: + // - owner = LIGHT_TOKEN_PROGRAM_ID + // - data length > 165 bytes + // - account_type byte at offset 165 (0-indexed) == 0x01 (Mint) + // The mint PDA is at data bytes [84..116] (0-indexed), which is + // substring starting at byte 85 (1-indexed) for 32 bytes. + let sql = backfill_mint_onchain_pubkey_sql(backend)?; + + manager + .get_connection() + .execute(Statement::from_string(backend, sql)) + .await?; + + Ok(()) + } + + async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { + let backend = manager.get_database_backend(); + + // Clear only values this migration backfilled, preserving independently-updated rows. + let sql = clear_backfilled_mint_onchain_pubkey_sql(backend)?; + + manager + .get_connection() + .execute(Statement::from_string(backend, sql)) + .await?; + + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_backfill_sql_uses_shared_offsets() { + let pg_sql = backfill_mint_onchain_pubkey_sql(DatabaseBackend::Postgres).unwrap(); + assert!(pg_sql.contains(&format!( + "substring(data from {COMPRESSED_MINT_PDA_OFFSET_SQL} for {COMPRESSED_MINT_PDA_LEN})" + ))); + assert!(pg_sql.contains(&format!("length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET}"))); + assert!(pg_sql.contains(&format!( + "substring(data from {TOKEN_ACCOUNT_TYPE_OFFSET_SQL} for 1)" + ))); + } + + #[test] + fn test_down_sql_only_clears_backfilled_values() { + let sqlite_sql = clear_backfilled_mint_onchain_pubkey_sql(DatabaseBackend::Sqlite).unwrap(); + assert!(sqlite_sql.contains("onchain_pubkey = substr(data,")); + assert!(sqlite_sql.contains("SET onchain_pubkey = NULL")); + } +} diff --git a/src/migration/migrations/standard/mod.rs b/src/migration/migrations/standard/mod.rs index 53527423..bb041b3d 100644 --- a/src/migration/migrations/standard/mod.rs +++ b/src/migration/migrations/standard/mod.rs @@ -16,6 +16,7 @@ pub mod m20250923_000001_add_tree_metadata; pub mod m20251021_000001_optimize_nullifier_queue_index; pub mod m20260127_000001_add_onchain_pubkey; pub mod m20260201_000002_add_ata_owner; +pub mod m20260210_000001_backfill_mint_onchain_pubkey; pub mod m20260210_000002_add_ata_owner_index; pub mod m20260220_000001_add_discriminator_v2; pub fn get_standard_migrations() -> Vec> { @@ -36,6 +37,7 @@ pub fn get_standard_migrations() -> Vec> { Box::new(m20251021_000001_optimize_nullifier_queue_index::Migration), Box::new(m20260127_000001_add_onchain_pubkey::Migration), Box::new(m20260201_000002_add_ata_owner::Migration), + Box::new(m20260210_000001_backfill_mint_onchain_pubkey::Migration), Box::new(m20260210_000002_add_ata_owner_index::Migration), Box::new(m20260220_000001_add_discriminator_v2::Migration), ] From 73bddb5b7bccd4a1355ce80800cc78f72e3613b8 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 3 Mar 2026 17:38:02 +0000 Subject: [PATCH 06/16] refactor: remove unused backfill migration for mint onchain pubkey --- src/common/token_layout.rs | 5 - ...210_000001_backfill_mint_onchain_pubkey.rs | 131 ------------------ src/migration/migrations/standard/mod.rs | 2 - 3 files changed, 138 deletions(-) delete mode 100644 src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs diff --git a/src/common/token_layout.rs b/src/common/token_layout.rs index e061f522..3310bce5 100644 --- a/src/common/token_layout.rs +++ b/src/common/token_layout.rs @@ -4,8 +4,6 @@ pub const SPL_TOKEN_ACCOUNT_BASE_LEN: usize = 165; /// Account type marker byte offset in token/mint account data. pub const TOKEN_ACCOUNT_TYPE_OFFSET: usize = SPL_TOKEN_ACCOUNT_BASE_LEN; -/// 1-indexed equivalent for SQL substring functions. -pub const TOKEN_ACCOUNT_TYPE_OFFSET_SQL: usize = TOKEN_ACCOUNT_TYPE_OFFSET + 1; /// AccountType::Mint discriminator value. pub const ACCOUNT_TYPE_MINT: u8 = 1; @@ -14,6 +12,3 @@ pub const ACCOUNT_TYPE_MINT: u8 = 1; pub const LIGHT_MINT_PDA_OFFSET: usize = 84; pub const LIGHT_MINT_PDA_LEN: usize = 32; pub const LIGHT_MINT_PDA_END: usize = LIGHT_MINT_PDA_OFFSET + LIGHT_MINT_PDA_LEN; -/// Aliases used by the backfill migration (SQL 1-indexed). -pub const COMPRESSED_MINT_PDA_OFFSET_SQL: usize = LIGHT_MINT_PDA_OFFSET + 1; -pub const COMPRESSED_MINT_PDA_LEN: usize = LIGHT_MINT_PDA_LEN; diff --git a/src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs b/src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs deleted file mode 100644 index eb4e0474..00000000 --- a/src/migration/migrations/standard/m20260210_000001_backfill_mint_onchain_pubkey.rs +++ /dev/null @@ -1,131 +0,0 @@ -use sea_orm_migration::{ - prelude::*, - sea_orm::{ConnectionTrait, DatabaseBackend, Statement}, -}; - -use crate::common::token_layout::{ - COMPRESSED_MINT_PDA_LEN, COMPRESSED_MINT_PDA_OFFSET_SQL, TOKEN_ACCOUNT_TYPE_OFFSET, - TOKEN_ACCOUNT_TYPE_OFFSET_SQL, -}; - -#[derive(DeriveMigrationName)] -pub struct Migration; - -/// Raw 32-byte pubkey for cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m -const LIGHT_TOKEN_PROGRAM_ID_HEX: &str = - "0915a35723794e8fb65d075b6b72699c38dd02e5948b75b0e5a0418e80975b44"; - -fn backfill_mint_onchain_pubkey_sql(backend: DatabaseBackend) -> Result { - match backend { - DatabaseBackend::Postgres => Ok(format!( - "UPDATE accounts \ - SET onchain_pubkey = substring(data from {COMPRESSED_MINT_PDA_OFFSET_SQL} for {COMPRESSED_MINT_PDA_LEN}) \ - WHERE onchain_pubkey IS NULL \ - AND spent = false \ - AND data IS NOT NULL \ - AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ - AND substring(data from {TOKEN_ACCOUNT_TYPE_OFFSET_SQL} for 1) = E'\\\\x01' \ - AND owner = E'\\\\x{LIGHT_TOKEN_PROGRAM_ID_HEX}'" - )), - DatabaseBackend::Sqlite => Ok(format!( - "UPDATE accounts \ - SET onchain_pubkey = substr(data, {COMPRESSED_MINT_PDA_OFFSET_SQL}, {COMPRESSED_MINT_PDA_LEN}) \ - WHERE onchain_pubkey IS NULL \ - AND spent = 0 \ - AND data IS NOT NULL \ - AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ - AND substr(data, {TOKEN_ACCOUNT_TYPE_OFFSET_SQL}, 1) = X'01' \ - AND owner = X'{LIGHT_TOKEN_PROGRAM_ID_HEX}'" - )), - _ => Err(DbErr::Custom("Unsupported database backend".to_string())), - } -} - -fn clear_backfilled_mint_onchain_pubkey_sql(backend: DatabaseBackend) -> Result { - match backend { - DatabaseBackend::Postgres => Ok(format!( - "UPDATE accounts \ - SET onchain_pubkey = NULL \ - WHERE onchain_pubkey IS NOT NULL \ - AND spent = false \ - AND data IS NOT NULL \ - AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ - AND substring(data from {TOKEN_ACCOUNT_TYPE_OFFSET_SQL} for 1) = E'\\\\x01' \ - AND owner = E'\\\\x{LIGHT_TOKEN_PROGRAM_ID_HEX}' \ - AND onchain_pubkey = substring(data from {COMPRESSED_MINT_PDA_OFFSET_SQL} for {COMPRESSED_MINT_PDA_LEN})" - )), - DatabaseBackend::Sqlite => Ok(format!( - "UPDATE accounts \ - SET onchain_pubkey = NULL \ - WHERE onchain_pubkey IS NOT NULL \ - AND spent = 0 \ - AND data IS NOT NULL \ - AND length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET} \ - AND substr(data, {TOKEN_ACCOUNT_TYPE_OFFSET_SQL}, 1) = X'01' \ - AND owner = X'{LIGHT_TOKEN_PROGRAM_ID_HEX}' \ - AND onchain_pubkey = substr(data, {COMPRESSED_MINT_PDA_OFFSET_SQL}, {COMPRESSED_MINT_PDA_LEN})" - )), - _ => Err(DbErr::Custom("Unsupported database backend".to_string())), - } -} - -#[async_trait::async_trait] -impl MigrationTrait for Migration { - async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> { - let backend = manager.get_database_backend(); - - // Backfill onchain_pubkey for compressed mint accounts. - // Compressed mints have: - // - owner = LIGHT_TOKEN_PROGRAM_ID - // - data length > 165 bytes - // - account_type byte at offset 165 (0-indexed) == 0x01 (Mint) - // The mint PDA is at data bytes [84..116] (0-indexed), which is - // substring starting at byte 85 (1-indexed) for 32 bytes. - let sql = backfill_mint_onchain_pubkey_sql(backend)?; - - manager - .get_connection() - .execute(Statement::from_string(backend, sql)) - .await?; - - Ok(()) - } - - async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> { - let backend = manager.get_database_backend(); - - // Clear only values this migration backfilled, preserving independently-updated rows. - let sql = clear_backfilled_mint_onchain_pubkey_sql(backend)?; - - manager - .get_connection() - .execute(Statement::from_string(backend, sql)) - .await?; - - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - - #[test] - fn test_backfill_sql_uses_shared_offsets() { - let pg_sql = backfill_mint_onchain_pubkey_sql(DatabaseBackend::Postgres).unwrap(); - assert!(pg_sql.contains(&format!( - "substring(data from {COMPRESSED_MINT_PDA_OFFSET_SQL} for {COMPRESSED_MINT_PDA_LEN})" - ))); - assert!(pg_sql.contains(&format!("length(data) > {TOKEN_ACCOUNT_TYPE_OFFSET}"))); - assert!(pg_sql.contains(&format!( - "substring(data from {TOKEN_ACCOUNT_TYPE_OFFSET_SQL} for 1)" - ))); - } - - #[test] - fn test_down_sql_only_clears_backfilled_values() { - let sqlite_sql = clear_backfilled_mint_onchain_pubkey_sql(DatabaseBackend::Sqlite).unwrap(); - assert!(sqlite_sql.contains("onchain_pubkey = substr(data,")); - assert!(sqlite_sql.contains("SET onchain_pubkey = NULL")); - } -} diff --git a/src/migration/migrations/standard/mod.rs b/src/migration/migrations/standard/mod.rs index bb041b3d..53527423 100644 --- a/src/migration/migrations/standard/mod.rs +++ b/src/migration/migrations/standard/mod.rs @@ -16,7 +16,6 @@ pub mod m20250923_000001_add_tree_metadata; pub mod m20251021_000001_optimize_nullifier_queue_index; pub mod m20260127_000001_add_onchain_pubkey; pub mod m20260201_000002_add_ata_owner; -pub mod m20260210_000001_backfill_mint_onchain_pubkey; pub mod m20260210_000002_add_ata_owner_index; pub mod m20260220_000001_add_discriminator_v2; pub fn get_standard_migrations() -> Vec> { @@ -37,7 +36,6 @@ pub fn get_standard_migrations() -> Vec> { Box::new(m20251021_000001_optimize_nullifier_queue_index::Migration), Box::new(m20260127_000001_add_onchain_pubkey::Migration), Box::new(m20260201_000002_add_ata_owner::Migration), - Box::new(m20260210_000001_backfill_mint_onchain_pubkey::Migration), Box::new(m20260210_000002_add_ata_owner_index::Migration), Box::new(m20260220_000001_add_discriminator_v2::Migration), ] From f0e557c0b0db654ede92774d6bbbb5619570305b Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 3 Mar 2026 17:44:43 +0000 Subject: [PATCH 07/16] refactor: remove parse_account_discriminator function and update usages for clarity --- src/api/method/utils.rs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/api/method/utils.rs b/src/api/method/utils.rs index 56240c5d..1cf78467 100644 --- a/src/api/method/utils.rs +++ b/src/api/method/utils.rs @@ -35,12 +35,6 @@ pub fn parse_decimal(value: Decimal) -> Result { .map_err(|_| PhotonApiError::UnexpectedError("Invalid decimal value".to_string())) } -pub fn parse_account_discriminator( - discriminator: Option, -) -> Result, PhotonApiError> { - discriminator.map(parse_decimal).transpose() -} - pub(crate) fn parse_leaf_index(leaf_index: i64) -> Result { leaf_index .try_into() From 1ac3b9a82b53a1b1c9e42b91187baaaca4ae1143 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 3 Mar 2026 14:25:01 +0000 Subject: [PATCH 08/16] feat: add Account Interface APIs (getAccountInterface, getMultipleAccountInterfaces) - Add getAccountInterface and getMultipleAccountInterfaces RPC methods - Implement racing logic for compressed vs on-chain account resolution - Add interface types (AccountInterface, SolanaAccountData) - Register new methods in RPC server and OpenAPI spec - Add integration tests with snapshot testing - Add test transaction data for indexer interface --- src/api/api.rs | 31 + .../method/interface/get_account_interface.rs | 22 + .../get_multiple_account_interfaces.rs | 107 ++ src/api/method/interface/mod.rs | 8 + src/api/method/interface/racing.rs | 1424 +++++++++++++++++ src/api/method/interface/types.rs | 87 + src/api/method/mod.rs | 1 + src/api/rpc_server.rs | 21 + src/openapi/mod.rs | 4 + ...2eSZuEdjKrqw9ez2yhxJt5U7S8LYdrUdSq1KKZid4X | 158 ++ ...2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd | 157 ++ ...iqFp6pXAB9fdrFHq66u6zvv3ddY5xLAzpmREASatnB | 114 ++ ...bufv4nTbqrp7ZQ5fpopHh7pU9RnimvvR31XeckFt9F | 158 ++ ...USeWpegrdfvrPkGA8qxfBFpu5ru9DjTFktRSB6w4s1 | 115 ++ tests/integration_tests/interface_tests.rs | 222 +++ tests/integration_tests/main.rs | 1 + ...ace_compressed_only-account-interface.snap | 11 + ...terface_nonexistent-account-interface.snap | 11 + ...nterfaces-multiple-account-interfaces.snap | 15 + ...face_by_owner-token-account-interface.snap | 11 + ...mpressed_only-token-account-interface.snap | 11 + 21 files changed, 2689 insertions(+) create mode 100644 src/api/method/interface/get_account_interface.rs create mode 100644 src/api/method/interface/get_multiple_account_interfaces.rs create mode 100644 src/api/method/interface/mod.rs create mode 100644 src/api/method/interface/racing.rs create mode 100644 src/api/method/interface/types.rs create mode 100644 tests/data/transactions/indexer_interface/2Q8KnAuf9TuPThbkEFZp6tfFC9bsGBVEpvoDJzLZAAEDKi2eSZuEdjKrqw9ez2yhxJt5U7S8LYdrUdSq1KKZid4X create mode 100644 tests/data/transactions/indexer_interface/2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd create mode 100644 tests/data/transactions/indexer_interface/2afJTiZyNEMvrKJasbDFqPaTaLWMttjAHnBLgm7CizqzqsiqFp6pXAB9fdrFHq66u6zvv3ddY5xLAzpmREASatnB create mode 100644 tests/data/transactions/indexer_interface/5bLkzWasPYAivyrVvrt5UN3amycT3MSdNB2evCEMyuW1Ajbufv4nTbqrp7ZQ5fpopHh7pU9RnimvvR31XeckFt9F create mode 100644 tests/data/transactions/indexer_interface/628ZqqrNWuVUfHF2seH7XQEZqBJtWA8NaAjcVeH96XWaubUSeWpegrdfvrPkGA8qxfBFpu5ru9DjTFktRSB6w4s1 create mode 100644 tests/integration_tests/interface_tests.rs create mode 100644 tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_compressed_only-account-interface.snap create mode 100644 tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_nonexistent-account-interface.snap create mode 100644 tests/integration_tests/snapshots/integration_tests__interface_tests__get_multiple_account_interfaces-multiple-account-interfaces.snap create mode 100644 tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_by_owner-token-account-interface.snap create mode 100644 tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_compressed_only-token-account-interface.snap diff --git a/src/api/api.rs b/src/api/api.rs index e323c2cd..c382db1a 100644 --- a/src/api/api.rs +++ b/src/api/api.rs @@ -85,6 +85,11 @@ use crate::api::method::get_validity_proof::{ GetValidityProofRequestDocumentation, GetValidityProofRequestV2, GetValidityProofResponse, GetValidityProofResponseV2, }; +use crate::api::method::interface::{ + get_account_interface, get_multiple_account_interfaces, GetAccountInterfaceRequest, + GetAccountInterfaceResponse, GetMultipleAccountInterfacesRequest, + GetMultipleAccountInterfacesResponse, +}; use crate::api::method::utils::{ AccountBalanceResponse, GetLatestSignaturesRequest, GetNonPaginatedSignaturesResponse, GetNonPaginatedSignaturesResponseWithError, GetPaginatedSignaturesResponse, HashRequest, @@ -402,6 +407,21 @@ impl PhotonApi { get_latest_non_voting_signatures(self.db_conn.as_ref(), request).await } + // Interface endpoints - race hot (on-chain) and cold (compressed) lookups + pub async fn get_account_interface( + &self, + request: GetAccountInterfaceRequest, + ) -> Result { + get_account_interface(&self.db_conn, &self.rpc_client, request).await + } + + pub async fn get_multiple_account_interfaces( + &self, + request: GetMultipleAccountInterfacesRequest, + ) -> Result { + get_multiple_account_interfaces(&self.db_conn, &self.rpc_client, request).await + } + pub fn method_api_specs() -> Vec { vec![ OpenApiSpec { @@ -591,6 +611,17 @@ impl PhotonApi { request: None, response: UnsignedInteger::schema().1, }, + // Interface endpoints + OpenApiSpec { + name: "getAccountInterface".to_string(), + request: Some(GetAccountInterfaceRequest::schema().1), + response: GetAccountInterfaceResponse::schema().1, + }, + OpenApiSpec { + name: "getMultipleAccountInterfaces".to_string(), + request: Some(GetMultipleAccountInterfacesRequest::schema().1), + response: GetMultipleAccountInterfacesResponse::schema().1, + }, ] } } diff --git a/src/api/method/interface/get_account_interface.rs b/src/api/method/interface/get_account_interface.rs new file mode 100644 index 00000000..cc6aa514 --- /dev/null +++ b/src/api/method/interface/get_account_interface.rs @@ -0,0 +1,22 @@ +use sea_orm::DatabaseConnection; +use solana_client::nonblocking::rpc_client::RpcClient; + +use crate::api::error::PhotonApiError; +use crate::common::typedefs::context::Context; + +use super::racing::race_hot_cold; +use super::types::{GetAccountInterfaceRequest, GetAccountInterfaceResponse}; + +/// Get account data from either on-chain or compressed sources. +/// Races both lookups and returns the result with the higher slot. +pub async fn get_account_interface( + conn: &DatabaseConnection, + rpc_client: &RpcClient, + request: GetAccountInterfaceRequest, +) -> Result { + let context = Context::extract(conn).await?; + + let value = race_hot_cold(rpc_client, conn, &request.address, None).await?; + + Ok(GetAccountInterfaceResponse { context, value }) +} diff --git a/src/api/method/interface/get_multiple_account_interfaces.rs b/src/api/method/interface/get_multiple_account_interfaces.rs new file mode 100644 index 00000000..576b8cf9 --- /dev/null +++ b/src/api/method/interface/get_multiple_account_interfaces.rs @@ -0,0 +1,107 @@ +use sea_orm::DatabaseConnection; +use solana_client::nonblocking::rpc_client::RpcClient; +use tokio::sync::Semaphore; + +use crate::api::error::PhotonApiError; +use crate::common::typedefs::context::Context; +use crate::common::typedefs::serializable_pubkey::SerializablePubkey; + +use super::racing::{get_distinct_owners_with_addresses, race_hot_cold}; +use super::types::{ + AccountInterface, GetMultipleAccountInterfacesRequest, GetMultipleAccountInterfacesResponse, + MAX_BATCH_SIZE, +}; + +/// Maximum concurrent hot+cold lookups per batch request. +const MAX_CONCURRENT_LOOKUPS: usize = 20; + +/// Get multiple account data from either on-chain or compressed sources. +/// Returns one unified AccountInterface shape for every input pubkey. +pub async fn get_multiple_account_interfaces( + conn: &DatabaseConnection, + rpc_client: &RpcClient, + request: GetMultipleAccountInterfacesRequest, +) -> Result { + if request.addresses.len() > MAX_BATCH_SIZE { + return Err(PhotonApiError::ValidationError(format!( + "Batch size {} exceeds maximum of {}", + request.addresses.len(), + MAX_BATCH_SIZE + ))); + } + + if request.addresses.is_empty() { + return Err(PhotonApiError::ValidationError( + "At least one address must be provided".to_string(), + )); + } + + let context = Context::extract(conn).await?; + + let distinct_owners = get_distinct_owners_with_addresses(conn) + .await + .map_err(PhotonApiError::DatabaseError)?; + + let semaphore = Semaphore::new(MAX_CONCURRENT_LOOKUPS); + let futures: Vec<_> = request + .addresses + .iter() + .map(|address| async { + let _permit = semaphore.acquire().await.unwrap(); + race_hot_cold(rpc_client, conn, address, Some(&distinct_owners)).await + }) + .collect(); + + let results = futures::future::join_all(futures).await; + + let value = collect_batch_results(&request.addresses, results)?; + + Ok(GetMultipleAccountInterfacesResponse { context, value }) +} + +fn collect_batch_results( + addresses: &[SerializablePubkey], + results: Vec, PhotonApiError>>, +) -> Result>, PhotonApiError> { + let mut value = Vec::with_capacity(results.len()); + for (i, result) in results.into_iter().enumerate() { + match result { + // Includes Ok(None): account not found is returned as None. + Ok(account) => value.push(account), + // Only actual lookup failures abort the entire batch call. + Err(e) => { + log::error!( + "Failed to fetch interface for address {:?} (index {}): {:?}", + addresses.get(i), + i, + e + ); + return Err(e); + } + } + } + Ok(value) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn collect_batch_results_keeps_none_for_not_found_accounts() { + let addresses = vec![SerializablePubkey::default(), SerializablePubkey::default()]; + let results = vec![Ok(None), Ok(None)]; + + let value = collect_batch_results(&addresses, results).expect("expected success"); + assert_eq!(value, vec![None, None]); + } + + #[test] + fn collect_batch_results_returns_error_for_actual_failure() { + let addresses = vec![SerializablePubkey::default()]; + let results = vec![Err(PhotonApiError::UnexpectedError("boom".to_string()))]; + + let err = collect_batch_results(&addresses, results).expect_err("expected error"); + assert_eq!(err, PhotonApiError::UnexpectedError("boom".to_string())); + } +} diff --git a/src/api/method/interface/mod.rs b/src/api/method/interface/mod.rs new file mode 100644 index 00000000..0be4588f --- /dev/null +++ b/src/api/method/interface/mod.rs @@ -0,0 +1,8 @@ +pub mod get_account_interface; +pub mod get_multiple_account_interfaces; +pub mod racing; +pub mod types; + +pub use get_account_interface::get_account_interface; +pub use get_multiple_account_interfaces::get_multiple_account_interfaces; +pub use types::*; diff --git a/src/api/method/interface/racing.rs b/src/api/method/interface/racing.rs new file mode 100644 index 00000000..8ed98f2f --- /dev/null +++ b/src/api/method/interface/racing.rs @@ -0,0 +1,1424 @@ +use std::collections::HashMap; +use std::time::Duration; + +use crate::api::error::PhotonApiError; +use crate::common::typedefs::account::AccountV2; +use crate::common::typedefs::bs64_string::Base64String; +use crate::common::typedefs::hash::Hash; +use crate::common::typedefs::serializable_pubkey::SerializablePubkey; +use crate::common::typedefs::token_data::AccountState; +use crate::common::typedefs::unsigned_integer::UnsignedInteger; +use crate::dao::generated::{accounts, token_accounts}; +use light_compressed_account::address::derive_address; +use light_hasher::{sha256::Sha256BE, Hasher}; +use light_sdk_types::constants::ADDRESS_TREE_V2; +use sea_orm::prelude::Decimal; +use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, QueryFilter}; +use solana_account::Account as SolanaAccount; +use solana_client::nonblocking::rpc_client::RpcClient; +use solana_commitment_config::CommitmentConfig; +use solana_program_option::COption; +use solana_program_pack::Pack; +use solana_pubkey::Pubkey; +use spl_token_interface::state::Account as SplTokenAccount; +use spl_token_interface::state::AccountState as SplAccountState; +use tokio::time::timeout; + +use crate::common::typedefs::token_data::TokenData; +use crate::ingester::persist::DECOMPRESSED_ACCOUNT_DISCRIMINATOR; + +use super::types::{AccountInterface, SolanaAccountData, DB_TIMEOUT_MS, RPC_TIMEOUT_MS}; + +/// Result from a hot (on-chain RPC) lookup. +#[derive(Debug)] +pub struct HotLookupResult { + pub account: Option, + pub slot: u64, +} + +/// Result from a cold (compressed DB) lookup. +#[derive(Debug)] +pub struct ColdLookupResult { + pub accounts: Vec, + /// Map from account hash → wallet owner bytes (from ata_owner in token_accounts table). + pub token_wallet_owners: HashMap, +} + +/// Perform a hot lookup via Solana RPC. +pub async fn hot_lookup( + rpc_client: &RpcClient, + address: &Pubkey, +) -> Result { + let result = timeout( + Duration::from_millis(RPC_TIMEOUT_MS), + rpc_client.get_account_with_commitment(address, CommitmentConfig::confirmed()), + ) + .await; + + match result { + Ok(Ok(response)) => Ok(HotLookupResult { + account: response.value, + slot: response.context.slot, + }), + Ok(Err(e)) => Err(PhotonApiError::UnexpectedError(format!("RPC error: {}", e))), + Err(_) => Err(PhotonApiError::UnexpectedError("RPC timeout".to_string())), + } +} + +/// Perform a cold lookup from the compressed accounts database. +/// +/// The lookup aggregates all compressed accounts associated with the queried pubkey: +/// 1) direct onchain pubkey matches (decompressed account linkage), +/// 2) derived compressed address matches (V2 address tree only), +/// 3) token account owner / ata_owner matches (can return multiple accounts). +pub async fn cold_lookup( + conn: &DatabaseConnection, + address: &SerializablePubkey, + distinct_owners: Option<&[Vec]>, +) -> Result { + let (models, token_wallet_owners) = find_cold_models(conn, address, distinct_owners).await?; + + let mut accounts_v2 = Vec::with_capacity(models.len()); + for model in models { + let account = AccountV2::try_from(model)?; + accounts_v2.push(account); + } + + Ok(ColdLookupResult { + accounts: accounts_v2, + token_wallet_owners, + }) +} + +fn has_decompressed_placeholder_shape(model: &accounts::Model) -> bool { + let Some(data) = model.data.as_ref() else { + return false; + }; + let Some(onchain_pubkey) = model.onchain_pubkey.as_ref() else { + return false; + }; + + data.len() == 32 && onchain_pubkey.len() == 32 && data.as_slice() == onchain_pubkey.as_slice() +} + +fn has_decompressed_placeholder_hash(model: &accounts::Model) -> bool { + let Some(onchain_pubkey) = model.onchain_pubkey.as_ref() else { + return false; + }; + let Some(data_hash) = model.data_hash.as_ref() else { + return false; + }; + + if onchain_pubkey.len() != 32 || data_hash.len() != 32 { + return false; + } + + match Sha256BE::hash(onchain_pubkey) { + Ok(expected_hash) => expected_hash.as_slice() == data_hash.as_slice(), + Err(_) => false, + } +} + +fn has_decompressed_placeholder_discriminator(model: &accounts::Model) -> bool { + let expected_disc = Decimal::from(DECOMPRESSED_ACCOUNT_DISCRIMINATOR); + let sqlite_rounded_disc = Decimal::from((DECOMPRESSED_ACCOUNT_DISCRIMINATOR as f64) as u64); + model.discriminator == Some(expected_disc) || model.discriminator == Some(sqlite_rounded_disc) +} + +fn is_decompressed_placeholder_model(model: &accounts::Model) -> bool { + if !has_decompressed_placeholder_shape(model) { + return false; + } + + if model.data_hash.is_some() && !has_decompressed_placeholder_hash(model) { + return false; + } + + has_decompressed_placeholder_discriminator(model) +} + +async fn find_cold_models( + conn: &DatabaseConnection, + address: &SerializablePubkey, + distinct_owners: Option<&[Vec]>, +) -> Result<(Vec, HashMap), PhotonApiError> { + let address_bytes: Vec = (*address).into(); + let pda_seed = address.0.to_bytes(); + + let mut by_hash: HashMap, accounts::Model> = HashMap::new(); + let mut token_wallet_owners: HashMap = HashMap::new(); + + // 1) Direct onchain pubkey linkage. + let onchain_result = timeout( + Duration::from_millis(DB_TIMEOUT_MS), + accounts::Entity::find() + .filter(accounts::Column::Spent.eq(false)) + .filter(accounts::Column::OnchainPubkey.eq(address_bytes.clone())) + .all(conn), + ) + .await; + + match onchain_result { + Ok(Ok(models)) => { + for model in models { + by_hash.insert(model.hash.clone(), model); + } + } + Ok(Err(e)) => return Err(PhotonApiError::DatabaseError(e)), + Err(_) => { + return Err(PhotonApiError::UnexpectedError( + "Database timeout".to_string(), + )) + } + } + + // 2) Derived-address fallback (V2 only). + // Use pre-fetched owners when available (batch path), otherwise query. + let owned_owners; + let owners: &[Vec] = match distinct_owners { + Some(cached) => cached, + None => { + let owners_result = timeout( + Duration::from_millis(DB_TIMEOUT_MS), + get_distinct_owners_with_addresses(conn), + ) + .await; + + owned_owners = match owners_result { + Ok(Ok(o)) => o, + Ok(Err(e)) => return Err(PhotonApiError::DatabaseError(e)), + Err(_) => { + return Err(PhotonApiError::UnexpectedError( + "Database timeout getting owners".to_string(), + )) + } + }; + &owned_owners + } + }; + + if !owners.is_empty() { + // Derived address lookups use V2 address tree only — compressible + // programs (the only users of this path) always create accounts + // with ADDRESS_TREE_V2. + let derived_addresses: Vec> = owners + .iter() + .filter_map(|owner| owner.as_slice().try_into().ok()) + .map(|owner_bytes: [u8; 32]| { + derive_address(&pda_seed, &ADDRESS_TREE_V2, &owner_bytes).to_vec() + }) + .collect(); + + if !derived_addresses.is_empty() { + let derived_result = timeout( + Duration::from_millis(DB_TIMEOUT_MS), + accounts::Entity::find() + .filter( + Condition::all() + .add(accounts::Column::Spent.eq(false)) + .add(accounts::Column::Address.is_in(derived_addresses)), + ) + .all(conn), + ) + .await; + + match derived_result { + Ok(Ok(models)) => { + for model in models { + by_hash.insert(model.hash.clone(), model); + } + } + Ok(Err(e)) => return Err(PhotonApiError::DatabaseError(e)), + Err(_) => { + return Err(PhotonApiError::UnexpectedError( + "Database timeout during derived address lookup".to_string(), + )) + } + } + } + } + + // 3) Token account linkage by token owner / ata_owner. + let token_result = timeout( + Duration::from_millis(DB_TIMEOUT_MS), + token_accounts::Entity::find() + .filter(token_accounts::Column::Spent.eq(false)) + .filter( + Condition::any() + .add(token_accounts::Column::AtaOwner.eq(address_bytes.clone())) + .add(token_accounts::Column::Owner.eq(address_bytes)), + ) + .find_also_related(accounts::Entity) + .all(conn), + ) + .await; + + match token_result { + Ok(Ok(rows)) => { + for (token, maybe_account) in rows { + if let Some(model) = maybe_account { + if !model.spent { + if let Some(ata_owner) = token.ata_owner { + match ( + Hash::try_from(model.hash.clone()), + <[u8; 32]>::try_from(ata_owner.as_slice()), + ) { + (Ok(hash), Ok(owner)) => { + token_wallet_owners.insert(hash, owner); + } + _ => log::warn!( + "Skipping invalid token wallet owner entry: hash_len={}, owner_len={}", + model.hash.len(), + ata_owner.len() + ), + } + } + by_hash.insert(model.hash.clone(), model); + } + } + } + } + Ok(Err(e)) => return Err(PhotonApiError::DatabaseError(e)), + Err(_) => { + return Err(PhotonApiError::UnexpectedError( + "Database timeout during token lookup".to_string(), + )) + } + } + + // Filter out decompressed PDA placeholders — they are bookmarks in the + // Merkle tree, not truly cold accounts. + // Sort by hash for deterministic ordering across identical queries. + let mut models: Vec<_> = by_hash + .into_values() + .filter(|m| !is_decompressed_placeholder_model(m)) + .collect(); + models.sort_by(|a, b| a.hash.cmp(&b.hash)); + Ok((models, token_wallet_owners)) +} + +/// Get distinct owners from accounts that have derived addresses. +/// These are accounts from compressible programs (their address is derived from PDA + tree + owner). +/// This is typically a small set since most programs aren't compressible. +pub async fn get_distinct_owners_with_addresses( + conn: &DatabaseConnection, +) -> Result>, sea_orm::DbErr> { + use sea_orm::{FromQueryResult, QuerySelect}; + + #[derive(FromQueryResult)] + struct OwnerResult { + owner: Vec, + } + + let owners: Vec = accounts::Entity::find() + .select_only() + .column(accounts::Column::Owner) + .distinct() + .filter(accounts::Column::Spent.eq(false)) + .filter(accounts::Column::Address.is_not_null()) + .into_model::() + .all(conn) + .await?; + + Ok(owners.into_iter().map(|o| o.owner).collect()) +} + +fn hot_to_solana_account_data(account: &SolanaAccount) -> SolanaAccountData { + SolanaAccountData { + lamports: UnsignedInteger(account.lamports), + data: Base64String(account.data.clone()), + owner: SerializablePubkey::from(account.owner.to_bytes()), + executable: account.executable, + rent_epoch: UnsignedInteger(account.rent_epoch), + space: UnsignedInteger(account.data.len() as u64), + } +} + +/// Build the 165-byte SPL Token Account layout from compressed TokenData + +/// corrected wallet owner. +fn build_spl_token_account_bytes(token_data: &TokenData, wallet_owner: &[u8; 32]) -> Vec { + let spl_state = match token_data.state { + AccountState::initialized => SplAccountState::Initialized, + AccountState::frozen => SplAccountState::Frozen, + }; + + let spl_account = SplTokenAccount { + mint: Pubkey::from(token_data.mint.0.to_bytes()), + owner: Pubkey::from(*wallet_owner), + amount: token_data.amount.0, + delegate: match &token_data.delegate { + Some(d) => COption::Some(Pubkey::from(d.0.to_bytes())), + None => COption::None, + }, + state: spl_state, + is_native: COption::None, + delegated_amount: 0, + close_authority: COption::None, + }; + + let mut buf = vec![0u8; SplTokenAccount::LEN]; + SplTokenAccount::pack(spl_account, &mut buf).expect("buffer is exactly LEN bytes"); + buf +} + +fn cold_to_synthetic_account_data( + account: &AccountV2, + wallet_owner: Option<&[u8]>, +) -> SolanaAccountData { + // For token accounts, always synthesize 165-byte SPL layout. + // Prefer ATA wallet owner when available, else fall back to compressed token owner. + if let Ok(Some(token_data)) = account.parse_token_data() { + let owner_arr = match wallet_owner.and_then(|bytes| <&[u8; 32]>::try_from(bytes).ok()) { + Some(owner) => *owner, + None => { + if let Some(owner) = wallet_owner { + log::debug!( + "Invalid ata_owner length for token account {}, using compressed owner: {}", + account.hash, + owner.len() + ); + } + token_data.owner.0.to_bytes() + } + }; + + let spl_bytes = build_spl_token_account_bytes(&token_data, &owner_arr); + let space = spl_bytes.len() as u64; + return SolanaAccountData { + lamports: account.lamports, + data: Base64String(spl_bytes), + // Preserve the original program owner from the cold account model. + // This can be LIGHT token program and, depending on account source, + // may also be SPL Token / Token-2022. + owner: account.owner, + executable: false, + rent_epoch: UnsignedInteger(0), + space: UnsignedInteger(space), + }; + } + + if wallet_owner + .map(|bytes| <&[u8; 32]>::try_from(bytes).is_err()) + .unwrap_or(false) + { + log::debug!( + "Ignoring invalid wallet owner length for non-token cold account: {:?}", + wallet_owner.map(|v| v.len()) + ); + } + + let full_data = account + .data + .as_ref() + .map(|d| d.data.0.clone()) + .unwrap_or_default(); + + let space = full_data.len() as u64; + SolanaAccountData { + lamports: account.lamports, + data: Base64String(full_data), + owner: account.owner, + executable: false, + rent_epoch: UnsignedInteger(0), + space: UnsignedInteger(space), + } +} + +fn parse_hot_spl_token(data: &[u8]) -> Option { + SplTokenAccount::unpack(data).ok() +} + +fn build_interface( + address: SerializablePubkey, + account_data: SolanaAccountData, + cold_accounts: Vec, +) -> AccountInterface { + AccountInterface { + key: address, + account: account_data, + cold: (!cold_accounts.is_empty()).then_some(cold_accounts), + } +} + +/// Race hot and cold lookups, returning a single unified interface shape. +/// +/// Account selection policy: +/// 1) If hot exists with lamports > 0 and hot slot >= newest cold slot, use hot account view. +/// 2) Otherwise, if cold exists, synthesize account view from newest cold account. +/// 3) Include all cold accounts in `cold` whenever they exist. +pub async fn race_hot_cold( + rpc_client: &RpcClient, + conn: &DatabaseConnection, + address: &SerializablePubkey, + distinct_owners: Option<&[Vec]>, +) -> Result, PhotonApiError> { + let pubkey = Pubkey::from(address.0.to_bytes()); + + let (hot_result, cold_result) = tokio::join!( + hot_lookup(rpc_client, &pubkey), + cold_lookup(conn, address, distinct_owners) + ); + + resolve_race_result(hot_result, cold_result, *address) +} + +fn resolve_race_result( + hot_result: Result, + cold_result: Result, + address: SerializablePubkey, +) -> Result, PhotonApiError> { + match (hot_result, cold_result) { + (Ok(hot), Ok(cold)) => Ok(resolve_single_race( + hot.account.as_ref(), + &cold.accounts, + hot.slot, + address, + &cold.token_wallet_owners, + )), + (Ok(hot), Err(e)) => { + log::debug!("Cold lookup failed, using hot result: {:?}", e); + Ok(hot + .account + .as_ref() + .filter(|account| account.lamports > 0) + .map(|account| { + build_interface(address, hot_to_solana_account_data(account), vec![]) + })) + } + (Err(e), Ok(cold)) => { + log::debug!("Hot lookup failed, using cold result: {:?}", e); + Ok(resolve_single_race( + None, + &cold.accounts, + 0, + address, + &cold.token_wallet_owners, + )) + } + (Err(hot_err), Err(cold_err)) => { + log::warn!( + "Both hot and cold lookups failed. Hot: {:?}, Cold: {:?}", + hot_err, + cold_err + ); + Err(hot_err) + } + } +} + +/// Build a synthetic `SolanaAccountData` from cold accounts, optionally +/// including a hot on-chain account's balance. +/// +/// For fungible tokens: if **all** cold accounts parse as token accounts with +/// the same mint (and, when provided, the hot account shares that mint) their +/// amounts are summed into a single SPL Token layout. When a hot account is +/// present it is used as the base for the synthetic view (it already carries the +/// correct wallet owner, delegate, state, etc.). Otherwise the newest cold +/// account (by slot) provides those fields. +/// +/// For everything else (non-token accounts, mixed mints, parse failures) the +/// function falls back to the hot account (if present and newer) or the newest +/// cold account. +fn cold_accounts_to_synthetic( + cold_accounts: &[AccountV2], + token_wallet_owners: &HashMap, + hot_account: Option<&SolanaAccount>, + hot_slot: u64, +) -> SolanaAccountData { + debug_assert!(!cold_accounts.is_empty()); + + // Try to parse every cold account as a token account. + let parsed: Vec<(&AccountV2, TokenData)> = cold_accounts + .iter() + .filter_map(|acc| acc.parse_token_data().ok().flatten().map(|td| (acc, td))) + .collect(); + + // All cold accounts must be token accounts with the same mint. + if !parsed.is_empty() && parsed.len() == cold_accounts.len() { + let first_mint = &parsed[0].1.mint; + let all_same_mint = parsed.iter().all(|(_, td)| td.mint == *first_mint); + + if all_same_mint { + // If a hot account is provided, it must also be an SPL token with + // the same mint; otherwise skip aggregation entirely. + let hot_contribution = match hot_account { + Some(hot) => match parse_hot_spl_token(&hot.data) { + Some(spl) if spl.mint.to_bytes() == first_mint.0.to_bytes() => Some(spl), + Some(_) => None, // different mint — can't aggregate + None => None, // not a token account + }, + None => None, + }; + + // When hot exists but doesn't match, fall through to fallback. + if hot_account.is_none() || hot_contribution.is_some() { + let cold_total: u64 = parsed.iter().map(|(_, td)| td.amount.0).sum(); + let hot_amount = hot_contribution.as_ref().map_or(0, |spl| spl.amount); + let total_amount = cold_total + hot_amount; + + // When a hot account matches, use it as the base for the + // synthetic view — it already has the correct wallet owner, + // delegate, state, etc. Unpack, set aggregated amount, repack. + if let (Some(hot), Some(mut spl)) = (hot_account, hot_contribution) { + spl.amount = total_amount; + let mut spl_bytes = vec![0u8; SplTokenAccount::LEN]; + SplTokenAccount::pack(spl, &mut spl_bytes) + .expect("buffer is exactly LEN bytes"); + let space = spl_bytes.len() as u64; + return SolanaAccountData { + lamports: UnsignedInteger(hot.lamports), + data: Base64String(spl_bytes), + owner: SerializablePubkey::from(hot.owner.to_bytes()), + executable: false, + rent_epoch: UnsignedInteger(0), + space: UnsignedInteger(space), + }; + } + + // Cold-only path: build from newest cold account. + let (newest_acc, newest_td) = parsed + .iter() + .max_by_key(|(acc, _)| acc.slot_created.0) + .unwrap(); + + let wallet_owner_bytes = token_wallet_owners.get(&newest_acc.hash); + let owner_arr = match wallet_owner_bytes + .and_then(|bytes| <&[u8; 32]>::try_from(bytes.as_slice()).ok()) + { + Some(owner) => *owner, + None => newest_td.owner.0.to_bytes(), + }; + + let aggregated = TokenData { + mint: newest_td.mint, + owner: newest_td.owner, + amount: UnsignedInteger(total_amount), + delegate: newest_td.delegate, + state: newest_td.state, + tlv: newest_td.tlv.clone(), + }; + + let spl_bytes = build_spl_token_account_bytes(&aggregated, &owner_arr); + let space = spl_bytes.len() as u64; + return SolanaAccountData { + lamports: newest_acc.lamports, + data: Base64String(spl_bytes), + owner: newest_acc.owner, + executable: false, + rent_epoch: UnsignedInteger(0), + space: UnsignedInteger(space), + }; + } + } + } + + // Fallback: compare hot slot vs newest cold slot to pick the fresher view. + let newest = cold_accounts + .iter() + .max_by_key(|acc| acc.slot_created.0) + .unwrap(); + + if let Some(hot) = hot_account { + if hot_slot >= newest.slot_created.0 { + return hot_to_solana_account_data(hot); + } + } + + let wallet_owner = token_wallet_owners.get(&newest.hash); + cold_to_synthetic_account_data(newest, wallet_owner.map(|v| v.as_slice())) +} + +fn resolve_single_race( + hot_account: Option<&SolanaAccount>, + cold_accounts: &[AccountV2], + hot_slot: u64, + address: SerializablePubkey, + token_wallet_owners: &HashMap, +) -> Option { + let hot = hot_account.filter(|account| account.lamports > 0); + let has_cold = !cold_accounts.is_empty(); + + let account_data = match (hot, has_cold) { + (Some(hot), true) => { + cold_accounts_to_synthetic(cold_accounts, token_wallet_owners, Some(hot), hot_slot) + } + (Some(hot), false) => hot_to_solana_account_data(hot), + (None, true) => cold_accounts_to_synthetic(cold_accounts, token_wallet_owners, None, 0), + (None, false) => return None, + }; + + Some(build_interface( + address, + account_data, + cold_accounts.to_vec(), + )) +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::api::method::get_validity_proof::MerkleContextV2; + use crate::common::typedefs::account::AccountData; + use crate::common::typedefs::account::C_TOKEN_DISCRIMINATOR_V2; + use crate::common::typedefs::hash::Hash; + use crate::common::typedefs::token_data::AccountState; + use crate::ingester::persist::LIGHT_TOKEN_PROGRAM_ID; + use solana_program_pack::Pack; + use spl_token_interface::state::Account as SplTokenAccount; + + fn sample_cold(slot_created: u64, lamports: u64) -> AccountV2 { + AccountV2 { + hash: Hash::default(), + address: Some(SerializablePubkey::default()), + data: Some(AccountData { + discriminator: UnsignedInteger(0x0807060504030201), + data: Base64String(vec![100, 200]), + data_hash: Hash::default(), + }), + owner: SerializablePubkey::default(), + lamports: UnsignedInteger(lamports), + leaf_index: UnsignedInteger(0), + seq: Some(UnsignedInteger(1)), + slot_created: UnsignedInteger(slot_created), + prove_by_index: false, + merkle_context: MerkleContextV2 { + tree_type: 3, + tree: SerializablePubkey::default(), + queue: SerializablePubkey::default(), + cpi_context: None, + next_tree_context: None, + }, + } + } + + /// Build a cold AccountV2 that looks like a compressed token account. + /// Uses LIGHT_TOKEN_PROGRAM_ID as owner and a c_token discriminator. + fn sample_token_cold(slot_created: u64, lamports: u64, token_data: &TokenData) -> AccountV2 { + sample_token_cold_with_hash(slot_created, lamports, token_data, Hash::default()) + } + + fn sample_token_cold_with_hash( + slot_created: u64, + lamports: u64, + token_data: &TokenData, + hash: Hash, + ) -> AccountV2 { + use borsh::BorshSerialize; + let mut data_bytes = Vec::new(); + token_data.serialize(&mut data_bytes).unwrap(); + + let discriminator = u64::from_le_bytes(C_TOKEN_DISCRIMINATOR_V2); + + AccountV2 { + hash, + address: Some(SerializablePubkey::default()), + data: Some(AccountData { + discriminator: UnsignedInteger(discriminator), + data: Base64String(data_bytes), + data_hash: Hash::default(), + }), + owner: SerializablePubkey::from(LIGHT_TOKEN_PROGRAM_ID), + lamports: UnsignedInteger(lamports), + leaf_index: UnsignedInteger(0), + seq: Some(UnsignedInteger(1)), + slot_created: UnsignedInteger(slot_created), + prove_by_index: false, + merkle_context: MerkleContextV2 { + tree_type: 3, + tree: SerializablePubkey::default(), + queue: SerializablePubkey::default(), + cpi_context: None, + next_tree_context: None, + }, + } + } + + #[test] + fn test_resolve_single_race_prefers_hot_when_newer_or_equal() { + let hot = SolanaAccount { + lamports: 1000, + data: vec![1, 2, 3], + owner: Pubkey::new_unique(), + executable: false, + rent_epoch: 0, + }; + let cold = sample_cold(100, 500); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 200, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + assert_eq!(result.account.lamports.0, 1000); + assert!(result.cold.is_some()); + assert_eq!(result.cold.unwrap().len(), 1); + } + + #[test] + fn test_resolve_single_race_prefers_newer_cold_by_slot() { + let hot = SolanaAccount { + lamports: 1000, + data: vec![1, 2, 3], + owner: Pubkey::new_unique(), + executable: false, + rent_epoch: 0, + }; + let cold = sample_cold(300, 777); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 200, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + assert_eq!(result.account.lamports.0, 777); + assert!(result.cold.is_some()); + } + + #[test] + fn test_resolve_single_race_falls_back_to_cold_when_hot_deleted() { + let hot = SolanaAccount { + lamports: 0, + data: vec![], + owner: Pubkey::new_unique(), + executable: false, + rent_epoch: 0, + }; + let cold = sample_cold(100, 500); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 200, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + assert_eq!(result.account.lamports.0, 500); + assert!(result.cold.is_some()); + } + + #[test] + fn test_resolve_single_race_only_hot() { + let hot = SolanaAccount { + lamports: 1000, + data: vec![1, 2, 3], + owner: Pubkey::new_unique(), + executable: false, + rent_epoch: 0, + }; + + let result = resolve_single_race( + Some(&hot), + &[], + 200, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + assert_eq!(result.account.lamports.0, 1000); + assert!(result.cold.is_none()); + } + + #[test] + fn test_resolve_single_race_only_cold() { + let cold = sample_cold(100, 555); + + let result = resolve_single_race( + None, + std::slice::from_ref(&cold), + 0, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + assert_eq!(result.account.lamports.0, 555); + assert!(result.cold.is_some()); + } + + #[test] + fn test_resolve_single_race_neither() { + let result = + resolve_single_race(None, &[], 0, SerializablePubkey::default(), &HashMap::new()); + assert!(result.is_none()); + } + + // ============ SPL Token Account reconstruction tests ============ + + #[test] + fn test_build_spl_token_account_bytes_basic() { + let mint = Pubkey::new_unique(); + let wallet_owner = [42u8; 32]; + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), // compressed owner (not wallet) + amount: UnsignedInteger(1_000_000), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let bytes = build_spl_token_account_bytes(&token_data, &wallet_owner); + + assert_eq!(bytes.len(), SplTokenAccount::LEN); + let parsed = SplTokenAccount::unpack(&bytes).expect("valid SPL layout"); + assert_eq!(parsed.mint, mint); + assert_eq!(parsed.owner, Pubkey::from(wallet_owner)); + assert_eq!(parsed.amount, 1_000_000); + assert!(parsed.delegate.is_none()); + assert_eq!( + parsed.state, + spl_token_interface::state::AccountState::Initialized + ); + assert!(parsed.is_native.is_none()); + assert_eq!(parsed.delegated_amount, 0); + assert!(parsed.close_authority.is_none()); + } + + #[test] + fn test_build_spl_token_account_bytes_with_delegate() { + let mint = Pubkey::new_unique(); + let wallet_owner = [10u8; 32]; + let delegate_key = Pubkey::new_unique(); + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(500), + delegate: Some(SerializablePubkey::from(delegate_key)), + state: AccountState::frozen, + tlv: None, + }; + + let bytes = build_spl_token_account_bytes(&token_data, &wallet_owner); + + assert_eq!(bytes.len(), SplTokenAccount::LEN); + let parsed = SplTokenAccount::unpack(&bytes).expect("valid SPL layout"); + assert_eq!(parsed.amount, 500); + assert_eq!( + parsed.delegate, + solana_program_option::COption::Some(delegate_key) + ); + assert_eq!( + parsed.state, + spl_token_interface::state::AccountState::Frozen + ); + } + + #[test] + fn test_cold_to_synthetic_token_with_wallet_owner() { + let mint = Pubkey::new_unique(); + let wallet_owner = [55u8; 32]; + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(42), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let cold = sample_token_cold(100, 1_000_000, &token_data); + let result = cold_to_synthetic_account_data(&cold, Some(&wallet_owner)); + + // Should produce 165-byte SPL layout + let parsed = SplTokenAccount::unpack(&result.data.0).expect("valid SPL layout"); + assert_eq!(result.space.0, SplTokenAccount::LEN as u64); + // Program owner should be preserved from cold account. + assert_eq!( + result.owner, + SerializablePubkey::from(LIGHT_TOKEN_PROGRAM_ID) + ); + assert_eq!(parsed.owner, Pubkey::from(wallet_owner)); + } + + #[test] + fn test_cold_to_synthetic_token_without_wallet_owner() { + let mint = Pubkey::new_unique(); + let compressed_owner = [99u8; 32]; + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from(compressed_owner), + amount: UnsignedInteger(42), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let cold = sample_token_cold(100, 1_000_000, &token_data); + // No wallet owner → should fall back to compressed token owner. + let result = cold_to_synthetic_account_data(&cold, None); + + let parsed = SplTokenAccount::unpack(&result.data.0).expect("valid SPL layout"); + assert_eq!(result.space.0, SplTokenAccount::LEN as u64); + assert_eq!( + result.owner, + SerializablePubkey::from(LIGHT_TOKEN_PROGRAM_ID) + ); + assert_eq!(parsed.owner, Pubkey::from(compressed_owner)); + } + + #[test] + fn test_cold_to_synthetic_token_invalid_wallet_owner_uses_compressed_owner() { + let mint = Pubkey::new_unique(); + let compressed_owner = [77u8; 32]; + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from(compressed_owner), + amount: UnsignedInteger(42), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let cold = sample_token_cold(100, 1_000_000, &token_data); + let invalid_owner = [1u8; 31]; + let result = cold_to_synthetic_account_data(&cold, Some(&invalid_owner)); + + let parsed = SplTokenAccount::unpack(&result.data.0).expect("valid SPL layout"); + assert_eq!(parsed.owner, Pubkey::from(compressed_owner)); + } + + #[test] + fn test_cold_to_synthetic_non_token() { + let cold = sample_cold(100, 500); + let wallet_owner = [55u8; 32]; + + // Non-token account with wallet_owner should be unaffected + let result = cold_to_synthetic_account_data(&cold, Some(&wallet_owner)); + + // Should use fallback (discriminator + data), NOT 165-byte SPL layout + assert_ne!(result.data.0.len(), SplTokenAccount::LEN); + // Owner should remain as the account's owner (default pubkey) + assert_eq!(result.owner, SerializablePubkey::default()); + } + + // ============ Decompressed placeholder filtering tests ============ + + use crate::dao::generated::accounts; + use sea_orm::prelude::Decimal; + + fn make_account_model( + hash_byte: u8, + discriminator: Option, + data: Option>, + data_hash: Option>, + onchain_pubkey: Option>, + ) -> accounts::Model { + accounts::Model { + hash: vec![hash_byte; 32], + address: None, + discriminator, + data, + data_hash, + tree: vec![], + leaf_index: 0, + seq: Some(1), + slot_created: 100, + owner: vec![0u8; 32], + lamports: Decimal::from(0), + spent: false, + prev_spent: Some(false), + tx_hash: None, + onchain_pubkey, + tree_type: Some(3), + nullified_in_tree: false, + nullifier_queue_index: None, + in_output_queue: false, + queue: None, + nullifier: None, + } + } + + #[test] + fn test_find_cold_models_filters_decompressed_placeholders() { + let pda = vec![1u8; 32]; + let data_hash = Sha256BE::hash(&pda).unwrap().to_vec(); + let placeholder = make_account_model( + 1, + Some(Decimal::from(DECOMPRESSED_ACCOUNT_DISCRIMINATOR)), + Some(pda.clone()), + Some(data_hash), + Some(pda), + ); + let normal = make_account_model( + 2, + Some(Decimal::from(0x0807060504030201u64)), + None, + None, + None, + ); + let no_disc = make_account_model(3, None, None, None, None); + + // Simulate the filtering logic from find_cold_models. + let by_hash: HashMap, accounts::Model> = vec![ + (placeholder.hash.clone(), placeholder), + (normal.hash.clone(), normal), + (no_disc.hash.clone(), no_disc), + ] + .into_iter() + .collect(); + + let filtered: Vec<_> = by_hash + .into_values() + .filter(|m| !is_decompressed_placeholder_model(m)) + .collect(); + + // Placeholder should be filtered out, normal and no-disc should remain. + assert_eq!(filtered.len(), 2); + let hashes: Vec<&Vec> = filtered.iter().map(|m| &m.hash).collect(); + assert!(hashes.contains(&&vec![2u8; 32])); + assert!(hashes.contains(&&vec![3u8; 32])); + } + + #[test] + fn test_find_cold_models_filters_sqlite_rounded_decompressed_placeholder() { + // SQLite REAL rounding shifts this discriminator by +1 for large u64 values. + let rounded_disc = Decimal::from(DECOMPRESSED_ACCOUNT_DISCRIMINATOR + 1); + let pda = vec![9u8; 32]; + let data_hash = Sha256BE::hash(&pda).unwrap().to_vec(); + let placeholder = make_account_model( + 9, + Some(rounded_disc), + Some(pda.clone()), + Some(data_hash), + Some(pda.clone()), + ); + + assert!(is_decompressed_placeholder_model(&placeholder)); + } + + #[test] + fn test_find_cold_models_filters_legacy_sqlite_rounded_placeholder_without_disc_bytes() { + let rounded_disc = Decimal::from(DECOMPRESSED_ACCOUNT_DISCRIMINATOR + 1); + let pda = vec![8u8; 32]; + let placeholder = + make_account_model(8, Some(rounded_disc), Some(pda.clone()), None, Some(pda)); + + assert!(is_decompressed_placeholder_model(&placeholder)); + } + + #[test] + fn test_find_cold_models_keeps_non_placeholder_with_onchain_pubkey() { + // Model shape similar to compressed mint linkage: has onchain_pubkey but + // does not store it in the first 32 bytes of data. + let rounded_disc = Decimal::from(DECOMPRESSED_ACCOUNT_DISCRIMINATOR + 1); + let mut mint_data = vec![0u8; 120]; + let onchain = vec![7u8; 32]; + mint_data[84..116].copy_from_slice(&onchain); + + let model = make_account_model(7, Some(rounded_disc), Some(mint_data), None, Some(onchain)); + assert!(!is_decompressed_placeholder_model(&model)); + } + + // ============ Fungible token amount aggregation tests ============ + + #[test] + fn test_resolve_aggregates_fungible_token_amounts() { + let mint = Pubkey::new_unique(); + let wallet_owner = [55u8; 32]; + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + let hash2 = Hash::try_from(vec![2u8; 32]).unwrap(); + let hash3 = Hash::try_from(vec![3u8; 32]).unwrap(); + + let td1 = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(100), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let td2 = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(250), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let td3 = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(650), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let cold1 = sample_token_cold_with_hash(100, 0, &td1, hash1); + let cold2 = sample_token_cold_with_hash(200, 0, &td2, hash2); + let cold3 = sample_token_cold_with_hash(300, 0, &td3, hash3.clone()); + + let cold_accounts = vec![cold1, cold2, cold3]; + + // Map newest hash → wallet owner + let mut token_wallet_owners = HashMap::new(); + token_wallet_owners.insert(hash3, wallet_owner); + + let result = resolve_single_race( + None, + &cold_accounts, + 0, + SerializablePubkey::default(), + &token_wallet_owners, + ) + .expect("expected Some interface"); + + // Primary view should have aggregated amount = 100 + 250 + 650 = 1000 + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 1000); + assert_eq!(parsed.owner, Pubkey::from(wallet_owner)); + + // All cold accounts should be included + assert_eq!(result.cold.as_ref().unwrap().len(), 3); + } + + #[test] + fn test_resolve_mixed_mints_uses_newest() { + let mint_a = Pubkey::new_unique(); + let mint_b = Pubkey::new_unique(); + + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + let hash2 = Hash::try_from(vec![2u8; 32]).unwrap(); + + let td1 = TokenData { + mint: SerializablePubkey::from(mint_a), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(100), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let td2 = TokenData { + mint: SerializablePubkey::from(mint_b), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(200), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let cold1 = sample_token_cold_with_hash(100, 0, &td1, hash1); + let cold2 = sample_token_cold_with_hash(200, 0, &td2, hash2.clone()); + + let cold_accounts = vec![cold1, cold2]; + + let mut token_wallet_owners = HashMap::new(); + token_wallet_owners.insert(hash2, [55u8; 32]); + + let result = resolve_single_race( + None, + &cold_accounts, + 0, + SerializablePubkey::default(), + &token_wallet_owners, + ) + .expect("expected Some interface"); + + // Mixed mints → fallback to newest by slot (cold2, amount=200) + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 200); + } + + #[test] + fn test_resolve_single_token_unchanged() { + let mint = Pubkey::new_unique(); + let wallet_owner = [55u8; 32]; + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + let td = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(42), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let cold = sample_token_cold_with_hash(100, 1_000_000, &td, hash1.clone()); + let cold_accounts = vec![cold]; + + let mut token_wallet_owners = HashMap::new(); + token_wallet_owners.insert(hash1, wallet_owner); + + let result = resolve_single_race( + None, + &cold_accounts, + 0, + SerializablePubkey::default(), + &token_wallet_owners, + ) + .expect("expected Some interface"); + + // Single token account → amount should be 42, unchanged + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 42); + assert_eq!(parsed.owner, Pubkey::from(wallet_owner)); + } + + // ============ Hot + cold aggregation tests ============ + + /// Helper to build a hot SolanaAccount that looks like an SPL token ATA. + fn sample_hot_token_account(mint: &Pubkey, owner: &Pubkey, amount: u64) -> SolanaAccount { + use solana_program_option::COption; + use spl_token_interface::state::AccountState as SplAccountState; + + let spl_account = SplTokenAccount { + mint: *mint, + owner: *owner, + amount, + delegate: COption::None, + state: SplAccountState::Initialized, + is_native: COption::None, + delegated_amount: 0, + close_authority: COption::None, + }; + + let mut data = vec![0u8; SplTokenAccount::LEN]; + SplTokenAccount::pack(spl_account, &mut data).unwrap(); + + // Use the real SPL Token program id. + let spl_token_program = Pubkey::try_from(spl_token_interface::ID.as_ref()).unwrap(); + + SolanaAccount { + lamports: 2_039_280, // typical rent-exempt ATA + data, + owner: spl_token_program, + executable: false, + rent_epoch: 0, + } + } + + #[test] + fn test_resolve_aggregates_hot_and_cold_token_amounts() { + let mint = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + let hash2 = Hash::try_from(vec![2u8; 32]).unwrap(); + + // Hot ATA with 500 tokens. + let hot = sample_hot_token_account(&mint, &wallet_owner, 500); + + // Two cold compressed token accounts, 100 + 400 tokens. + let td1 = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(100), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let td2 = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(400), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + + let cold1 = sample_token_cold_with_hash(100, 0, &td1, hash1); + let cold2 = sample_token_cold_with_hash(200, 0, &td2, hash2); + let cold_accounts = vec![cold1, cold2]; + + let result = resolve_single_race( + Some(&hot), + &cold_accounts, + 300, // hot_slot + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + // Primary view should have aggregated amount = 500 (hot) + 100 + 400 (cold) = 1000 + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 1000); + // Wallet owner should come from the hot ATA. + assert_eq!(parsed.owner, wallet_owner); + assert_eq!(parsed.mint, mint); + // Cold accounts still included. + assert_eq!(result.cold.as_ref().unwrap().len(), 2); + } + + #[test] + fn test_resolve_hot_token_different_mint_from_cold_uses_hot() { + let mint_hot = Pubkey::new_unique(); + let mint_cold = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + let hot = sample_hot_token_account(&mint_hot, &wallet_owner, 500); + + let td = TokenData { + mint: SerializablePubkey::from(mint_cold), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(300), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let cold = sample_token_cold_with_hash(100, 0, &td, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 300, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + // Different mints → fallback to hot account (since hot is present). + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 500); + assert_eq!(parsed.mint, mint_hot); + } + + #[test] + fn test_resolve_hot_non_token_with_cold_tokens_uses_hot() { + let mint = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + // Hot is not a token account (random data, too short for SPL). + let hot = SolanaAccount { + lamports: 1000, + data: vec![1, 2, 3], + owner: Pubkey::new_unique(), + executable: false, + rent_epoch: 0, + }; + + let td = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(300), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let cold = sample_token_cold_with_hash(100, 0, &td, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 300, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + // Hot is not a token → can't aggregate → fallback to hot. + assert_eq!(result.account.lamports.0, 1000); + assert_eq!(result.account.data.0, vec![1, 2, 3]); + } +} diff --git a/src/api/method/interface/types.rs b/src/api/method/interface/types.rs new file mode 100644 index 00000000..42ba4a8d --- /dev/null +++ b/src/api/method/interface/types.rs @@ -0,0 +1,87 @@ +use serde::{Deserialize, Serialize}; +use solana_pubkey::{pubkey, Pubkey}; +use utoipa::ToSchema; + +use crate::common::typedefs::account::AccountV2; +use crate::common::typedefs::bs64_string::Base64String; +use crate::common::typedefs::context::Context; +use crate::common::typedefs::serializable_pubkey::SerializablePubkey; +use crate::common::typedefs::unsigned_integer::UnsignedInteger; + +/// Nested Solana account fields (matches getAccountInfo shape) +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct SolanaAccountData { + pub lamports: UnsignedInteger, + pub data: Base64String, + pub owner: SerializablePubkey, + pub executable: bool, + pub rent_epoch: UnsignedInteger, + pub space: UnsignedInteger, +} + +/// Unified account interface — works for both on-chain and compressed accounts +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct AccountInterface { + /// The queried Solana pubkey + pub key: SerializablePubkey, + /// Standard Solana account fields (hot view or synthetic cold view) + pub account: SolanaAccountData, + /// Compressed accounts associated with this pubkey + pub cold: Option>, +} + +// ============ Request Types ============ + +/// Request for getAccountInterface +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct GetAccountInterfaceRequest { + /// The account address to look up + pub address: SerializablePubkey, +} + +/// Request for getMultipleAccountInterfaces +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct GetMultipleAccountInterfacesRequest { + /// List of account addresses to look up (max 100) + pub addresses: Vec, +} + +// ============ Response Types ============ + +/// Response for getAccountInterface +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct GetAccountInterfaceResponse { + /// Current context (slot) + pub context: Context, + /// The account data, or None if not found + pub value: Option, +} + +/// Response for getMultipleAccountInterfaces +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct GetMultipleAccountInterfacesResponse { + /// Current context (slot) + pub context: Context, + /// List of account results (Some for found accounts, None for not found) + pub value: Vec>, +} + +// ============ Constants ============ + +/// Maximum number of accounts that can be looked up in a single batch request +pub const MAX_BATCH_SIZE: usize = 100; + +/// RPC timeout in milliseconds for hot lookups +pub const RPC_TIMEOUT_MS: u64 = 5000; + +/// Database timeout in milliseconds for cold lookups +pub const DB_TIMEOUT_MS: u64 = 3000; + +/// SPL Token program ID (on-chain Token program) +pub const SPL_TOKEN_PROGRAM_ID: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); diff --git a/src/api/method/mod.rs b/src/api/method/mod.rs index 50073948..93a4496a 100644 --- a/src/api/method/mod.rs +++ b/src/api/method/mod.rs @@ -24,5 +24,6 @@ pub mod get_queue_elements; pub mod get_queue_info; pub mod get_transaction_with_compression_info; pub mod get_validity_proof; +pub mod interface; pub mod utils; diff --git a/src/api/rpc_server.rs b/src/api/rpc_server.rs index 5cc11dd8..b9649121 100644 --- a/src/api/rpc_server.rs +++ b/src/api/rpc_server.rs @@ -425,5 +425,26 @@ fn build_rpc_module(api_and_indexer: PhotonApi) -> Result, }, )?; + // Interface endpoints - race hot (on-chain) and cold (compressed) lookups + module.register_async_method( + "getAccountInterface", + |rpc_params, rpc_context| async move { + let api = rpc_context.as_ref(); + let payload = rpc_params.parse()?; + api.get_account_interface(payload).await.map_err(Into::into) + }, + )?; + + module.register_async_method( + "getMultipleAccountInterfaces", + |rpc_params, rpc_context| async move { + let api = rpc_context.as_ref(); + let payload = rpc_params.parse()?; + api.get_multiple_account_interfaces(payload) + .await + .map_err(Into::into) + }, + )?; + Ok(module) } diff --git a/src/openapi/mod.rs b/src/openapi/mod.rs index 5bfadf77..214d133e 100644 --- a/src/openapi/mod.rs +++ b/src/openapi/mod.rs @@ -33,6 +33,7 @@ use crate::api::method::get_validity_proof::{ AccountProofInputs, AddressProofInputs, CompressedProof, CompressedProofWithContext, CompressedProofWithContextV2, MerkleContextV2, RootIndex, TreeContextInfo, }; +use crate::api::method::interface::types::{AccountInterface, SolanaAccountData}; use crate::api::method::utils::PaginatedSignatureInfoList; use crate::api::method::utils::SignatureInfo; use crate::api::method::utils::SignatureInfoList; @@ -148,6 +149,9 @@ const JSON_CONTENT_TYPE: &str = "application/json"; TreeContextInfo, GetCompressedAccountProofResponseValue, GetCompressedAccountProofResponseValueV2, + // Interface types + AccountInterface, + SolanaAccountData, )))] struct ApiDoc; diff --git a/tests/data/transactions/indexer_interface/2Q8KnAuf9TuPThbkEFZp6tfFC9bsGBVEpvoDJzLZAAEDKi2eSZuEdjKrqw9ez2yhxJt5U7S8LYdrUdSq1KKZid4X b/tests/data/transactions/indexer_interface/2Q8KnAuf9TuPThbkEFZp6tfFC9bsGBVEpvoDJzLZAAEDKi2eSZuEdjKrqw9ez2yhxJt5U7S8LYdrUdSq1KKZid4X new file mode 100644 index 00000000..6514a3a3 --- /dev/null +++ b/tests/data/transactions/indexer_interface/2Q8KnAuf9TuPThbkEFZp6tfFC9bsGBVEpvoDJzLZAAEDKi2eSZuEdjKrqw9ez2yhxJt5U7S8LYdrUdSq1KKZid4X @@ -0,0 +1,158 @@ +{ + "slot": 200, + "transaction": [ + "AkX10M+vjtXvXVcyhHxy20yOQNg+i6YhaLQWTY9OjscFDTMeotSI3DKM8Scq2juC8isiS40iKcSP+MhwBK7TNARXGFC8jgns1c5ti9DfHEHnEEUFtf6CPX3hhcUuLbmNQuFPO/XOom3OP1WtMwxmUk4Hynw8nTXiWQQ8OkkCPJsJAgEIDjwnoQx7ujHJcfKDkl7hQKUz/Hvi6qrsfBpPmC20LrGTUl3YAEgdiOAbZtUAebWqVueellDUwIToGo3jD8DY3VUIpumYsF/pK5ig2fd52dvosvPu9ngTKHvrpSZJgJFovQv/FayGQswvkPcc7/1XU+ilA3gepE4uMS/o0kSPDPCgDI2bLhfzRRfeR7LAd9xMdGmgOSCB64sMQmncryF2aMP/FEBUY9NQC5zeHFjcA5wRMaQnaOChzXgQrzecV5U53QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqdV+CE5BU1EJLFa8MQwzy9Lf5h5OtoSUtSPNmbGy84JFaNXI3lOj7ZdB1trcmmcON0C5ZSLdbDloEGOgJdbRAksNuwi9ReDAP20Sqpq/8/wpG4cvGQcDj7QnaE7nvUIHuvEjPsyZLvDS/XFpag0/GdQAG8phtlvI1vIh1703USIrUFUKyGRFyFIIDtR9PTMC/j/zeXfXPye4yA/xd8IK+bJGLC9fM+RVESKer9qjzl4KaHo/Qin8NCzqrh4Uvwy+7ModRBcroW1tER2B+2/4UUnv7QjkRykBCO/0VJ6JnUN20rUZ+rp7CRfJxPQChsery38xTizp4HM/11v+0giagEIDgcBAAsFBAAMCg0JBgMCswJnAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAEAAAAHAAAAAAABJU17ueh1/feW4mxAqYqnn5xlI4gq8MetfQ2bCq+4U1ehgkf0jk6O8I5ArokNry+qwiWAIUrsmgfHjDnt8IUoCwmMOUiE6moo8MN5F0Ny/UIy52CpO8nCjC2M50yAgC/UJ19v2t3/LsIYbb6ly0PJAcgFlk2L7IebDm5T1PNJivUAAQAAAAAAAAAACQMA/xRAVGPTUAuc3hxY3AOcETGkJ2jgoc14EK83nFeVOd1SXdgASB2I4Btm1QB5tapW556WUNTAhOgajeMPwNjdVfwBPCehDHu6Mclx8oOSXuFApTP8e+Lqqux8Gk+YLbQusZMBPCehDHu6Mclx8oOSXuFApTP8e+Lqqux8Gk+YLbQusZMA", + "base64" + ], + "meta": { + "err": null, + "status": { + "Ok": null + }, + "fee": 10000, + "preBalances": [ + 99994966515, + 0, + 331204641, + 29687444, + 997278640, + 0, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 3048480, + 0, + 0 + ], + "postBalances": [ + 99994930513, + 0, + 331214641, + 29692446, + 994557280, + 2732360, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 3048480, + 0, + 0 + ], + "innerInstructions": [ + { + "index": 0, + "instructions": [ + { + "programIdIndex": 6, + "accounts": [ + 4, + 5 + ], + "data": "11113xKfKE6p9J9ueSoGmavScokzpTedhAJrNMacgmywBmT1tm1vFGSKi8kPhX5guiprAo", + "stackHeight": 2 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 5 + ], + "data": "3Bxs4iNAP7JpFgdV", + "stackHeight": 2 + }, + { + "programIdIndex": 7, + "accounts": [ + 0, + 12, + 10, + 13, + 9, + 6, + 3, + 2 + ], + "data": "SsreHtLmPZSmph3vsdxZMpf2WYPqC95uk5eE3MNA6WrSEc5Xyqb3DcHgPyM1FFK6D9iPD85Fd2zguWvfFuP372c3adQKWzTYHdNzPGhDSpBQaZu3oyZ8MBWFxGNCLZvCChsAKT3BfuhpA4pP7iSeVMwuMcrtEabo4ziZQfUBpBugTaZiF19Jc316RxiWvFPtMu5t635jj3TPdCyNr48a9fy5soUGmXoSLbvKktWacRpoyv2Tz1XPsaNJT4PKDH4tzJYb9mKNFCMcn3ekjf83JCCBeNufWnQ23w6UaG1WE8VRyVJPdBLzqQrpafqsaPYttf99VWDGfG3gPaNLgtKQnpcyjFefu77GmNHk5FnPpFvZGmW4HGuB8M6WkNjpZRcpGxUAVELPFBJmWNo2weSENcadsubjQgHLCrzNaXPJVoKopZmTsAhzercbZXMymDkwiXiUajT2Q1HUdCTJFqXggVNSrzamtULVnChxFH31iUUDXmQ7jppZJqV7nyJhrzmKJ6BQxCj5hvJQL5qdP2ixafJk5d", + "stackHeight": 2 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 2 + ], + "data": "3Bxs43ZMjSRQLs6o", + "stackHeight": 3 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 3 + ], + "data": "3Bxs41C4bWBEDcNb", + "stackHeight": 3 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 3 + ], + "data": "3Bxs4PckVVt51W8w", + "stackHeight": 3 + }, + { + "programIdIndex": 9, + "accounts": [ + 13, + 10, + 2, + 3 + ], + "data": "HDtpqY3uCYv8VK5FAXvJVKJiyeFUY1KJsHnwwLbivMrxEE5JmPBPHoCLNUJzwdQDk68HHfELvRZtMSVoM6iTvvEjFFWfzhRiXykKqnaMan7tthkyuLTKgq6BwoDffh2QjRvuT7Q3doiRs6xoEKDk7WAjPPRgSVVp8j16x45uJeWjXYDAbkL6EebJwvQSTTiTmdnmdLuYEAd46K8Ama2KFffMuDmqwjSGHqsEKwasYR8Z3RDggqtdZeJ5LJahZsQhTEj6WXuCp9fg2p4vCYYgXXYBX2XT2yTK8rRZ8wZTSCyuuVcCyfhjNCVLspbzhHVWNH1Lres54TWWNgJ57wA6YbGcUnRfDiuUPrtTE2Kt27tGXpf9aznCCPDzys52hKru3Bh2GnkVEa4J7sV", + "stackHeight": 3 + } + ] + } + ], + "logMessages": [ + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m invoke [1]", + "Program log: MintAction", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 invoke [2]", + "Program log: invoke_cpi_with_read_only", + "Program log: mode V2", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq invoke [3]", + "Program log: Instruction: InsertIntoQueues", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq consumed 7887 of 68064 compute units", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 consumed 121394 of 181534 compute units", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 success", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m consumed 139956 of 200000 compute units", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m success" + ], + "preTokenBalances": [], + "postTokenBalances": [], + "rewards": [], + "loadedAddresses": { + "writable": [], + "readonly": [] + }, + "computeUnitsConsumed": 139956 + }, + "blockTime": 1769454113 +} \ No newline at end of file diff --git a/tests/data/transactions/indexer_interface/2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd b/tests/data/transactions/indexer_interface/2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd new file mode 100644 index 00000000..66968c8a --- /dev/null +++ b/tests/data/transactions/indexer_interface/2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd @@ -0,0 +1,157 @@ +{ + "slot": 181, + "transaction": [ + "AU0mgPKoIcxqWWNDOxB0mQnROtQjP4uGrnPyvhrrS/Ns/RdY4AnJxBcRWOF1dc+KdHTxFWoYdL1+BMr3IWkfzgwBAAoOPCehDHu6Mclx8oOSXuFApTP8e+Lqqux8Gk+YLbQusZML/xWshkLML5D3HO/9V1PopQN4HqROLjEv6NJEjwzwoA3papgQCCfpwR3bIM+xFmRoYlGnMDhgngGQUuDiXFK0lom6RB9jsvMqIWoCd4Ulg7euwYGDqc2I4P4ScSwQhQgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAMGRm/lIRcy/+ytunLDm+e8jOW7xfcSayxDmzpAAAAABqdV+CE5BU1EJLFa8MQwzy9Lf5h5OtoSUtSPNmbGy84G3fbh12Whk9nL4UbO63msHLSF7V9bN5E6jPWFfv8AqQkVo1cjeU6Ptl0HW2tyaZw43QLllIt1sOWgQY6Al1tECSw27CL1F4MA/bRKqmr/z/Ckbhy8ZBwOPtCdoTue9QgLvA/Au0fKL3TEES6UqxPPo8Y05dwX6ssDzRojzX54fB7rxIz7MmS7w0v1xaWoNPxnUABvKYbZbyNbyIde9N1E5skYsL18z5FURIp6v2qPOXgpoej9CKfw0LOquHhS/DL7syh1EFyuhbW0RHYH7b/hRSe/tCORHKQEI7/RUnomdf427ipsEwFFqy88r4hvgc1jxHYducXzE7h0qGBGX02oAgUABQJAQg8ACA8AAAwDAgcGCwoNCQEIBAhh8SIwuiWze8ACAAAAvXb5WzGk9JaBZcitjB/xcMqTTXU1My2mkuHY7C6jjy7iIFXC69uRm/KOi+tBbbgYh8BI6jB4XeQTMyvupurcpwIAAAAAypo7AAAAAABlzR0AAAAAAA==", + "base64" + ], + "meta": { + "err": null, + "status": { + "Ok": null + }, + "fee": 5000, + "preBalances": [ + 99995027520, + 29677440, + 2039280, + 2923200, + 1, + 1, + 1141440, + 929020800, + 1141440, + 1141440, + 1141440, + 1614720, + 0, + 0 + ], + "postBalances": [ + 99995017518, + 29682442, + 2039280, + 2923200, + 1, + 1, + 1141440, + 929020800, + 1141440, + 1141440, + 1141440, + 1614720, + 0, + 0 + ], + "innerInstructions": [ + { + "index": 1, + "instructions": [ + { + "programIdIndex": 7, + "accounts": [ + 3, + 2, + 0 + ], + "data": "6AmSbVFP5kF9", + "stackHeight": 2 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 12, + 11, + 10, + 13, + 9, + 8, + 6, + 6, + 4, + 6, + 1 + ], + "data": "GTTgHALwTd7DpQtTbhDPe6Etuj33yy5U6jgYa2WWYaV5bxbWNAoYdv6GqxzfqaSCM5hfpmMaS2XqiKaBpmhGziUyBwjEmtxfYUJKhK7rf8rTopmkctMexb3fYyQP2GHm41uaogWrVYgBHDCZrm2mQpmet157csi1YDjpkM4QNFks6rXCKZyJsU64atn2qSSsqVFuFXuNRcuiFSbU9h1xW354vfPAaDj8TP7TVosEgyoRemqnZ6a9HTh43uiCJgfaop36ghCh2RDcJnQLy4Tmo2FqaqA3qwq97SqA71Qpa7xnfX3oLLwCyZ5scn6YLd3RXr5vNhqxk2CkWKZZV4arwmDJG3SW7N1nWDjXewrUo2aA9jrWHD72R73bhZi3iZA3PLFk9iQTeMJZm3JP1aT652osgroGsJ1Qddq35gBbCHQRa9M5vv3B8fHAhh34UmfKvA6YNgAjS6Hv7Zzw5W91LgsKZDhUsnWDTM", + "stackHeight": 2 + }, + { + "programIdIndex": 4, + "accounts": [ + 0, + 1 + ], + "data": "3Bxs4Px9qXVhzify", + "stackHeight": 3 + }, + { + "programIdIndex": 9, + "accounts": [ + 13, + 11, + 1 + ], + "data": "9d3AmkaMU85XDt4fU7UFAkrqRj3M5LhLS5fHMv6N4JJL5sZD7yoaCiaCdPo2PyUeapwFnA8Y132N9LAPWc2GV1KTFFwtRvfzgpaJKEbtWX25RDQTrTvRKYYkPDvb7DytLhT5ULmYZXuzf2tYQxnwwJgest8dqv2dJpraxQEdE4Bqx7FaGJTze3Z7fRjQKJJ4s7gNnwAvEkxewwbqTQXNhX32sSnxkZ8Y8jXfF8s8Juwr9osmY249FDqjQbmgvdEGqkd9gbLfGgC3e6EHbMBs2JtcEj4bYYLEx5eWHd", + "stackHeight": 3 + } + ] + } + ], + "logMessages": [ + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m invoke [1]", + "Program log: Instruction: MintTo", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", + "Program log: Instruction: MintTo", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4538 of 986662 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 invoke [2]", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq invoke [3]", + "Program log: Instruction: InsertIntoQueues", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq consumed 5020 of 956018 compute units", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 consumed 21167 of 972129 compute units", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 success", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m consumed 49171 of 999850 compute units", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m success" + ], + "preTokenBalances": [ + { + "accountIndex": 2, + "mint": "B8dxn19gmQFB7g1wHsiN2R5jkqEWw14B3CFNQZ9tDwbm", + "uiTokenAmount": { + "uiAmount": null, + "decimals": 2, + "amount": "0", + "uiAmountString": "0" + }, + "owner": "GXtd2izAiMJPwMEjfgTRH3d7k9mjn4Jq3JrWFv9gySYy", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "postTokenBalances": [ + { + "accountIndex": 2, + "mint": "B8dxn19gmQFB7g1wHsiN2R5jkqEWw14B3CFNQZ9tDwbm", + "uiTokenAmount": { + "uiAmount": 15000000.0, + "decimals": 2, + "amount": "1500000000", + "uiAmountString": "15000000" + }, + "owner": "GXtd2izAiMJPwMEjfgTRH3d7k9mjn4Jq3JrWFv9gySYy", + "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" + } + ], + "rewards": [], + "loadedAddresses": { + "writable": [], + "readonly": [] + }, + "computeUnitsConsumed": 49321 + }, + "blockTime": 1769454104 +} \ No newline at end of file diff --git a/tests/data/transactions/indexer_interface/2afJTiZyNEMvrKJasbDFqPaTaLWMttjAHnBLgm7CizqzqsiqFp6pXAB9fdrFHq66u6zvv3ddY5xLAzpmREASatnB b/tests/data/transactions/indexer_interface/2afJTiZyNEMvrKJasbDFqPaTaLWMttjAHnBLgm7CizqzqsiqFp6pXAB9fdrFHq66u6zvv3ddY5xLAzpmREASatnB new file mode 100644 index 00000000..85666707 --- /dev/null +++ b/tests/data/transactions/indexer_interface/2afJTiZyNEMvrKJasbDFqPaTaLWMttjAHnBLgm7CizqzqsiqFp6pXAB9fdrFHq66u6zvv3ddY5xLAzpmREASatnB @@ -0,0 +1,114 @@ +{ + "slot": 208, + "transaction": [ + "AU8LXvOcRJuGCjHXPKqHFyWVyEl7rT90u4shh2Vy9uNYNig5cL0OePQA16cEVuIOXcewwrnIxH89mrCiV8tWrAABAAgNPCehDHu6Mclx8oOSXuFApTP8e+Lqqux8Gk+YLbQusZMI6H6PkrgpCuD+a6ghBiFJ+7bEwI+4xaykgT6BErceDwv/FayGQswvkPcc7/1XU+ilA3gepE4uMS/o0kSPDPCgDI2bLhfzRRfeR7LAd9xMdGmgOSCB64sMQmncryF2aMP/FEBUY9NQC5zeHFjcA5wRMaQnaOChzXgQrzecV5U53QAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqdV+CE5BU1EJLFa8MQwzy9Lf5h5OtoSUtSPNmbGy84JFaNXI3lOj7ZdB1trcmmcON0C5ZSLdbDloEGOgJdbRAksNuwi9ReDAP20Sqpq/8/wpG4cvGQcDj7QnaE7nvUIHuvEjPsyZLvDS/XFpag0/GdQAG8phtlvI1vIh1703USIrUFUKyGRFyFIIDtR9PTMC/j/zeXfXPye4yA/xd8IK+bJGLC9fM+RVESKer9qjzl4KaHo/Qin8NCzqrh4Uvwy+7ModRBcroW1tER2B+2/4UUnv7QjkRykBCO/0VJ6JnUiA7TT6TASDX8cJIvdrUQV4V/RQJjaJBFxQv0uKK3+CgEHDgYACgQDAAsJDAgFAgECFGcDAAAAAQAAAAAAAQAAAAgAAAAA", + "base64" + ], + "meta": { + "err": null, + "status": { + "Ok": null + }, + "fee": 5000, + "preBalances": [ + 99994930513, + 331184640, + 29692446, + 994557280, + 2732360, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 3048480, + 0, + 0 + ], + "postBalances": [ + 99994920512, + 331184640, + 29697447, + 997289640, + 0, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 3048480, + 0, + 0 + ], + "innerInstructions": [ + { + "index": 0, + "instructions": [ + { + "programIdIndex": 6, + "accounts": [ + 0, + 11, + 9, + 12, + 8, + 5, + 2, + 1, + 2 + ], + "data": "7yPYWt3P1KLPqjnnhJNfj5DorRne6QD8zS9JUUYH4kJpXGovUoiE6HxphCA6gsTLyzN2ch4UUJXkk86r6mthoWQvFC3bYagFdqeRCsJkmezxzSJeWmGRJGNMeJ9sTXq2jDJCx8UP57yWiigktnJszKufAmgveJGD8VxrpnHgTPeQaaB1V6TTNP11FBcDypXyJmuSZkktnDZCo7AN8W3LAZBkiyu47F3z3Xodf7E4HVKD3UXv1Wy5GkS2qnkyWy6V9NQvPaK2xcrVLUGT1DmUSfptTTPa7ndBqDwqrGAc2EFMBW2cAFVxh1eWNrFtN6Hw5AqDEXy9FeV3NqPJdmgX2UB81jkdZPeiD9RoWdkK6UFAbQr17k2X6cysEqycpcmpimxLwKfwtTTVyrgNWiTcuC6PmhZdqD8j8sNrwredsq7pRBndp39RVvmvRNxuVVKw3wmVrmavgq4bVeFukqABddKsL6pjoRESq5WxPqnJiTGdF1uPRXVBgU4wx9cvRPMHHWLo4XTtJM86PPZEq7JC2sUkU36ntPSUUVE36KSCTZa3mGFXBYkqjHgYpJsUERL2BFFg6sZViyPqeS1ncQ7s8YTsmxvHXC2ss27MmnzvJjUYybnHxWgcuLdjwACJ5VU88sPGZscaHhHmWcaQuaPJ7sPFQitGBYLmDYnirNgi2cf58BxZ4PG9vDS7PPJeTzv9yL8h5YP3qGWJwiakjS2LF1rdx9FCM85KbFYLU7LUQk24Ej", + "stackHeight": 2 + }, + { + "programIdIndex": 5, + "accounts": [ + 0, + 2 + ], + "data": "3Bxs4PnTAWgtW7QT", + "stackHeight": 3 + }, + { + "programIdIndex": 8, + "accounts": [ + 12, + 9, + 2, + 2, + 1 + ], + "data": "95YB9JH8MTYtuZfgNwFoqXrHxz6iXNSKY1qkjTcBMMeHjhd7su25YYcxsur46vsYc4kvTLvUGUB1E2EmdLVQzNBiyrMqCRy82cF6QSUzwTvHFrkC9LSD49oYxj89q7W1UAdFFvB6nrfud9pEUsDGM8sRYKYu3HqkPs5FYBpbAA2yvUEFvSqnRXpbYxpxFgPJ8EGrQrcsW5pVHvrixd89yT1P2Mpzaacg8e9SQRjZS3t2qWHmmnwutPE2AEpy9jszxwjbgNvcUkj18drGNNfKox7Dn64QSWNDmb9CKqh7rska5Lp1yghsDRnQUuh6MLaLust5qEKUHDK568Cih2T83NeZasP84hce5UEDcoinBEtKrSjoFUB7vm9oERjjwDn9bBUoATx31CYHiokexpQwpT", + "stackHeight": 3 + } + ] + } + ], + "logMessages": [ + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m invoke [1]", + "Program log: MintAction", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 invoke [2]", + "Program log: invoke_cpi_with_read_only", + "Program log: mode V2", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq invoke [3]", + "Program log: Instruction: InsertIntoQueues", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq consumed 9419 of 171642 compute units", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 consumed 28244 of 190430 compute units", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 success", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m consumed 37908 of 200000 compute units", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m success" + ], + "preTokenBalances": [], + "postTokenBalances": [], + "rewards": [], + "loadedAddresses": { + "writable": [], + "readonly": [] + }, + "computeUnitsConsumed": 37908 + }, + "blockTime": 1769454116 +} \ No newline at end of file diff --git a/tests/data/transactions/indexer_interface/5bLkzWasPYAivyrVvrt5UN3amycT3MSdNB2evCEMyuW1Ajbufv4nTbqrp7ZQ5fpopHh7pU9RnimvvR31XeckFt9F b/tests/data/transactions/indexer_interface/5bLkzWasPYAivyrVvrt5UN3amycT3MSdNB2evCEMyuW1Ajbufv4nTbqrp7ZQ5fpopHh7pU9RnimvvR31XeckFt9F new file mode 100644 index 00000000..66a67be0 --- /dev/null +++ b/tests/data/transactions/indexer_interface/5bLkzWasPYAivyrVvrt5UN3amycT3MSdNB2evCEMyuW1Ajbufv4nTbqrp7ZQ5fpopHh7pU9RnimvvR31XeckFt9F @@ -0,0 +1,158 @@ +{ + "slot": 193, + "transaction": [ + "AuWunKtcv7kqto1NtjY8HIuzotEs+lg1kijLpU+PBwo0mYt51Ln4bh1F9NOgiGpRmUty4UE6FueiV0W9DTjXYwqAsevIRqtuTRPENNSzGW7y2vIVX3wxPdQTp9JRwz/57LvsV3lUbmBUaKE2HIG2K4KQyyaLMP5npN/xHkt+paMAAgEIDjwnoQx7ujHJcfKDkl7hQKUz/Hvi6qrsfBpPmC20LrGTMtb6DSl+WkiPAtcrxA8NVI+tc289204ixlOq983dKEcIpumYsF/pK5ig2fd52dvosvPu9ngTKHvrpSZJgJFovQv/FayGQswvkPcc7/1XU+ilA3gepE4uMS/o0kSPDPCgDI2bLhfzRRfeR7LAd9xMdGmgOSCB64sMQmncryF2aMOqHn30jJgOMQTkdobcfQiPsJtmK5kNekZQUhC5RGMHSAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABqdV+CE5BU1EJLFa8MQwzy9Lf5h5OtoSUtSPNmbGy84JFaNXI3lOj7ZdB1trcmmcON0C5ZSLdbDloEGOgJdbRAksNuwi9ReDAP20Sqpq/8/wpG4cvGQcDj7QnaE7nvUIHuvEjPsyZLvDS/XFpag0/GdQAG8phtlvI1vIh1703USIrUFUKyGRFyFIIDtR9PTMC/j/zeXfXPye4yA/xd8IK+bJGLC9fM+RVESKer9qjzl4KaHo/Qin8NCzqrh4Uvwy+7ModRBcroW1tER2B+2/4UUnv7QjkRykBCO/0VJ6JnVMF4x44Hz7GtbAJgLPgC0V51Frv1yJL2Zbk7+uCvjBgQEIDgcBAAsFBAAMCg0JBgMCkwJnAAAAAAAAAAAAAQAAAAAAAAAAAAAAAAEAAAAHAAAAAAABAZi6vOM5+jYyfzW0tiOzPz0FS26iRcNK0P98UId9FU6ruLyzZ2rzuMC5iE4jD2hI3y6+KgtNCdbEHDjqzRXQOSdyPKepwSiCmdX4eYgL+4yMbYaifBspG1KAotUoacNrrXqc78QvOFGYjsG7eoaMFRcbW7ulIBRLim0QA0PLp/YAAQAAAAAAAAAABgMAqh599IyYDjEE5HaG3H0Ij7CbZiuZDXpGUFIQuURjB0gy1voNKX5aSI8C1yvEDw1Uj61zbz3bTiLGU6r3zd0oR/8BPCehDHu6Mclx8oOSXuFApTP8e+Lqqux8Gk+YLbQusZMAAA==", + "base64" + ], + "meta": { + "err": null, + "status": { + "Ok": null + }, + "fee": 10000, + "preBalances": [ + 99995002517, + 0, + 331194641, + 29682442, + 1000000000, + 0, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 3048480, + 0, + 0 + ], + "postBalances": [ + 99994966515, + 0, + 331204641, + 29687444, + 997278640, + 2732360, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 3048480, + 0, + 0 + ], + "innerInstructions": [ + { + "index": 0, + "instructions": [ + { + "programIdIndex": 6, + "accounts": [ + 4, + 5 + ], + "data": "11113xKfKE6p9J9ueSoGmavScokzpTedhAJrNMacgmywBmT1tm1vFGSKi8kPhX5guiprAo", + "stackHeight": 2 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 5 + ], + "data": "3Bxs4iNAP7JpFgdV", + "stackHeight": 2 + }, + { + "programIdIndex": 7, + "accounts": [ + 0, + 12, + 10, + 13, + 9, + 6, + 3, + 2 + ], + "data": "SsreHtLmPZSmph3vsdxZMpf2WYPqC95uk5eE3MNA6WrSEc5Xyqb3DcHgPyM1FFK6D9iPD85Fd2zguWaLho3EC7ujP4ng4EZ3qCbzGSWxnrNRiC3USzXkjCy83WiMTkvQ7Z9SFADiEZpFS9fuQqWVz5eyy1Mtno2i8WyQ3HW1VjNkUHDjkJxHLavNCn8UQEhrYqoRGr2r2ufXusxvKwFzbKFi64EUSEMFzA2iGQ3gBjNPeByjUAJ4dbZUX4Cyhh8VcBqTXUx6B6UmNTZ3SDYFKidJVarjCDfwVKa4RGenMJZ3b8wFAVzu9FyFLtoSp5yPoBg8LkkbkYXQjnXxaNvaCFNy7vJQkDDU6Zi46EVVx7XmJhAgUMP4x65xMn41dyf1T85BsZKK1fmfqCqbfQn3bod5jbQWiUUvzbrDeqUuYx1oVHQ5uLnPVvmBBCeJy6HWLyD4CfFE3oZRgMfK6aarzBRrDhTVyswtnKf4ZDhsPPqXhSxNkKWNjZ3XkLxqjWqmW3ZwUW7HxU1vP9BDysFVutwqAP", + "stackHeight": 2 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 2 + ], + "data": "3Bxs43ZMjSRQLs6o", + "stackHeight": 3 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 3 + ], + "data": "3Bxs41C4bWBEDcNb", + "stackHeight": 3 + }, + { + "programIdIndex": 6, + "accounts": [ + 0, + 3 + ], + "data": "3Bxs4PckVVt51W8w", + "stackHeight": 3 + }, + { + "programIdIndex": 9, + "accounts": [ + 13, + 10, + 2, + 3 + ], + "data": "HDtpqY3uCYv8VK5FAXvJVKJiyeFUY1KJsHnwwLbivMrxEE5JmPBPHoCLNUJzwdQDk68HHfEMf5Xnt1Fm2otBYmxvscTYkmVupf9G1BrBgdoRqPzYqx9KMYqykNczWyupQCxSuTTDrFqeWjtygFFH8qSZzYBwBTmiiVYbcBe1Bo8GQRsfmZ4uiWQoFtJWtyyk8rhqMSfUHtgAvjoPN2d9hWXW5nafb4sPr9zDxb3NkLdp8ej8Fdogyh8czH81eUUvActkPVZTi75zyaoNPvKqVtW7Bg1pAodLD4kKkHhHndp7QtD9X9vV37ZMgU5cwMXcah9vV7RhqVfgeCXAygbQBu9wcPkBnPfDyqXn2rNKQRcheoWwqxj2J4koibvtUtbH9mJioDyutZ1oF1R", + "stackHeight": 3 + } + ] + } + ], + "logMessages": [ + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m invoke [1]", + "Program log: MintAction", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [2]", + "Program 11111111111111111111111111111111 success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 invoke [2]", + "Program log: invoke_cpi_with_read_only", + "Program log: mode V2", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq invoke [3]", + "Program log: Instruction: InsertIntoQueues", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq consumed 7887 of 72596 compute units", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 consumed 121394 of 186066 compute units", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 success", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m consumed 135424 of 200000 compute units", + "Program cTokenmWW8bLPjZEBAUgYy3zKxQZW6VKi7bqNFEVv3m success" + ], + "preTokenBalances": [], + "postTokenBalances": [], + "rewards": [], + "loadedAddresses": { + "writable": [], + "readonly": [] + }, + "computeUnitsConsumed": 135424 + }, + "blockTime": 1769454109 +} \ No newline at end of file diff --git a/tests/data/transactions/indexer_interface/628ZqqrNWuVUfHF2seH7XQEZqBJtWA8NaAjcVeH96XWaubUSeWpegrdfvrPkGA8qxfBFpu5ru9DjTFktRSB6w4s1 b/tests/data/transactions/indexer_interface/628ZqqrNWuVUfHF2seH7XQEZqBJtWA8NaAjcVeH96XWaubUSeWpegrdfvrPkGA8qxfBFpu5ru9DjTFktRSB6w4s1 new file mode 100644 index 00000000..7143dbc5 --- /dev/null +++ b/tests/data/transactions/indexer_interface/628ZqqrNWuVUfHF2seH7XQEZqBJtWA8NaAjcVeH96XWaubUSeWpegrdfvrPkGA8qxfBFpu5ru9DjTFktRSB6w4s1 @@ -0,0 +1,115 @@ +{ + "slot": 192, + "transaction": [ + "AfsPUmjOEBICNrhP7/Bg2o9koAwZ2oY8a/MQzvBpCrlc8YqlThsS2hSNtXJqkoBYwVPiwwdah77JQjbepbbS4gABAAkLPCehDHu6Mclx8oOSXuFApTP8e+Lqqux8Gk+YLbQusZMIpumYsF/pK5ig2fd52dvosvPu9ngTKHvrpSZJgJFovQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAwZGb+UhFzL/7K26csOb57yM5bvF9xJrLEObOkAAAAAGp1X4ITkFTUQksVrwxDDPL0t/mHk62hJS1I82ZsbLzgksNuwi9ReDAP20Sqpq/8/wpG4cvGQcDj7QnaE7nvUIC7wPwLtHyi90xBEulKsTz6PGNOXcF+rLA80aI81+eHwe68SM+zJku8NL9cWlqDT8Z1AAbymG2W8jW8iHXvTdRNWem8sa08HDC9sJmzqsOsj+S+dqH6i3TLNx6mW/Y5xi9f/NHLoyuMDzJdu5uE5yCqPBB+d1u+u44BM7lLKWQ/L7syh1EFyuhbW0RHYH7b/hRSe/tCORHKQEI7/RUnomdQflONqnQEnTSXyD+ptXOtcIdrRa5K5HsdBhsmpzu8yWAgMABQJAQg8ACAoABAUKBwYICQIBgAIx1L+BJ8IrxPMAAABWL6OmFd9cCAD/1Z6byxrTwcML2wmbOqw6yP5L52ofqLdMs3HqZb9jnGIAAAAAAAAAAAAAAQAAAAEmb4gY4t+qkKEhVaTDn5Ilgei4BYNQdfyEHk1ly1JGxA60J22rap8E3REII0w22VHmKvaSG7I+NrP42R6HXdBsLbZ0BS0Gp/MT4S8hwuMMh/E3GVOMexZ7Oq1NgrNu0juDiEZXj/+M6ysKKbZcbac4fWisuPBckRrLrs185dp0wQEAAAAqKioqKioqKioqKioqKioqKioqKioqKioqKioqKioqKgAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/", + "base64" + ], + "meta": { + "err": null, + "status": { + "Ok": null + }, + "fee": 5000, + "preBalances": [ + 99995017518, + 331184640, + 1, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 1141440, + 0, + 0 + ], + "postBalances": [ + 99995002517, + 331194641, + 1, + 1, + 1141440, + 1141440, + 1141440, + 1614720, + 1141440, + 0, + 0 + ], + "innerInstructions": [ + { + "index": 1, + "instructions": [ + { + "programIdIndex": 4, + "accounts": [ + 0, + 9, + 7, + 6, + 10, + 5, + 8, + 4, + 4, + 2, + 4, + 1 + ], + "data": "BqT7gkM6QBUXLrebMuy9CaECRJVBDqCrrkzhkYSUzDvv98DeYSB9aE7c7gULTn24ZQLCzP11o1hX4SUYQaJC3V6xgkhkK3EZPddj4RKWAZQABjBp5nCzEZuZtWLpyagyQgUk9RvPxzGVZMXkR3gqsunjMy8oDT73cv41srUqyc56kRTSLvkRwzqizowJKdWUFxsWbt6FCWPEGBFw79WPV3FBvmA4kWVNM2jTuKhm5Zr422BJdp2VcxgTjY4efecNV3JjUGv3nZ6SX2jVRTBEFDzC1xhXcN7n3Bb5cTMPbWyChs9WyTcMM4vJijHm6pVAecWQjEkUxmQs", + "stackHeight": 2 + }, + { + "programIdIndex": 2, + "accounts": [ + 0, + 1 + ], + "data": "3Bxs43j4QTEDqUNK", + "stackHeight": 3 + }, + { + "programIdIndex": 5, + "accounts": [ + 10, + 7, + 1 + ], + "data": "gK3e1kzqySfsx4tv3nzLMZFLDuiod2Yo4Ayk9tULRFFquKTNa1tMWGhsXsKvAdGNkc4anw77fExSM5RvUkhM5bjJ8zuEXpJ7WD8bDCXHyUbDFS3dtLq3FfiVPsWj5AoNQfS27FS3mMVcMLuSgTUWSMYndJ6CJG3xi3HVTGCzdP8oiNCmobqQVdqPALH8Gsud8AsEYzBTuCkJXk18QKgXnk7KkZYNMyRxYEMohxpD5ofNTTD", + "stackHeight": 3 + } + ] + } + ], + "logMessages": [ + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy invoke [1]", + "Program log: Instruction: InvokeCpi", + "Program consumption: 996329 units remaining", + "Program consumption: 993542 units remaining", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 invoke [2]", + "Program log: invoke_cpi_with_read_only", + "Program log: mode Anchor", + "Program 11111111111111111111111111111111 invoke [3]", + "Program 11111111111111111111111111111111 success", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq invoke [3]", + "Program log: Instruction: InsertIntoQueues", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq consumed 4712 of 883793 compute units", + "Program compr6CUsB5m2jS4Y3831ztGSTnDpnKJTKS95d64XVq success", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 consumed 110338 of 989382 compute units", + "Program SySTEM1eSU2p4BGQfQpimFEWWSC1XDFeun3Nqzz3rT7 success", + "Program FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy consumed 121427 of 999850 compute units", + "Program FNt7byTHev1k5x2cXZLBr8TdWiC3zoP5vcnZR4P682Uy success" + ], + "preTokenBalances": [], + "postTokenBalances": [], + "rewards": [], + "loadedAddresses": { + "writable": [], + "readonly": [] + }, + "computeUnitsConsumed": 121577 + }, + "blockTime": 1769454109 +} \ No newline at end of file diff --git a/tests/integration_tests/interface_tests.rs b/tests/integration_tests/interface_tests.rs new file mode 100644 index 00000000..f753b3e1 --- /dev/null +++ b/tests/integration_tests/interface_tests.rs @@ -0,0 +1,222 @@ +use std::sync::Arc; + +use function_name::named; +use futures::{pin_mut, StreamExt}; +use photon_indexer::api::method::interface::{ + GetAccountInterfaceRequest, GetMultipleAccountInterfacesRequest, +}; +use photon_indexer::common::typedefs::serializable_pubkey::SerializablePubkey; +use photon_indexer::ingester::index_block; +use photon_indexer::ingester::typedefs::block_info::{BlockInfo, BlockMetadata}; +use sea_orm::DatabaseConnection; +use serial_test::serial; +use solana_client::nonblocking::rpc_client::RpcClient; + +use crate::utils::*; + +/// Directory containing interface test transaction data. +/// Generated by forester's test_indexer_interface test. +const INTERFACE_TEST_DATA_DIR: &str = "indexer_interface"; + +/// Helper to set up indexing methodologies for interface tests. +fn all_indexing_methodologies_for_interface( + db_conn: Arc, + rpc_client: Arc, + txns: &[&str], +) -> impl futures::Stream { + let txs = txns.iter().map(|x| x.to_string()).collect::>(); + async_stream::stream! { + reset_tables(db_conn.as_ref()).await.unwrap(); + populate_test_tree_metadata(db_conn.as_ref()).await; + index_block( + db_conn.as_ref(), + &BlockInfo { + metadata: BlockMetadata { + slot: 0, + ..Default::default() + }, + ..Default::default() + }, + ) + .await + .unwrap(); + + for tx in &txs { + index_transaction(INTERFACE_TEST_DATA_DIR, db_conn.clone(), rpc_client.clone(), tx).await; + } + yield (); + } +} + +/// Test getAccountInterface resolves compressed token accounts by token owner pubkey. +#[named] +#[rstest] +#[tokio::test] +#[serial] +async fn test_get_account_interface_token_owner( + #[values(DatabaseBackend::Sqlite, DatabaseBackend::Postgres)] db_backend: DatabaseBackend, +) { + let name = trim_test_name(function_name!()); + let setup = setup_with_options( + name.clone(), + TestSetupOptions { + network: Network::Localnet, + db_backend, + }, + ) + .await; + + // Mint compressed tokens to Bob and Charlie + let mint_tokens_tx = + "2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd"; + + // Bob's pubkey is the token owner. Interface lookup should return + // synthetic account data plus compressed token accounts in `cold`. + let bob_pubkey = + SerializablePubkey::try_from("DkbH1tracp6nxSQLrHQqJwVE7NaDAAb7eGKzfB9TwBdF").unwrap(); + + let txs = [mint_tokens_tx]; + let indexing = + all_indexing_methodologies_for_interface(setup.db_conn.clone(), setup.client.clone(), &txs); + pin_mut!(indexing); + + while let Some(_) = indexing.next().await { + // getAccountInterface must support token-owner lookups. + let result = setup + .api + .get_account_interface(GetAccountInterfaceRequest { + address: bob_pubkey, + }) + .await + .unwrap(); + + let value = result.value.clone().expect("expected interface value"); + let cold = value.cold.expect("expected compressed token accounts"); + assert!( + !cold.is_empty(), + "expected at least one compressed token account" + ); + } +} + +/// Test getMultipleAccountInterfaces with mixed addresses. +/// +/// Tests batch lookup with addresses that don't exist in compressed DB. +#[named] +#[rstest] +#[tokio::test] +#[serial] +async fn test_get_multiple_account_interfaces( + #[values(DatabaseBackend::Sqlite, DatabaseBackend::Postgres)] db_backend: DatabaseBackend, +) { + let name = trim_test_name(function_name!()); + let setup = setup_with_options( + name.clone(), + TestSetupOptions { + network: Network::Localnet, + db_backend, + }, + ) + .await; + + // Mint compressed tokens to Bob and Charlie + let mint_tokens_tx = + "2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd"; + + // Token owner pubkeys. + let bob_pubkey = + SerializablePubkey::try_from("DkbH1tracp6nxSQLrHQqJwVE7NaDAAb7eGKzfB9TwBdF").unwrap(); + let charlie_pubkey = + SerializablePubkey::try_from("GDhjk4DmDQ8bFWqrdcLGaJcYBDnq73ExjGyZYrca6nDc").unwrap(); + // Use a random address that definitely doesn't exist on-chain or compressed + // (default pubkey 11111... is the system program which exists on-chain) + let nonexistent_address = + SerializablePubkey::try_from("DeadDeadDeadDeadDeadDeadDeadDeadDeadDeadDead").unwrap(); + + let txs = [mint_tokens_tx]; + let indexing = + all_indexing_methodologies_for_interface(setup.db_conn.clone(), setup.client.clone(), &txs); + pin_mut!(indexing); + + while let Some(_) = indexing.next().await { + // Test getMultipleAccountInterfaces + let result = setup + .api + .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { + addresses: vec![bob_pubkey, charlie_pubkey, nonexistent_address], + }) + .await + .unwrap(); + + // Both owner pubkeys should resolve to token-backed interfaces. + assert_eq!(result.value.len(), 3); + assert!(result.value[0] + .as_ref() + .and_then(|v| v.cold.as_ref()) + .is_some_and(|cold| !cold.is_empty())); + assert!(result.value[1] + .as_ref() + .and_then(|v| v.cold.as_ref()) + .is_some_and(|cold| !cold.is_empty())); + assert!(result.value[2].is_none()); + } +} + +/// Test batch size validation for getMultipleAccountInterfaces. +#[named] +#[rstest] +#[tokio::test] +#[serial] +async fn test_get_multiple_account_interfaces_validation( + #[values(DatabaseBackend::Sqlite, DatabaseBackend::Postgres)] db_backend: DatabaseBackend, +) { + let name = trim_test_name(function_name!()); + let setup = setup_with_options( + name.clone(), + TestSetupOptions { + network: Network::Localnet, + db_backend, + }, + ) + .await; + + // Test empty request - should fail + let empty_result = setup + .api + .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { addresses: vec![] }) + .await; + + assert!(empty_result.is_err()); + + // Test over limit - should fail (MAX_BATCH_SIZE is 100) + let over_limit: Vec = + (0..101).map(|_| SerializablePubkey::default()).collect(); + + let over_limit_result = setup + .api + .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { + addresses: over_limit, + }) + .await; + + assert!(over_limit_result.is_err()); +} + +/* +## Test Data + +Test data is generated by forester's test_indexer_interface test: + cd light-protocol/forester && cargo test -p forester --test test_indexer_interface -- --nocapture + +Then exported using: + cargo xtask export-photon-test-data --test-name indexer_interface + +The test creates: +1. SPL Mint (on-chain) - standard mint for token operations +2. Compressed token accounts (via mint_to) - these have NO address field +3. Registered v2 address in batched address tree - for address tree verification +4. Compressible token accounts - on-chain accounts that can be compressed + +Transaction files are stored in tests/data/transactions/indexer_interface/ + +*/ diff --git a/tests/integration_tests/main.rs b/tests/integration_tests/main.rs index 78bad68e..b6691a99 100644 --- a/tests/integration_tests/main.rs +++ b/tests/integration_tests/main.rs @@ -6,6 +6,7 @@ mod batch_append_nullified_test; mod batched_address_tree_tests; mod batched_state_tree_tests; mod e2e_tests; +mod interface_tests; mod merkle_tree_deserialization; mod mock_tests; mod monitor_tests; diff --git a/tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_compressed_only-account-interface.snap b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_compressed_only-account-interface.snap new file mode 100644 index 00000000..b3875ed4 --- /dev/null +++ b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_compressed_only-account-interface.snap @@ -0,0 +1,11 @@ +--- +source: tests/integration_tests/interface_tests.rs +assertion_line: 107 +expression: result +--- +{ + "context": { + "slot": 0 + }, + "value": null +} diff --git a/tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_nonexistent-account-interface.snap b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_nonexistent-account-interface.snap new file mode 100644 index 00000000..a9bd9223 --- /dev/null +++ b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_account_interface_nonexistent-account-interface.snap @@ -0,0 +1,11 @@ +--- +source: tests/integration_tests/interface_tests.rs +assertion_line: 106 +expression: result +--- +{ + "context": { + "slot": 0 + }, + "value": null +} diff --git a/tests/integration_tests/snapshots/integration_tests__interface_tests__get_multiple_account_interfaces-multiple-account-interfaces.snap b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_multiple_account_interfaces-multiple-account-interfaces.snap new file mode 100644 index 00000000..3ee0f30e --- /dev/null +++ b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_multiple_account_interfaces-multiple-account-interfaces.snap @@ -0,0 +1,15 @@ +--- +source: tests/integration_tests/interface_tests.rs +assertion_line: 230 +expression: result +--- +{ + "context": { + "slot": 0 + }, + "value": [ + null, + null, + null + ] +} diff --git a/tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_by_owner-token-account-interface.snap b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_by_owner-token-account-interface.snap new file mode 100644 index 00000000..06f65e54 --- /dev/null +++ b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_by_owner-token-account-interface.snap @@ -0,0 +1,11 @@ +--- +source: tests/integration_tests/interface_tests.rs +assertion_line: 161 +expression: result +--- +{ + "context": { + "slot": 0 + }, + "value": null +} diff --git a/tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_compressed_only-token-account-interface.snap b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_compressed_only-token-account-interface.snap new file mode 100644 index 00000000..a280f25a --- /dev/null +++ b/tests/integration_tests/snapshots/integration_tests__interface_tests__get_token_account_interface_compressed_only-token-account-interface.snap @@ -0,0 +1,11 @@ +--- +source: tests/integration_tests/interface_tests.rs +assertion_line: 157 +expression: result +--- +{ + "context": { + "slot": 0 + }, + "value": null +} From c92b363ae8ac02955aa8654fecc5bae620230b99 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 3 Mar 2026 15:30:38 +0000 Subject: [PATCH 09/16] fix: remove redundant comment for SPL Token program ID in types.rs --- src/api/method/interface/types.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/api/method/interface/types.rs b/src/api/method/interface/types.rs index 42ba4a8d..737979a9 100644 --- a/src/api/method/interface/types.rs +++ b/src/api/method/interface/types.rs @@ -81,7 +81,4 @@ pub const MAX_BATCH_SIZE: usize = 100; pub const RPC_TIMEOUT_MS: u64 = 5000; /// Database timeout in milliseconds for cold lookups -pub const DB_TIMEOUT_MS: u64 = 3000; - -/// SPL Token program ID (on-chain Token program) -pub const SPL_TOKEN_PROGRAM_ID: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); +pub const DB_TIMEOUT_MS: u64 = 3000; \ No newline at end of file From 789200ae05982c7f993f05ac699b00d71eeb6949 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Tue, 3 Mar 2026 18:47:05 +0000 Subject: [PATCH 10/16] feat: add discriminator_v2 field to account interface and update related test structure --- src/api/method/interface/racing.rs | 1 + src/api/method/interface/types.rs | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/api/method/interface/racing.rs b/src/api/method/interface/racing.rs index 8ed98f2f..fa5efeb5 100644 --- a/src/api/method/interface/racing.rs +++ b/src/api/method/interface/racing.rs @@ -1030,6 +1030,7 @@ mod tests { prev_spent: Some(false), tx_hash: None, onchain_pubkey, + discriminator_v2: None, tree_type: Some(3), nullified_in_tree: false, nullifier_queue_index: None, diff --git a/src/api/method/interface/types.rs b/src/api/method/interface/types.rs index 737979a9..d120bab8 100644 --- a/src/api/method/interface/types.rs +++ b/src/api/method/interface/types.rs @@ -1,5 +1,4 @@ use serde::{Deserialize, Serialize}; -use solana_pubkey::{pubkey, Pubkey}; use utoipa::ToSchema; use crate::common::typedefs::account::AccountV2; @@ -81,4 +80,4 @@ pub const MAX_BATCH_SIZE: usize = 100; pub const RPC_TIMEOUT_MS: u64 = 5000; /// Database timeout in milliseconds for cold lookups -pub const DB_TIMEOUT_MS: u64 = 3000; \ No newline at end of file +pub const DB_TIMEOUT_MS: u64 = 3000; From 741ff8448b221be85dba35c5b09e70570853a396 Mon Sep 17 00:00:00 2001 From: Sergey Timoshin Date: Wed, 4 Mar 2026 20:44:46 +0000 Subject: [PATCH 11/16] fix: add missing rpc_client arg to interface_tests index_block call --- tests/integration_tests/interface_tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/integration_tests/interface_tests.rs b/tests/integration_tests/interface_tests.rs index f753b3e1..f93f1736 100644 --- a/tests/integration_tests/interface_tests.rs +++ b/tests/integration_tests/interface_tests.rs @@ -37,6 +37,7 @@ fn all_indexing_methodologies_for_interface( }, ..Default::default() }, + &rpc_client, ) .await .unwrap(); From b73f7533f37648c030fd14dd00003fb7a6aea7f1 Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Tue, 10 Mar 2026 02:44:48 +0000 Subject: [PATCH 12/16] fix get_account_interface --- .../method/interface/get_account_interface.rs | 3 +- .../get_multiple_account_interfaces.rs | 10 +- src/api/method/interface/racing.rs | 141 +++++++++++++++++- src/api/method/interface/types.rs | 24 +++ tests/integration_tests/interface_tests.rs | 8 +- 5 files changed, 176 insertions(+), 10 deletions(-) diff --git a/src/api/method/interface/get_account_interface.rs b/src/api/method/interface/get_account_interface.rs index cc6aa514..b184046d 100644 --- a/src/api/method/interface/get_account_interface.rs +++ b/src/api/method/interface/get_account_interface.rs @@ -15,8 +15,9 @@ pub async fn get_account_interface( request: GetAccountInterfaceRequest, ) -> Result { let context = Context::extract(conn).await?; + let commitment = request.commitment.unwrap_or_default(); - let value = race_hot_cold(rpc_client, conn, &request.address, None).await?; + let value = race_hot_cold(rpc_client, conn, &request.address, None, commitment).await?; Ok(GetAccountInterfaceResponse { context, value }) } diff --git a/src/api/method/interface/get_multiple_account_interfaces.rs b/src/api/method/interface/get_multiple_account_interfaces.rs index 576b8cf9..2590c977 100644 --- a/src/api/method/interface/get_multiple_account_interfaces.rs +++ b/src/api/method/interface/get_multiple_account_interfaces.rs @@ -37,6 +37,7 @@ pub async fn get_multiple_account_interfaces( } let context = Context::extract(conn).await?; + let commitment = request.commitment.unwrap_or_default(); let distinct_owners = get_distinct_owners_with_addresses(conn) .await @@ -48,7 +49,14 @@ pub async fn get_multiple_account_interfaces( .iter() .map(|address| async { let _permit = semaphore.acquire().await.unwrap(); - race_hot_cold(rpc_client, conn, address, Some(&distinct_owners)).await + race_hot_cold( + rpc_client, + conn, + address, + Some(&distinct_owners), + commitment, + ) + .await }) .collect(); diff --git a/src/api/method/interface/racing.rs b/src/api/method/interface/racing.rs index fa5efeb5..a4e99211 100644 --- a/src/api/method/interface/racing.rs +++ b/src/api/method/interface/racing.rs @@ -16,7 +16,6 @@ use sea_orm::prelude::Decimal; use sea_orm::{ColumnTrait, Condition, DatabaseConnection, EntityTrait, QueryFilter}; use solana_account::Account as SolanaAccount; use solana_client::nonblocking::rpc_client::RpcClient; -use solana_commitment_config::CommitmentConfig; use solana_program_option::COption; use solana_program_pack::Pack; use solana_pubkey::Pubkey; @@ -27,7 +26,9 @@ use tokio::time::timeout; use crate::common::typedefs::token_data::TokenData; use crate::ingester::persist::DECOMPRESSED_ACCOUNT_DISCRIMINATOR; -use super::types::{AccountInterface, SolanaAccountData, DB_TIMEOUT_MS, RPC_TIMEOUT_MS}; +use super::types::{ + AccountInterface, RpcCommitment, SolanaAccountData, DB_TIMEOUT_MS, RPC_TIMEOUT_MS, +}; /// Result from a hot (on-chain RPC) lookup. #[derive(Debug)] @@ -48,10 +49,11 @@ pub struct ColdLookupResult { pub async fn hot_lookup( rpc_client: &RpcClient, address: &Pubkey, + commitment: RpcCommitment, ) -> Result { let result = timeout( Duration::from_millis(RPC_TIMEOUT_MS), - rpc_client.get_account_with_commitment(address, CommitmentConfig::confirmed()), + rpc_client.get_account_with_commitment(address, commitment.to_commitment_config()), ) .await; @@ -334,6 +336,66 @@ fn hot_to_solana_account_data(account: &SolanaAccount) -> SolanaAccountData { } } +const COMPRESSED_ONLY_DISCRIMINATOR: u8 = 31; + +fn extension_data_size(discriminator: u8) -> Option { + match discriminator { + 0..=18 => Some(0), + 19 => None, // TokenMetadata (variable) + 20..=28 => Some(0), + 29 => Some(8), // TransferFeeAccountExtension (u64) + 30 => Some(1), // TransferHookAccountExtension (u8) + 31 => Some(17), // CompressedOnlyExtension (u64 + u64 + u8) + 32 => None, // CompressibleExtension (variable) + _ => None, + } +} + +fn extract_delegated_amount_from_tlv(tlv: Option<&Base64String>) -> Option { + let bytes = tlv?.0.as_slice(); + if bytes.len() < 4 { + return None; + } + + let mut offset = 0usize; + let vec_len = u32::from_le_bytes(bytes[offset..offset + 4].try_into().ok()?) as usize; + offset += 4; + + for _ in 0..vec_len { + if offset >= bytes.len() { + return None; + } + let discriminator = bytes[offset]; + offset += 1; + + if discriminator == COMPRESSED_ONLY_DISCRIMINATOR { + if offset + 8 > bytes.len() { + return None; + } + let amount = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?); + return Some(amount); + } + + let size = extension_data_size(discriminator)?; + if offset + size > bytes.len() { + return None; + } + offset += size; + } + + None +} + +fn delegated_contribution(token_data: &TokenData) -> u64 { + if token_data.delegate.is_none() { + return 0; + } + + let delegated = + extract_delegated_amount_from_tlv(token_data.tlv.as_ref()).unwrap_or(token_data.amount.0); + delegated.min(token_data.amount.0) +} + /// Build the 165-byte SPL Token Account layout from compressed TokenData + /// corrected wallet owner. fn build_spl_token_account_bytes(token_data: &TokenData, wallet_owner: &[u8; 32]) -> Vec { @@ -352,7 +414,7 @@ fn build_spl_token_account_bytes(token_data: &TokenData, wallet_owner: &[u8; 32] }, state: spl_state, is_native: COption::None, - delegated_amount: 0, + delegated_amount: delegated_contribution(token_data), close_authority: COption::None, }; @@ -451,11 +513,12 @@ pub async fn race_hot_cold( conn: &DatabaseConnection, address: &SerializablePubkey, distinct_owners: Option<&[Vec]>, + commitment: RpcCommitment, ) -> Result, PhotonApiError> { let pubkey = Pubkey::from(address.0.to_bytes()); let (hot_result, cold_result) = tokio::join!( - hot_lookup(rpc_client, &pubkey), + hot_lookup(rpc_client, &pubkey, commitment), cold_lookup(conn, address, distinct_owners) ); @@ -556,11 +619,71 @@ fn cold_accounts_to_synthetic( let hot_amount = hot_contribution.as_ref().map_or(0, |spl| spl.amount); let total_amount = cold_total + hot_amount; + let has_frozen_cold = parsed + .iter() + .any(|(_, td)| td.state == AccountState::frozen); + let has_frozen_hot = hot_contribution + .as_ref() + .map(|spl| spl.state == SplAccountState::Frozen) + .unwrap_or(false); + let any_frozen = has_frozen_hot || has_frozen_cold; + + let newest_delegated_cold = parsed + .iter() + .filter(|(_, td)| td.delegate.is_some()) + .max_by_key(|(acc, _)| acc.slot_created.0) + .and_then(|(_, td)| td.delegate.as_ref()) + .map(|d| Pubkey::from(d.0.to_bytes())); + let canonical_delegate = hot_contribution + .as_ref() + .and_then(|spl| match spl.delegate { + COption::Some(d) => Some(d), + COption::None => None, + }) + .or(newest_delegated_cold); + + let cold_delegated_total: u64 = if let Some(delegate) = canonical_delegate.as_ref() + { + parsed + .iter() + .filter(|(_, td)| { + td.delegate + .as_ref() + .map(|d| Pubkey::from(d.0.to_bytes()) == *delegate) + .unwrap_or(false) + }) + .map(|(_, td)| delegated_contribution(td)) + .sum() + } else { + 0 + }; + let hot_delegated_contribution = if let (Some(delegate), Some(spl)) = + (canonical_delegate.as_ref(), hot_contribution.as_ref()) + { + match spl.delegate { + COption::Some(d) if d == *delegate => spl.delegated_amount.min(spl.amount), + _ => 0, + } + } else { + 0 + }; + let canonical_delegated = cold_delegated_total + hot_delegated_contribution; + // When a hot account matches, use it as the base for the // synthetic view — it already has the correct wallet owner, // delegate, state, etc. Unpack, set aggregated amount, repack. if let (Some(hot), Some(mut spl)) = (hot_account, hot_contribution) { spl.amount = total_amount; + spl.delegate = match canonical_delegate { + Some(delegate) => COption::Some(delegate), + None => COption::None, + }; + spl.delegated_amount = canonical_delegated.min(spl.amount); + spl.state = if any_frozen { + SplAccountState::Frozen + } else { + SplAccountState::Initialized + }; let mut spl_bytes = vec![0u8; SplTokenAccount::LEN]; SplTokenAccount::pack(spl, &mut spl_bytes) .expect("buffer is exactly LEN bytes"); @@ -593,8 +716,12 @@ fn cold_accounts_to_synthetic( mint: newest_td.mint, owner: newest_td.owner, amount: UnsignedInteger(total_amount), - delegate: newest_td.delegate, - state: newest_td.state, + delegate: canonical_delegate.map(|d| SerializablePubkey::from(d.to_bytes())), + state: if any_frozen { + AccountState::frozen + } else { + AccountState::initialized + }, tlv: newest_td.tlv.clone(), }; diff --git a/src/api/method/interface/types.rs b/src/api/method/interface/types.rs index d120bab8..1cbd7c20 100644 --- a/src/api/method/interface/types.rs +++ b/src/api/method/interface/types.rs @@ -1,4 +1,5 @@ use serde::{Deserialize, Serialize}; +use solana_commitment_config::CommitmentConfig; use utoipa::ToSchema; use crate::common::typedefs::account::AccountV2; @@ -39,6 +40,8 @@ pub struct AccountInterface { pub struct GetAccountInterfaceRequest { /// The account address to look up pub address: SerializablePubkey, + /// Optional RPC commitment for the hot (on-chain) lookup + pub commitment: Option, } /// Request for getMultipleAccountInterfaces @@ -47,6 +50,27 @@ pub struct GetAccountInterfaceRequest { pub struct GetMultipleAccountInterfacesRequest { /// List of account addresses to look up (max 100) pub addresses: Vec, + /// Optional RPC commitment for hot (on-chain) lookups + pub commitment: Option, +} + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] +#[serde(rename_all = "camelCase")] +pub enum RpcCommitment { + Processed, + #[default] + Confirmed, + Finalized, +} + +impl RpcCommitment { + pub fn to_commitment_config(self) -> CommitmentConfig { + match self { + RpcCommitment::Processed => CommitmentConfig::processed(), + RpcCommitment::Confirmed => CommitmentConfig::confirmed(), + RpcCommitment::Finalized => CommitmentConfig::finalized(), + } + } } // ============ Response Types ============ diff --git a/tests/integration_tests/interface_tests.rs b/tests/integration_tests/interface_tests.rs index f93f1736..9883b23c 100644 --- a/tests/integration_tests/interface_tests.rs +++ b/tests/integration_tests/interface_tests.rs @@ -87,6 +87,7 @@ async fn test_get_account_interface_token_owner( .api .get_account_interface(GetAccountInterfaceRequest { address: bob_pubkey, + commitment: None, }) .await .unwrap(); @@ -145,6 +146,7 @@ async fn test_get_multiple_account_interfaces( .api .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { addresses: vec![bob_pubkey, charlie_pubkey, nonexistent_address], + commitment: None, }) .await .unwrap(); @@ -184,7 +186,10 @@ async fn test_get_multiple_account_interfaces_validation( // Test empty request - should fail let empty_result = setup .api - .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { addresses: vec![] }) + .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { + addresses: vec![], + commitment: None, + }) .await; assert!(empty_result.is_err()); @@ -197,6 +202,7 @@ async fn test_get_multiple_account_interfaces_validation( .api .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { addresses: over_limit, + commitment: None, }) .await; From eadaf11293d8460e833d496fc52ab2ffbbbc6e4e Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Tue, 10 Mar 2026 12:38:45 +0000 Subject: [PATCH 13/16] add tests --- src/api/method/interface/racing.rs | 446 +++++++++++++++++++++++++++++ 1 file changed, 446 insertions(+) diff --git a/src/api/method/interface/racing.rs b/src/api/method/interface/racing.rs index a4e99211..a2509c4a 100644 --- a/src/api/method/interface/racing.rs +++ b/src/api/method/interface/racing.rs @@ -793,6 +793,46 @@ mod tests { use solana_program_pack::Pack; use spl_token_interface::state::Account as SplTokenAccount; + // Test matrix for race + synthetic account logic: + // + // resolve_single_race dispatch: + // - (hot, cold) => test_resolve_single_race_prefers_hot_when_newer_or_equal + // - (hot, colder/newer) => test_resolve_single_race_prefers_newer_cold_by_slot + // - (hot deleted lamports=0, cold) => test_resolve_single_race_falls_back_to_cold_when_hot_deleted + // - (hot only) => test_resolve_single_race_only_hot + // - (cold only) => test_resolve_single_race_only_cold + // - (none) => test_resolve_single_race_neither + // + // cold_accounts_to_synthetic token aggregation path: + // - cold-only same mint aggregation => test_resolve_aggregates_fungible_token_amounts + // - hot+cold same mint aggregation => test_resolve_aggregates_hot_and_cold_token_amounts + // - same-mint aggregation even when hot slot older => test_resolve_same_mint_aggregates_even_when_hot_slot_is_older + // - mixed mints fallback to newest cold => test_resolve_mixed_mints_uses_newest + // - hot token mint mismatch fallback (hot newer) => test_resolve_hot_token_different_mint_from_cold_uses_hot + // - hot token mint mismatch fallback (cold newer) => test_resolve_hot_token_different_mint_from_cold_uses_cold_when_newer + // - hot non-token fallback (hot newer) => test_resolve_hot_non_token_with_cold_tokens_uses_hot + // - hot non-token fallback (cold newer) => test_resolve_hot_non_token_with_cold_tokens_uses_cold_when_newer + // + // delegate + delegated_amount + frozen semantics: + // - TLV delegated amount extraction => test_build_spl_token_account_bytes_uses_tlv_delegated_amount + // - delegated amount capping => test_build_spl_token_account_bytes_caps_tlv_delegated_amount_to_amount + // - hot delegate canonical + matching-cold contribution => test_resolve_hot_delegate_is_canonical_and_only_matching_cold_contributes + // - cold-only canonical delegate = newest delegated cold => test_resolve_cold_only_uses_newest_delegated_delegate + // - any frozen source marks synthetic frozen (cold frozen) => test_resolve_same_mint_any_frozen_marks_synthetic_frozen + // - any frozen source marks synthetic frozen (hot frozen) => test_resolve_same_mint_hot_frozen_marks_synthetic_frozen + // - hot delegated contribution capped by hot amount => test_resolve_hot_delegated_amount_is_capped_by_hot_amount + // + // cold synthetic reconstruction + decompressed filtering: + // - token reconstruction with wallet owner => test_cold_to_synthetic_token_with_wallet_owner + // - token reconstruction without wallet owner => test_cold_to_synthetic_token_without_wallet_owner + // - token reconstruction with invalid wallet owner => test_cold_to_synthetic_token_invalid_wallet_owner_uses_compressed_owner + // - non-token cold reconstruction => test_cold_to_synthetic_non_token + // - decompressed placeholder filtering variants: + // test_find_cold_models_filters_decompressed_placeholders + // test_find_cold_models_filters_sqlite_rounded_decompressed_placeholder + // test_find_cold_models_filters_legacy_sqlite_rounded_placeholder_without_disc_bytes + // test_find_cold_models_keeps_non_placeholder_with_onchain_pubkey + fn sample_cold(slot_created: u64, lamports: u64) -> AccountV2 { AccountV2 { hash: Hash::default(), @@ -1427,6 +1467,59 @@ mod tests { } } + fn sample_hot_token_account_with_delegate( + mint: &Pubkey, + owner: &Pubkey, + amount: u64, + delegate: Option<&Pubkey>, + delegated_amount: u64, + frozen: bool, + ) -> SolanaAccount { + use solana_program_option::COption; + use spl_token_interface::state::AccountState as SplAccountState; + + let spl_account = SplTokenAccount { + mint: *mint, + owner: *owner, + amount, + delegate: match delegate { + Some(d) => COption::Some(*d), + None => COption::None, + }, + state: if frozen { + SplAccountState::Frozen + } else { + SplAccountState::Initialized + }, + is_native: COption::None, + delegated_amount, + close_authority: COption::None, + }; + + let mut data = vec![0u8; SplTokenAccount::LEN]; + SplTokenAccount::pack(spl_account, &mut data).unwrap(); + + let spl_token_program = Pubkey::try_from(spl_token_interface::ID.as_ref()).unwrap(); + + SolanaAccount { + lamports: 2_039_280, + data, + owner: spl_token_program, + executable: false, + rent_epoch: 0, + } + } + + fn compressed_only_tlv(delegated_amount: u64) -> Base64String { + let mut bytes = Vec::new(); + bytes.extend_from_slice(&1u32.to_le_bytes()); // vec len = 1 extension + bytes.push(COMPRESSED_ONLY_DISCRIMINATOR); + bytes.extend_from_slice(&delegated_amount.to_le_bytes()); + bytes.extend_from_slice(&0u64.to_le_bytes()); // withheld_transfer_fee + bytes.push(1u8); // is_ata + Base64String(bytes) + } + #[test] fn test_resolve_aggregates_hot_and_cold_token_amounts() { let mint = Pubkey::new_unique(); @@ -1549,4 +1642,357 @@ mod tests { assert_eq!(result.account.lamports.0, 1000); assert_eq!(result.account.data.0, vec![1, 2, 3]); } + + #[test] + fn test_resolve_same_mint_aggregates_even_when_hot_slot_is_older() { + let mint = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + // Hot token account is older than cold by slot, but still contributes + // when mint matches. + let hot = sample_hot_token_account(&mint, &wallet_owner, 500); + let td = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(300), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let cold = sample_token_cold_with_hash(300, 0, &td, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 100, // older than cold slot + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.mint, mint); + assert_eq!(parsed.owner, wallet_owner); + assert_eq!(parsed.amount, 800); // 500 hot + 300 cold + } + + #[test] + fn test_resolve_hot_token_different_mint_from_cold_uses_cold_when_newer() { + let mint_hot = Pubkey::new_unique(); + let mint_cold = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + let hot = sample_hot_token_account(&mint_hot, &wallet_owner, 500); + let td = TokenData { + mint: SerializablePubkey::from(mint_cold), + owner: SerializablePubkey::from([88u8; 32]), + amount: UnsignedInteger(300), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let cold = sample_token_cold_with_hash(300, 0, &td, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 100, // older than cold slot, so fallback should choose cold + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.mint, mint_cold); + assert_eq!(parsed.amount, 300); + } + + #[test] + fn test_resolve_hot_non_token_with_cold_tokens_uses_cold_when_newer() { + let mint = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + let hot = SolanaAccount { + lamports: 1000, + data: vec![1, 2, 3], // non-token + owner: Pubkey::new_unique(), + executable: false, + rent_epoch: 0, + }; + + let td = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([77u8; 32]), + amount: UnsignedInteger(300), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let cold = sample_token_cold_with_hash(300, 0, &td, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 100, // older than cold slot, so fallback should choose cold + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.mint, mint); + assert_eq!(parsed.amount, 300); + } + + #[test] + fn test_build_spl_token_account_bytes_uses_tlv_delegated_amount() { + let mint = Pubkey::new_unique(); + let wallet_owner = [22u8; 32]; + let delegate = Pubkey::new_unique(); + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(500), + delegate: Some(SerializablePubkey::from(delegate)), + state: AccountState::initialized, + tlv: Some(compressed_only_tlv(123)), + }; + + let bytes = build_spl_token_account_bytes(&token_data, &wallet_owner); + let parsed = SplTokenAccount::unpack(&bytes).expect("valid SPL layout"); + assert_eq!(parsed.amount, 500); + assert_eq!(parsed.delegated_amount, 123); + } + + #[test] + fn test_build_spl_token_account_bytes_caps_tlv_delegated_amount_to_amount() { + let mint = Pubkey::new_unique(); + let wallet_owner = [33u8; 32]; + let delegate = Pubkey::new_unique(); + let token_data = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(200), + delegate: Some(SerializablePubkey::from(delegate)), + state: AccountState::initialized, + tlv: Some(compressed_only_tlv(500)), + }; + + let bytes = build_spl_token_account_bytes(&token_data, &wallet_owner); + let parsed = SplTokenAccount::unpack(&bytes).expect("valid SPL layout"); + assert_eq!(parsed.amount, 200); + assert_eq!(parsed.delegated_amount, 200); + } + + #[test] + fn test_resolve_hot_delegate_is_canonical_and_only_matching_cold_contributes() { + let mint = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let hot_delegate = Pubkey::new_unique(); + let other_delegate = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + let hash2 = Hash::try_from(vec![2u8; 32]).unwrap(); + + let hot = sample_hot_token_account_with_delegate( + &mint, + &wallet_owner, + 400, + Some(&hot_delegate), + 50, + false, + ); + + let td_matching_delegate = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(120), + delegate: Some(SerializablePubkey::from(hot_delegate)), + state: AccountState::initialized, + tlv: Some(compressed_only_tlv(60)), + }; + let td_other_delegate = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(80), + delegate: Some(SerializablePubkey::from(other_delegate)), + state: AccountState::initialized, + tlv: Some(compressed_only_tlv(70)), + }; + + let cold1 = sample_token_cold_with_hash(100, 0, &td_matching_delegate, hash1); + let cold2 = sample_token_cold_with_hash(200, 0, &td_other_delegate, hash2); + let result = resolve_single_race( + Some(&hot), + &[cold1, cold2], + 300, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 600); // 400 + 120 + 80 + assert_eq!( + parsed.delegate, + solana_program_option::COption::Some(hot_delegate) + ); + // canonical delegate is hot delegate: 50 (hot) + 60 (matching cold) only + assert_eq!(parsed.delegated_amount, 110); + } + + #[test] + fn test_resolve_cold_only_uses_newest_delegated_delegate() { + let mint = Pubkey::new_unique(); + let delegate_old = Pubkey::new_unique(); + let delegate_new = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + let hash2 = Hash::try_from(vec![2u8; 32]).unwrap(); + + let td_old = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(100), + delegate: Some(SerializablePubkey::from(delegate_old)), + state: AccountState::initialized, + tlv: Some(compressed_only_tlv(40)), + }; + let td_new = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(200), + delegate: Some(SerializablePubkey::from(delegate_new)), + state: AccountState::initialized, + tlv: Some(compressed_only_tlv(90)), + }; + + let cold_old = sample_token_cold_with_hash(100, 0, &td_old, hash1); + let cold_new = sample_token_cold_with_hash(300, 0, &td_new, hash2); + let result = resolve_single_race( + None, + &[cold_old, cold_new], + 0, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 300); + assert_eq!( + parsed.delegate, + solana_program_option::COption::Some(delegate_new) + ); + assert_eq!(parsed.delegated_amount, 90); + } + + #[test] + fn test_resolve_same_mint_any_frozen_marks_synthetic_frozen() { + let mint = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + let hot = sample_hot_token_account_with_delegate(&mint, &wallet_owner, 500, None, 0, false); + let td_frozen_cold = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(100), + delegate: None, + state: AccountState::frozen, + tlv: None, + }; + let cold = sample_token_cold_with_hash(100, 0, &td_frozen_cold, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 300, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 600); + assert_eq!( + parsed.state, + spl_token_interface::state::AccountState::Frozen + ); + } + + #[test] + fn test_resolve_same_mint_hot_frozen_marks_synthetic_frozen() { + let mint = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + let hot = sample_hot_token_account_with_delegate(&mint, &wallet_owner, 500, None, 0, true); + let td_cold = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(100), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let cold = sample_token_cold_with_hash(100, 0, &td_cold, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 300, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + assert_eq!(parsed.amount, 600); + assert_eq!( + parsed.state, + spl_token_interface::state::AccountState::Frozen + ); + } + + #[test] + fn test_resolve_hot_delegated_amount_is_capped_by_hot_amount() { + let mint = Pubkey::new_unique(); + let wallet_owner = Pubkey::new_unique(); + let delegate = Pubkey::new_unique(); + let hash1 = Hash::try_from(vec![1u8; 32]).unwrap(); + + let hot = sample_hot_token_account_with_delegate( + &mint, + &wallet_owner, + 100, + Some(&delegate), + 500, // intentionally above hot amount + false, + ); + let td_matching_delegate = TokenData { + mint: SerializablePubkey::from(mint), + owner: SerializablePubkey::from([99u8; 32]), + amount: UnsignedInteger(80), + delegate: Some(SerializablePubkey::from(delegate)), + state: AccountState::initialized, + tlv: Some(compressed_only_tlv(60)), + }; + let cold = sample_token_cold_with_hash(100, 0, &td_matching_delegate, hash1); + + let result = resolve_single_race( + Some(&hot), + std::slice::from_ref(&cold), + 300, + SerializablePubkey::default(), + &HashMap::new(), + ) + .expect("expected Some interface"); + + let parsed = SplTokenAccount::unpack(&result.account.data.0).expect("valid SPL layout"); + // amount = 100 hot + 80 cold + assert_eq!(parsed.amount, 180); + // delegated = min(hot_delegated, hot_amount)=100 + cold 60 + assert_eq!(parsed.delegated_amount, 160); + } } From 3a43b9182ad194ab8d21efea40b76857f17bf4e1 Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Thu, 19 Mar 2026 15:42:16 +0000 Subject: [PATCH 14/16] tests, fix interfaces --- src/api/method/interface/racing.rs | 16 +-- src/openapi/mod.rs | 11 +- src/openapi/specs/api.yaml | 18 ++- tests/integration_tests/interface_tests.rs | 146 ++++++++++++++++++--- 4 files changed, 164 insertions(+), 27 deletions(-) diff --git a/src/api/method/interface/racing.rs b/src/api/method/interface/racing.rs index a2509c4a..a0322eaa 100644 --- a/src/api/method/interface/racing.rs +++ b/src/api/method/interface/racing.rs @@ -72,7 +72,8 @@ pub async fn hot_lookup( /// The lookup aggregates all compressed accounts associated with the queried pubkey: /// 1) direct onchain pubkey matches (decompressed account linkage), /// 2) derived compressed address matches (V2 address tree only), -/// 3) token account owner / ata_owner matches (can return multiple accounts). +/// 3) token account owner matches (can return multiple accounts). +/// ata_owner is only used for synthetic SPL wallet-owner reconstruction. pub async fn cold_lookup( conn: &DatabaseConnection, address: &SerializablePubkey, @@ -240,16 +241,13 @@ async fn find_cold_models( } } - // 3) Token account linkage by token owner / ata_owner. + // 3) Token account linkage by token owner. + // ata_owner is only used later for synthetic SPL wallet-owner reconstruction. let token_result = timeout( Duration::from_millis(DB_TIMEOUT_MS), token_accounts::Entity::find() .filter(token_accounts::Column::Spent.eq(false)) - .filter( - Condition::any() - .add(token_accounts::Column::AtaOwner.eq(address_bytes.clone())) - .add(token_accounts::Column::Owner.eq(address_bytes)), - ) + .filter(token_accounts::Column::Owner.eq(address_bytes)) .find_also_related(accounts::Entity) .all(conn), ) @@ -692,8 +690,8 @@ fn cold_accounts_to_synthetic( lamports: UnsignedInteger(hot.lamports), data: Base64String(spl_bytes), owner: SerializablePubkey::from(hot.owner.to_bytes()), - executable: false, - rent_epoch: UnsignedInteger(0), + executable: hot.executable, + rent_epoch: UnsignedInteger(hot.rent_epoch), space: UnsignedInteger(space), }; } diff --git a/src/openapi/mod.rs b/src/openapi/mod.rs index 214d133e..d56bec57 100644 --- a/src/openapi/mod.rs +++ b/src/openapi/mod.rs @@ -33,7 +33,11 @@ use crate::api::method::get_validity_proof::{ AccountProofInputs, AddressProofInputs, CompressedProof, CompressedProofWithContext, CompressedProofWithContextV2, MerkleContextV2, RootIndex, TreeContextInfo, }; -use crate::api::method::interface::types::{AccountInterface, SolanaAccountData}; +use crate::api::method::interface::types::{ + AccountInterface, GetAccountInterfaceRequest, GetAccountInterfaceResponse, + GetMultipleAccountInterfacesRequest, GetMultipleAccountInterfacesResponse, RpcCommitment, + SolanaAccountData, +}; use crate::api::method::utils::PaginatedSignatureInfoList; use crate::api::method::utils::SignatureInfo; use crate::api::method::utils::SignatureInfoList; @@ -152,6 +156,11 @@ const JSON_CONTENT_TYPE: &str = "application/json"; // Interface types AccountInterface, SolanaAccountData, + RpcCommitment, + GetAccountInterfaceRequest, + GetAccountInterfaceResponse, + GetMultipleAccountInterfacesRequest, + GetMultipleAccountInterfacesResponse, )))] struct ApiDoc; diff --git a/src/openapi/specs/api.yaml b/src/openapi/specs/api.yaml index 57b51647..c57b1b5b 100644 --- a/src/openapi/specs/api.yaml +++ b/src/openapi/specs/api.yaml @@ -45,6 +45,13 @@ paths: properties: address: $ref: '#/components/schemas/SerializablePubkey' + commitment: + type: string + description: Optional RPC commitment for the hot (on-chain) lookup + enum: + - processed + - confirmed + - finalized additionalProperties: false required: true responses: @@ -84,7 +91,9 @@ paths: context: $ref: '#/components/schemas/Context' value: - $ref: '#/components/schemas/AccountInterface' + allOf: + - $ref: '#/components/schemas/AccountInterface' + nullable: true '429': description: Exceeded rate limit. content: @@ -3021,6 +3030,13 @@ paths: items: $ref: '#/components/schemas/SerializablePubkey' description: List of account addresses to look up (max 100) + commitment: + type: string + description: Optional RPC commitment for hot (on-chain) lookups + enum: + - processed + - confirmed + - finalized additionalProperties: false required: true responses: diff --git a/tests/integration_tests/interface_tests.rs b/tests/integration_tests/interface_tests.rs index 9883b23c..4c6fdd53 100644 --- a/tests/integration_tests/interface_tests.rs +++ b/tests/integration_tests/interface_tests.rs @@ -6,11 +6,14 @@ use photon_indexer::api::method::interface::{ GetAccountInterfaceRequest, GetMultipleAccountInterfacesRequest, }; use photon_indexer::common::typedefs::serializable_pubkey::SerializablePubkey; +use photon_indexer::dao::generated::token_accounts; use photon_indexer::ingester::index_block; use photon_indexer::ingester::typedefs::block_info::{BlockInfo, BlockMetadata}; -use sea_orm::DatabaseConnection; +use sea_orm::{ActiveModelTrait, ColumnTrait, DatabaseConnection, EntityTrait, QueryFilter, Set}; use serial_test::serial; use solana_client::nonblocking::rpc_client::RpcClient; +use solana_program_pack::Pack; +use spl_token_interface::state::Account as SplTokenAccount; use crate::utils::*; @@ -18,6 +21,33 @@ use crate::utils::*; /// Generated by forester's test_indexer_interface test. const INTERFACE_TEST_DATA_DIR: &str = "indexer_interface"; +async fn interface_lookup_addresses( + db_conn: &DatabaseConnection, +) -> ( + SerializablePubkey, + SerializablePubkey, +) { + let row = token_accounts::Entity::find() + .filter(token_accounts::Column::Spent.eq(false)) + .one(db_conn) + .await + .expect("token_accounts query should succeed") + .expect("expected at least one unspent token account in test data"); + + let token_owner = SerializablePubkey::try_from(row.owner.clone()) + .expect("token_accounts.owner must be a valid pubkey"); + let ata_owner = SerializablePubkey::new_unique(); + + let mut model: token_accounts::ActiveModel = row.into(); + model.ata_owner = Set(Some(ata_owner.to_bytes_vec())); + model + .update(db_conn) + .await + .expect("updating ata_owner for test fixture should succeed"); + + (ata_owner, token_owner) +} + /// Helper to set up indexing methodologies for interface tests. fn all_indexing_methodologies_for_interface( db_conn: Arc, @@ -71,22 +101,19 @@ async fn test_get_account_interface_token_owner( let mint_tokens_tx = "2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd"; - // Bob's pubkey is the token owner. Interface lookup should return - // synthetic account data plus compressed token accounts in `cold`. - let bob_pubkey = - SerializablePubkey::try_from("DkbH1tracp6nxSQLrHQqJwVE7NaDAAb7eGKzfB9TwBdF").unwrap(); - let txs = [mint_tokens_tx]; let indexing = all_indexing_methodologies_for_interface(setup.db_conn.clone(), setup.client.clone(), &txs); pin_mut!(indexing); while let Some(_) = indexing.next().await { - // getAccountInterface must support token-owner lookups. + let (ata_owner, token_owner) = interface_lookup_addresses(setup.db_conn.as_ref()).await; + + // Token owner lookup should resolve compressed token accounts. let result = setup .api .get_account_interface(GetAccountInterfaceRequest { - address: bob_pubkey, + address: token_owner, commitment: None, }) .await @@ -98,6 +125,90 @@ async fn test_get_account_interface_token_owner( !cold.is_empty(), "expected at least one compressed token account" ); + + // ATA-owner-only lookup must not resolve via cold token linkage. + let ata_owner_result = setup + .api + .get_account_interface(GetAccountInterfaceRequest { + address: ata_owner, + commitment: None, + }) + .await + .unwrap(); + assert!(ata_owner_result.value.is_none()); + } +} + +/// Test ATA-mode compressed lookup: +/// - token_accounts.owner (ATA pubkey) is used for lookup +/// - token_accounts.ata_owner (wallet pubkey) is used as synthetic SPL owner +#[named] +#[rstest] +#[tokio::test] +#[serial] +async fn test_get_account_interface_ata_mode_owner_lookup_and_wallet_owner_synthesis( + #[values(DatabaseBackend::Sqlite, DatabaseBackend::Postgres)] db_backend: DatabaseBackend, +) { + let name = trim_test_name(function_name!()); + let setup = setup_with_options( + name.clone(), + TestSetupOptions { + network: Network::Localnet, + db_backend, + }, + ) + .await; + + let mint_tokens_tx = + "2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd"; + + let txs = [mint_tokens_tx]; + let indexing = + all_indexing_methodologies_for_interface(setup.db_conn.clone(), setup.client.clone(), &txs); + pin_mut!(indexing); + + while let Some(_) = indexing.next().await { + let row = token_accounts::Entity::find() + .filter(token_accounts::Column::Spent.eq(false)) + .one(setup.db_conn.as_ref()) + .await + .expect("token_accounts query should succeed") + .expect("expected at least one unspent token account in test data"); + + let lookup_ata = SerializablePubkey::new_unique(); + let wallet_owner = SerializablePubkey::new_unique(); + + let mut model: token_accounts::ActiveModel = row.into(); + model.owner = Set(lookup_ata.to_bytes_vec()); + model.ata_owner = Set(Some(wallet_owner.to_bytes_vec())); + model + .update(setup.db_conn.as_ref()) + .await + .expect("updating token owner/ata_owner fixture should succeed"); + + let result = setup + .api + .get_account_interface(GetAccountInterfaceRequest { + address: lookup_ata, + commitment: None, + }) + .await + .unwrap(); + + let value = result.value.expect("expected interface value"); + let cold = value.cold.expect("expected compressed token accounts"); + assert!( + !cold.is_empty(), + "expected cold token accounts for ATA-mode owner lookup" + ); + + let parsed = SplTokenAccount::unpack(&value.account.data.0) + .expect("expected synthesized SPL token account bytes"); + assert_eq!( + SerializablePubkey::from(parsed.owner.to_bytes()), + wallet_owner, + "synthetic SPL owner should come from ata_owner wallet mapping" + ); } } @@ -125,11 +236,6 @@ async fn test_get_multiple_account_interfaces( let mint_tokens_tx = "2YTv5hjSmRAgfwoNHdc4DRDFWW7fqQb57f9s8Rxtu9u6jA2hDxNxEWoiybvn4p7ua2nw3scYeNo6htYCSuBYviFd"; - // Token owner pubkeys. - let bob_pubkey = - SerializablePubkey::try_from("DkbH1tracp6nxSQLrHQqJwVE7NaDAAb7eGKzfB9TwBdF").unwrap(); - let charlie_pubkey = - SerializablePubkey::try_from("GDhjk4DmDQ8bFWqrdcLGaJcYBDnq73ExjGyZYrca6nDc").unwrap(); // Use a random address that definitely doesn't exist on-chain or compressed // (default pubkey 11111... is the system program which exists on-chain) let nonexistent_address = @@ -141,18 +247,25 @@ async fn test_get_multiple_account_interfaces( pin_mut!(indexing); while let Some(_) = indexing.next().await { + let (first_ata_owner, token_owner) = interface_lookup_addresses(setup.db_conn.as_ref()).await; + // Test getMultipleAccountInterfaces let result = setup .api .get_multiple_account_interfaces(GetMultipleAccountInterfacesRequest { - addresses: vec![bob_pubkey, charlie_pubkey, nonexistent_address], + addresses: vec![ + token_owner, + token_owner, + first_ata_owner, + nonexistent_address, + ], commitment: None, }) .await .unwrap(); - // Both owner pubkeys should resolve to token-backed interfaces. - assert_eq!(result.value.len(), 3); + // Token owner pubkeys resolve, while ata-owner-only and nonexistent don't. + assert_eq!(result.value.len(), 4); assert!(result.value[0] .as_ref() .and_then(|v| v.cold.as_ref()) @@ -162,6 +275,7 @@ async fn test_get_multiple_account_interfaces( .and_then(|v| v.cold.as_ref()) .is_some_and(|cold| !cold.is_empty())); assert!(result.value[2].is_none()); + assert!(result.value[3].is_none()); } } From 44565ca4b4fb3f7af19073f0d223edb55887c962 Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Thu, 19 Mar 2026 23:25:39 +0000 Subject: [PATCH 15/16] add getAtaInterface endpoint --- src/api/api.rs | 17 +- src/api/method/interface/get_ata_interface.rs | 662 ++++++++++++++++++ src/api/method/interface/mod.rs | 2 + src/api/method/interface/types.rs | 99 +++ src/api/rpc_server.rs | 6 + src/openapi/mod.rs | 12 +- src/openapi/specs/api.yaml | 318 ++++++++- src/openapi/specs/getAtaInterface.spec.yaml | 264 +++++++ 8 files changed, 1362 insertions(+), 18 deletions(-) create mode 100644 src/api/method/interface/get_ata_interface.rs create mode 100644 src/openapi/specs/getAtaInterface.spec.yaml diff --git a/src/api/api.rs b/src/api/api.rs index c382db1a..d6beb6c0 100644 --- a/src/api/api.rs +++ b/src/api/api.rs @@ -86,8 +86,9 @@ use crate::api::method::get_validity_proof::{ GetValidityProofResponseV2, }; use crate::api::method::interface::{ - get_account_interface, get_multiple_account_interfaces, GetAccountInterfaceRequest, - GetAccountInterfaceResponse, GetMultipleAccountInterfacesRequest, + get_account_interface, get_ata_interface, get_multiple_account_interfaces, + GetAccountInterfaceRequest, GetAccountInterfaceResponse, GetAtaInterfaceRequest, + GetAtaInterfaceResponse, GetMultipleAccountInterfacesRequest, GetMultipleAccountInterfacesResponse, }; use crate::api::method::utils::{ @@ -422,6 +423,13 @@ impl PhotonApi { get_multiple_account_interfaces(&self.db_conn, &self.rpc_client, request).await } + pub async fn get_ata_interface( + &self, + request: GetAtaInterfaceRequest, + ) -> Result { + get_ata_interface(&self.db_conn, &self.rpc_client, request).await + } + pub fn method_api_specs() -> Vec { vec![ OpenApiSpec { @@ -622,6 +630,11 @@ impl PhotonApi { request: Some(GetMultipleAccountInterfacesRequest::schema().1), response: GetMultipleAccountInterfacesResponse::schema().1, }, + OpenApiSpec { + name: "getAtaInterface".to_string(), + request: Some(GetAtaInterfaceRequest::schema().1), + response: GetAtaInterfaceResponse::schema().1, + }, ] } } diff --git a/src/api/method/interface/get_ata_interface.rs b/src/api/method/interface/get_ata_interface.rs new file mode 100644 index 00000000..9f440ccd --- /dev/null +++ b/src/api/method/interface/get_ata_interface.rs @@ -0,0 +1,662 @@ +use sea_orm::DatabaseConnection; +use solana_account::Account as SolanaAccount; +use solana_client::nonblocking::rpc_client::RpcClient; +use solana_program_option::COption; +use solana_program_pack::Pack; +use solana_pubkey::{pubkey, Pubkey}; +use spl_token_interface::state::{Account as SplTokenAccount, AccountState as SplAccountState}; + +use crate::api::error::PhotonApiError; +use crate::api::method::get_compressed_token_accounts_by_owner::get_compressed_token_accounts_by_owner_v2; +use crate::api::method::utils::GetCompressedTokenAccountsByOwner; +use crate::common::typedefs::account::AccountV2; +use crate::common::typedefs::bs64_string::Base64String; +use crate::common::typedefs::context::Context; +use crate::common::typedefs::serializable_pubkey::SerializablePubkey; +use crate::common::typedefs::token_data::{AccountState, TokenData}; +use crate::common::typedefs::unsigned_integer::UnsignedInteger; +use crate::ingester::persist::LIGHT_TOKEN_PROGRAM_ID; + +use super::racing::hot_lookup; +use super::types::{ + AtaInterfaceValue, GetAtaDerivedAddresses, GetAtaHotEntry, GetAtaHotSources, + GetAtaInterfaceRequest, GetAtaInterfaceResponse, GetAtaProgramMode, SolanaAccountData, +}; +#[cfg(test)] +use super::types::GetAtaInterfaceConfig; + +const SPL_TOKEN_PROGRAM_ID: Pubkey = pubkey!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); +const TOKEN_2022_PROGRAM_ID: Pubkey = pubkey!("TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"); +const ASSOCIATED_TOKEN_PROGRAM_ID: Pubkey = pubkey!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); +const COMPRESSED_ONLY_DISCRIMINATOR: u8 = 31; + +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +enum SourceKind { + LightHot, + LightCold, + SplHot, + SplCold, + Token2022Hot, + Token2022Cold, +} + +impl SourceKind { + fn rank(self) -> u8 { + match self { + SourceKind::LightHot => 0, + SourceKind::LightCold => 1, + SourceKind::SplHot => 2, + SourceKind::Token2022Hot => 3, + SourceKind::SplCold => 4, + SourceKind::Token2022Cold => 5, + } + } + + fn is_hot(self) -> bool { + matches!( + self, + SourceKind::LightHot | SourceKind::SplHot | SourceKind::Token2022Hot + ) + } +} + +#[derive(Debug, Clone)] +struct Source { + kind: SourceKind, + amount: u64, + delegate: Option, + delegated_amount: u64, + frozen: bool, + slot_created: u64, + lamports: u64, + owner: SerializablePubkey, + executable: bool, + rent_epoch: u64, + spl: SplTokenAccount, +} + +#[derive(Debug, Clone, Copy)] +struct RequestOptions { + commitment: super::types::RpcCommitment, + mode: GetAtaProgramMode, + wrap: bool, + allow_owner_off_curve: bool, + min_context_slot: Option, +} + +fn derive_ata( + owner: &SerializablePubkey, + mint: &SerializablePubkey, + token_program_id: &Pubkey, + associated_program_id: &Pubkey, +) -> SerializablePubkey { + let seeds = &[owner.0.as_ref(), token_program_id.as_ref(), mint.0.as_ref()]; + let (ata, _) = Pubkey::find_program_address(seeds, associated_program_id); + SerializablePubkey::from(ata) +} + +fn extension_data_size(discriminator: u8) -> Option { + match discriminator { + 0..=18 => Some(0), + 19 => None, + 20..=28 => Some(0), + 29 => Some(8), + 30 => Some(1), + 31 => Some(17), + 32 => None, + _ => None, + } +} + +fn extract_delegated_amount_from_tlv(tlv: Option<&Base64String>) -> Option { + let bytes = tlv?.0.as_slice(); + if bytes.len() < 4 { + return None; + } + + let mut offset = 0usize; + let vec_len = u32::from_le_bytes(bytes[offset..offset + 4].try_into().ok()?) as usize; + offset += 4; + + for _ in 0..vec_len { + if offset >= bytes.len() { + return None; + } + + let discriminator = bytes[offset]; + offset += 1; + + if discriminator == COMPRESSED_ONLY_DISCRIMINATOR { + if offset + 8 > bytes.len() { + return None; + } + let amount = u64::from_le_bytes(bytes[offset..offset + 8].try_into().ok()?); + return Some(amount); + } + + let size = extension_data_size(discriminator)?; + if offset + size > bytes.len() { + return None; + } + offset += size; + } + + None +} + +fn delegated_contribution(source: &Source) -> u64 { + if source.delegate.is_none() { + return 0; + } + source.delegated_amount.min(source.amount) +} + +fn token_data_to_spl_account(token_data: &TokenData) -> SplTokenAccount { + let delegated_amount = if token_data.delegate.is_some() { + extract_delegated_amount_from_tlv(token_data.tlv.as_ref()) + .unwrap_or(token_data.amount.0) + .min(token_data.amount.0) + } else { + 0 + }; + + SplTokenAccount { + mint: Pubkey::from(token_data.mint.0.to_bytes()), + owner: Pubkey::from(token_data.owner.0.to_bytes()), + amount: token_data.amount.0, + delegate: match token_data.delegate { + Some(d) => COption::Some(Pubkey::from(d.0.to_bytes())), + None => COption::None, + }, + state: match token_data.state { + AccountState::initialized => SplAccountState::Initialized, + AccountState::frozen => SplAccountState::Frozen, + }, + is_native: COption::None, + delegated_amount, + close_authority: COption::None, + } +} + +fn source_kind_for_mode(mode: GetAtaProgramMode) -> SourceKind { + match mode { + GetAtaProgramMode::Auto | GetAtaProgramMode::Light => SourceKind::LightCold, + GetAtaProgramMode::Spl => SourceKind::SplCold, + GetAtaProgramMode::Token2022 => SourceKind::Token2022Cold, + } +} + +fn build_synthetic_account_from_sources(sources: &mut [Source]) -> Option { + if sources.is_empty() { + return None; + } + + sources.sort_by(|a, b| { + a.kind + .rank() + .cmp(&b.kind.rank()) + .then_with(|| b.slot_created.cmp(&a.slot_created)) + }); + + let total_amount_u128: u128 = sources.iter().map(|s| s.amount as u128).sum(); + let total_amount = u64::try_from(total_amount_u128) + .map_err(|_| ()) + .ok() + .unwrap_or(u64::MAX); + + let canonical_delegate = sources + .iter() + .find(|s| s.kind.is_hot() && s.delegate.is_some()) + .and_then(|s| s.delegate) + .or_else(|| { + sources + .iter() + .find(|s| !s.kind.is_hot() && s.delegate.is_some()) + .and_then(|s| s.delegate) + }); + + let canonical_delegated_u128: u128 = canonical_delegate + .map(|delegate| { + sources + .iter() + .filter(|s| s.delegate == Some(delegate)) + .map(delegated_contribution) + .map(u128::from) + .sum() + }) + .unwrap_or(0); + + let canonical_delegated = u64::try_from(canonical_delegated_u128) + .map_err(|_| ()) + .ok() + .unwrap_or(u64::MAX) + .min(total_amount); + + let any_frozen = sources.iter().any(|s| s.frozen); + + let primary = &sources[0]; + let mut spl = primary.spl; + spl.amount = total_amount; + spl.delegate = canonical_delegate + .map(COption::Some) + .unwrap_or(COption::None); + spl.delegated_amount = canonical_delegated; + spl.state = if any_frozen { + SplAccountState::Frozen + } else { + SplAccountState::Initialized + }; + + let mut spl_bytes = vec![0u8; SplTokenAccount::LEN]; + SplTokenAccount::pack(spl, &mut spl_bytes).expect("buffer is exactly LEN bytes"); + + Some(SolanaAccountData { + lamports: UnsignedInteger(primary.lamports), + data: Base64String(spl_bytes), + owner: primary.owner, + executable: primary.executable, + rent_epoch: UnsignedInteger(primary.rent_epoch), + space: UnsignedInteger(SplTokenAccount::LEN as u64), + }) +} + +fn hot_entry_from_account( + address: SerializablePubkey, + account: &SolanaAccount, + expected_program: Pubkey, + mint: SerializablePubkey, + kind: SourceKind, +) -> Option<(GetAtaHotEntry, Source)> { + if account.owner != expected_program { + return None; + } + + let spl = SplTokenAccount::unpack(&account.data).ok()?; + if spl.mint.to_bytes() != mint.0.to_bytes() { + return None; + } + + let delegate = match spl.delegate { + COption::Some(d) => Some(d), + COption::None => None, + }; + let entry = GetAtaHotEntry { + address, + amount: UnsignedInteger(spl.amount), + }; + let source = Source { + kind, + amount: spl.amount, + delegate, + delegated_amount: spl.delegated_amount, + frozen: spl.state == SplAccountState::Frozen, + slot_created: u64::MAX, + lamports: account.lamports, + owner: SerializablePubkey::from(account.owner.to_bytes()), + executable: account.executable, + rent_epoch: account.rent_epoch, + spl, + }; + Some((entry, source)) +} + +fn canonical_key_for_mode( + mode: GetAtaProgramMode, + light_ata: SerializablePubkey, + spl_ata: SerializablePubkey, + token2022_ata: SerializablePubkey, +) -> SerializablePubkey { + match mode { + GetAtaProgramMode::Auto | GetAtaProgramMode::Light => light_ata, + GetAtaProgramMode::Spl => spl_ata, + GetAtaProgramMode::Token2022 => token2022_ata, + } +} + +fn mode_from_program_id(program_id: Option) -> Result, PhotonApiError> { + let Some(program_id) = program_id else { + return Ok(None); + }; + let key = Pubkey::from(program_id.0.to_bytes()); + if key == LIGHT_TOKEN_PROGRAM_ID { + Ok(Some(GetAtaProgramMode::Light)) + } else if key == SPL_TOKEN_PROGRAM_ID { + Ok(Some(GetAtaProgramMode::Spl)) + } else if key == TOKEN_2022_PROGRAM_ID { + Ok(Some(GetAtaProgramMode::Token2022)) + } else { + Err(PhotonApiError::ValidationError(format!( + "Unsupported programId {}. Expected light token, SPL token, or Token-2022 program id", + key + ))) + } +} + +fn resolve_request_options(request: &GetAtaInterfaceRequest) -> Result { + let cfg = request.config.as_ref(); + let commitment = cfg + .and_then(|c| c.commitment) + .unwrap_or_default(); + let mode = mode_from_program_id(cfg.and_then(|c| c.program_id))? + .unwrap_or_default(); + let wrap = cfg.and_then(|c| c.wrap).unwrap_or(false); + let allow_owner_off_curve = cfg + .and_then(|c| c.allow_owner_off_curve) + .unwrap_or(false); + let min_context_slot = cfg.and_then(|c| c.min_context_slot).map(|v| v.0); + + if wrap && mode != GetAtaProgramMode::Auto { + return Err(PhotonApiError::ValidationError( + "wrap=true is only valid when config.programId is not set (auto mode)".to_string(), + )); + } + + Ok(RequestOptions { + commitment, + mode, + wrap, + allow_owner_off_curve, + min_context_slot, + }) +} + +/// Return canonical ATA interface for (owner, mint) with hot/cold aggregation. +pub async fn get_ata_interface( + conn: &DatabaseConnection, + rpc_client: &RpcClient, + request: GetAtaInterfaceRequest, +) -> Result { + let context = Context::extract(conn).await?; + let options = resolve_request_options(&request)?; + + if let Some(min_context_slot) = options.min_context_slot { + if context.slot < min_context_slot { + return Err(PhotonApiError::StaleSlot(min_context_slot - context.slot)); + } + } + + if !options.allow_owner_off_curve && !request.owner.0.is_on_curve() { + return Err(PhotonApiError::ValidationError( + "Owner is off-curve; set allowOwnerOffCurve=true to allow PDA owners".to_string(), + )); + } + + let light_ata = derive_ata( + &request.owner, + &request.mint, + &LIGHT_TOKEN_PROGRAM_ID, + &LIGHT_TOKEN_PROGRAM_ID, + ); + let spl_ata = derive_ata( + &request.owner, + &request.mint, + &SPL_TOKEN_PROGRAM_ID, + &ASSOCIATED_TOKEN_PROGRAM_ID, + ); + let token2022_ata = derive_ata( + &request.owner, + &request.mint, + &TOKEN_2022_PROGRAM_ID, + &ASSOCIATED_TOKEN_PROGRAM_ID, + ); + let key = canonical_key_for_mode(options.mode, light_ata, spl_ata, token2022_ata); + + let fetch_light_hot = matches!(options.mode, GetAtaProgramMode::Auto | GetAtaProgramMode::Light); + let fetch_spl_hot = matches!(options.mode, GetAtaProgramMode::Spl) + || (options.mode == GetAtaProgramMode::Auto && options.wrap); + let fetch_t22_hot = matches!(options.mode, GetAtaProgramMode::Token2022) + || (options.mode == GetAtaProgramMode::Auto && options.wrap); + + let mut hot_sources = GetAtaHotSources { + light: None, + spl: None, + token2022: None, + }; + let mut sources: Vec = Vec::new(); + + if fetch_light_hot { + if let Ok(hot) = hot_lookup( + rpc_client, + &Pubkey::from(light_ata.0.to_bytes()), + options.commitment, + ) + .await + { + if let Some(account) = hot.account.as_ref() { + if let Some((entry, src)) = hot_entry_from_account( + light_ata, + account, + LIGHT_TOKEN_PROGRAM_ID, + request.mint, + SourceKind::LightHot, + ) { + hot_sources.light = Some(entry); + sources.push(src); + } + } + } + } + + if fetch_spl_hot { + if let Ok(hot) = hot_lookup( + rpc_client, + &Pubkey::from(spl_ata.0.to_bytes()), + options.commitment, + ) + .await + { + if let Some(account) = hot.account.as_ref() { + if let Some((entry, src)) = hot_entry_from_account( + spl_ata, + account, + SPL_TOKEN_PROGRAM_ID, + request.mint, + SourceKind::SplHot, + ) { + hot_sources.spl = Some(entry); + sources.push(src); + } + } + } + } + + if fetch_t22_hot { + if let Ok(hot) = hot_lookup( + rpc_client, + &Pubkey::from(token2022_ata.0.to_bytes()), + options.commitment, + ) + .await + { + if let Some(account) = hot.account.as_ref() { + if let Some((entry, src)) = hot_entry_from_account( + token2022_ata, + account, + TOKEN_2022_PROGRAM_ID, + request.mint, + SourceKind::Token2022Hot, + ) { + hot_sources.token2022 = Some(entry); + sources.push(src); + } + } + } + } + + let cold_response = get_compressed_token_accounts_by_owner_v2( + conn, + GetCompressedTokenAccountsByOwner { + owner: request.owner, + mint: Some(request.mint), + cursor: None, + limit: None, + }, + ) + .await?; + + let mut cold_accounts: Vec = Vec::new(); + let mut cold_sources: Vec = cold_response + .value + .items + .into_iter() + .map(|item| { + cold_accounts.push(item.account.clone()); + let spl = token_data_to_spl_account(&item.token_data); + Source { + kind: source_kind_for_mode(options.mode), + amount: item.token_data.amount.0, + delegate: item + .token_data + .delegate + .map(|d| Pubkey::from(d.0.to_bytes())), + delegated_amount: spl.delegated_amount, + frozen: item.token_data.state == AccountState::frozen, + slot_created: item.account.slot_created.0, + lamports: item.account.lamports.0, + owner: item.account.owner, + executable: false, + rent_epoch: 0, + spl, + } + }) + .collect(); + + cold_sources.sort_by(|a, b| b.slot_created.cmp(&a.slot_created)); + sources.extend(cold_sources); + + let account = build_synthetic_account_from_sources(&mut sources); + let cold = (!cold_accounts.is_empty()).then_some(cold_accounts); + + let value = account.map(|account| AtaInterfaceValue { + key, + owner: request.owner, + mint: request.mint, + mode: options.mode, + wrap: options.wrap, + addresses: GetAtaDerivedAddresses { + light: light_ata, + spl: spl_ata, + token2022: token2022_ata, + canonical: key, + }, + account, + cold, + hot: hot_sources, + }); + + Ok(GetAtaInterfaceResponse { context, value }) +} + +#[cfg(test)] +mod tests { + use super::*; + + fn hot_source( + kind: SourceKind, + amount: u64, + delegate: Option, + delegated_amount: u64, + ) -> Source { + Source { + kind, + amount, + delegate, + delegated_amount, + frozen: false, + slot_created: u64::MAX, + lamports: 1, + owner: SerializablePubkey::default(), + executable: false, + rent_epoch: 0, + spl: SplTokenAccount { + mint: Pubkey::new_unique(), + owner: Pubkey::new_unique(), + amount, + delegate: delegate.map(COption::Some).unwrap_or(COption::None), + state: SplAccountState::Initialized, + is_native: COption::None, + delegated_amount, + close_authority: COption::None, + }, + } + } + + #[test] + fn canonical_delegate_prefers_first_hot_source() { + let d1 = Pubkey::new_unique(); + let d2 = Pubkey::new_unique(); + let mut sources = vec![ + hot_source(SourceKind::SplHot, 10, Some(d2), 9), + hot_source(SourceKind::LightHot, 10, Some(d1), 8), + ]; + + let data = build_synthetic_account_from_sources(&mut sources).expect("expected account"); + let parsed = SplTokenAccount::unpack(&data.data.0).expect("valid spl"); + assert_eq!(parsed.delegate, COption::Some(d1)); + assert_eq!(parsed.delegated_amount, 8); + } + + #[test] + fn different_hot_delegate_does_not_contribute() { + let d1 = Pubkey::new_unique(); + let d2 = Pubkey::new_unique(); + let mut sources = vec![ + hot_source(SourceKind::LightHot, 100, Some(d1), 40), + hot_source(SourceKind::SplHot, 50, Some(d2), 50), + ]; + + let data = build_synthetic_account_from_sources(&mut sources).expect("expected account"); + let parsed = SplTokenAccount::unpack(&data.data.0).expect("valid spl"); + assert_eq!(parsed.delegate, COption::Some(d1)); + assert_eq!(parsed.amount, 150); + assert_eq!(parsed.delegated_amount, 40); + } + + #[test] + fn wrap_requires_auto_mode() { + let req = GetAtaInterfaceRequest { + owner: SerializablePubkey::default(), + mint: SerializablePubkey::default(), + config: Some(GetAtaInterfaceConfig { + wrap: Some(true), + program_id: Some(SerializablePubkey::from(SPL_TOKEN_PROGRAM_ID.to_bytes())), + ..Default::default() + }), + }; + let err = resolve_request_options(&req).expect_err("expected validation error"); + assert_eq!( + err, + PhotonApiError::ValidationError( + "wrap=true is only valid when config.programId is not set (auto mode)".to_string() + ) + ); + } + + #[test] + fn unsupported_program_id_is_rejected() { + let req = GetAtaInterfaceRequest { + owner: SerializablePubkey::default(), + mint: SerializablePubkey::default(), + config: Some(GetAtaInterfaceConfig { + program_id: Some(SerializablePubkey::new_unique()), + ..Default::default() + }), + }; + let err = resolve_request_options(&req).expect_err("expected validation error"); + assert!(matches!(err, PhotonApiError::ValidationError(_))); + } + + #[test] + fn program_id_maps_to_mode() { + let req = GetAtaInterfaceRequest { + owner: SerializablePubkey::default(), + mint: SerializablePubkey::default(), + config: Some(GetAtaInterfaceConfig { + program_id: Some(SerializablePubkey::from(TOKEN_2022_PROGRAM_ID.to_bytes())), + ..Default::default() + }), + }; + let options = resolve_request_options(&req).expect("expected options"); + assert_eq!(options.mode, GetAtaProgramMode::Token2022); + } +} diff --git a/src/api/method/interface/mod.rs b/src/api/method/interface/mod.rs index 0be4588f..1830e63a 100644 --- a/src/api/method/interface/mod.rs +++ b/src/api/method/interface/mod.rs @@ -1,8 +1,10 @@ pub mod get_account_interface; +pub mod get_ata_interface; pub mod get_multiple_account_interfaces; pub mod racing; pub mod types; pub use get_account_interface::get_account_interface; +pub use get_ata_interface::get_ata_interface; pub use get_multiple_account_interfaces::get_multiple_account_interfaces; pub use types::*; diff --git a/src/api/method/interface/types.rs b/src/api/method/interface/types.rs index 1cbd7c20..77f5deff 100644 --- a/src/api/method/interface/types.rs +++ b/src/api/method/interface/types.rs @@ -54,6 +54,52 @@ pub struct GetMultipleAccountInterfacesRequest { pub commitment: Option, } +/// Program mode for getAtaInterface canonical account selection. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] +#[serde(rename_all = "camelCase")] +pub enum GetAtaProgramMode { + /// Unified mode. Canonical key is light ATA. + #[default] + Auto, + /// Force light-token ATA mode. + Light, + /// Force SPL ATA mode. + Spl, + /// Force Token-2022 ATA mode. + Token2022, +} + +/// Request for getAtaInterface +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct GetAtaInterfaceRequest { + /// Wallet owner used for ATA derivation. + pub owner: SerializablePubkey, + /// Mint used for ATA derivation and cold mint scoping. + pub mint: SerializablePubkey, + /// Optional Solana-style config object. + pub config: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] +#[serde(deny_unknown_fields, rename_all = "camelCase")] +pub struct GetAtaInterfaceConfig { + /// Optional RPC commitment for hot lookups. + pub commitment: Option, + /// Minimum context slot requirement (Solana RPC style). + pub min_context_slot: Option, + /// Optional token program id to force selection mode. + /// Supported values: + /// - light token program id + /// - SPL Token program id + /// - Token-2022 program id + pub program_id: Option, + /// Include SPL/T22 hot balances in canonical aggregation (auto mode only). + pub wrap: Option, + /// Allow PDA/off-curve owners for ATA derivation. + pub allow_owner_off_curve: Option, +} + #[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, ToSchema, Default)] #[serde(rename_all = "camelCase")] pub enum RpcCommitment { @@ -95,6 +141,59 @@ pub struct GetMultipleAccountInterfacesResponse { pub value: Vec>, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct GetAtaHotEntry { + pub address: SerializablePubkey, + pub amount: UnsignedInteger, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct GetAtaHotSources { + pub light: Option, + pub spl: Option, + pub token2022: Option, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct GetAtaDerivedAddresses { + pub light: SerializablePubkey, + pub spl: SerializablePubkey, + pub token2022: SerializablePubkey, + pub canonical: SerializablePubkey, +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct AtaInterfaceValue { + /// Canonical ATA pubkey for selected mode. + pub key: SerializablePubkey, + pub owner: SerializablePubkey, + pub mint: SerializablePubkey, + pub mode: GetAtaProgramMode, + pub wrap: bool, + /// Derived ATA addresses for all supported token programs. + pub addresses: GetAtaDerivedAddresses, + /// Canonical synthetic account after aggregation. + pub account: SolanaAccountData, + /// Raw compressed inputs used in synthesis. + pub cold: Option>, + /// Program-specific hot snapshot for write planners. + pub hot: GetAtaHotSources, +} + +/// Response for getAtaInterface +#[derive(Debug, Clone, PartialEq, Eq, Serialize, ToSchema)] +#[serde(rename_all = "camelCase")] +pub struct GetAtaInterfaceResponse { + /// Current context (slot) + pub context: Context, + /// ATA interface data, or null if not found + pub value: Option, +} + // ============ Constants ============ /// Maximum number of accounts that can be looked up in a single batch request diff --git a/src/api/rpc_server.rs b/src/api/rpc_server.rs index b9649121..6d8ff763 100644 --- a/src/api/rpc_server.rs +++ b/src/api/rpc_server.rs @@ -446,5 +446,11 @@ fn build_rpc_module(api_and_indexer: PhotonApi) -> Result, }, )?; + module.register_async_method("getAtaInterface", |rpc_params, rpc_context| async move { + let api = rpc_context.as_ref(); + let payload = rpc_params.parse()?; + api.get_ata_interface(payload).await.map_err(Into::into) + })?; + Ok(module) } diff --git a/src/openapi/mod.rs b/src/openapi/mod.rs index d56bec57..f2ff5eb7 100644 --- a/src/openapi/mod.rs +++ b/src/openapi/mod.rs @@ -34,7 +34,9 @@ use crate::api::method::get_validity_proof::{ CompressedProofWithContextV2, MerkleContextV2, RootIndex, TreeContextInfo, }; use crate::api::method::interface::types::{ - AccountInterface, GetAccountInterfaceRequest, GetAccountInterfaceResponse, + AccountInterface, AtaInterfaceValue, GetAccountInterfaceRequest, GetAccountInterfaceResponse, + GetAtaDerivedAddresses, GetAtaHotEntry, GetAtaHotSources, GetAtaInterfaceConfig, + GetAtaInterfaceRequest, GetAtaInterfaceResponse, GetAtaProgramMode, GetMultipleAccountInterfacesRequest, GetMultipleAccountInterfacesResponse, RpcCommitment, SolanaAccountData, }; @@ -161,6 +163,14 @@ const JSON_CONTENT_TYPE: &str = "application/json"; GetAccountInterfaceResponse, GetMultipleAccountInterfacesRequest, GetMultipleAccountInterfacesResponse, + GetAtaProgramMode, + AtaInterfaceValue, + GetAtaInterfaceConfig, + GetAtaDerivedAddresses, + GetAtaHotEntry, + GetAtaHotSources, + GetAtaInterfaceRequest, + GetAtaInterfaceResponse, )))] struct ApiDoc; diff --git a/src/openapi/specs/api.yaml b/src/openapi/specs/api.yaml index c57b1b5b..68cede4c 100644 --- a/src/openapi/specs/api.yaml +++ b/src/openapi/specs/api.yaml @@ -46,12 +46,9 @@ paths: address: $ref: '#/components/schemas/SerializablePubkey' commitment: - type: string - description: Optional RPC commitment for the hot (on-chain) lookup - enum: - - processed - - confirmed - - finalized + allOf: + - $ref: '#/components/schemas/RpcCommitment' + nullable: true additionalProperties: false required: true responses: @@ -91,9 +88,127 @@ paths: context: $ref: '#/components/schemas/Context' value: - allOf: - - $ref: '#/components/schemas/AccountInterface' - nullable: true + $ref: '#/components/schemas/AccountInterface' + '429': + description: Exceeded rate limit. + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + jsonrpc: + type: string + '500': + description: The server encountered an unexpected condition that prevented it from fulfilling the request. + content: + application/json: + schema: + type: object + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + jsonrpc: + type: string + /getAtaInterface: + summary: getAtaInterface + post: + requestBody: + content: + application/json: + schema: + type: object + required: + - jsonrpc + - id + - method + - params + properties: + id: + type: string + description: An ID to identify the request. + enum: + - test-account + jsonrpc: + type: string + description: The version of the JSON-RPC protocol. + enum: + - '2.0' + method: + type: string + description: The name of the method to invoke. + enum: + - getAtaInterface + params: + type: object + description: Request for getAtaInterface + required: + - owner + - mint + properties: + config: + allOf: + - $ref: '#/components/schemas/GetAtaInterfaceConfig' + nullable: true + mint: + $ref: '#/components/schemas/SerializablePubkey' + owner: + $ref: '#/components/schemas/SerializablePubkey' + additionalProperties: false + required: true + responses: + '200': + description: '' + content: + application/json: + schema: + type: object + required: + - jsonrpc + - id + properties: + error: + type: object + properties: + code: + type: integer + message: + type: string + id: + type: string + description: An ID to identify the response. + enum: + - test-account + jsonrpc: + type: string + description: The version of the JSON-RPC protocol. + enum: + - '2.0' + result: + type: object + description: Response for getAtaInterface + required: + - context + properties: + context: + $ref: '#/components/schemas/Context' + value: + $ref: '#/components/schemas/AtaInterfaceValue' '429': description: Exceeded rate limit. content: @@ -3031,12 +3146,9 @@ paths: $ref: '#/components/schemas/SerializablePubkey' description: List of account addresses to look up (max 100) commitment: - type: string - description: Optional RPC commitment for hot (on-chain) lookups - enum: - - processed - - confirmed - - finalized + allOf: + - $ref: '#/components/schemas/RpcCommitment' + nullable: true additionalProperties: false required: true responses: @@ -4857,6 +4969,40 @@ components: tree: $ref: '#/components/schemas/SerializablePubkey' additionalProperties: false + AtaInterfaceValue: + type: object + required: + - key + - owner + - mint + - mode + - wrap + - addresses + - account + - hot + properties: + account: + $ref: '#/components/schemas/SolanaAccountData' + addresses: + $ref: '#/components/schemas/GetAtaDerivedAddresses' + cold: + type: array + items: + $ref: '#/components/schemas/AccountV2' + description: Raw compressed inputs used in synthesis. + nullable: true + hot: + $ref: '#/components/schemas/GetAtaHotSources' + key: + $ref: '#/components/schemas/SerializablePubkey' + mint: + $ref: '#/components/schemas/SerializablePubkey' + mode: + $ref: '#/components/schemas/GetAtaProgramMode' + owner: + $ref: '#/components/schemas/SerializablePubkey' + wrap: + type: boolean Base58String: type: string description: A base 58 encoded string. @@ -5004,6 +5150,112 @@ components: properties: memcmp: $ref: '#/components/schemas/Memcmp' + GetAccountInterfaceRequest: + type: object + description: Request for getAccountInterface + required: + - address + properties: + address: + $ref: '#/components/schemas/SerializablePubkey' + commitment: + $ref: '#/components/schemas/RpcCommitment' + additionalProperties: false + GetAccountInterfaceResponse: + type: object + description: Response for getAccountInterface + required: + - context + properties: + context: + $ref: '#/components/schemas/Context' + value: + $ref: '#/components/schemas/AccountInterface' + GetAtaDerivedAddresses: + type: object + required: + - light + - spl + - token2022 + - canonical + properties: + canonical: + $ref: '#/components/schemas/SerializablePubkey' + light: + $ref: '#/components/schemas/SerializablePubkey' + spl: + $ref: '#/components/schemas/SerializablePubkey' + token2022: + $ref: '#/components/schemas/SerializablePubkey' + GetAtaHotEntry: + type: object + required: + - address + - amount + properties: + address: + $ref: '#/components/schemas/SerializablePubkey' + amount: + $ref: '#/components/schemas/UnsignedInteger' + GetAtaHotSources: + type: object + properties: + light: + $ref: '#/components/schemas/GetAtaHotEntry' + spl: + $ref: '#/components/schemas/GetAtaHotEntry' + token2022: + $ref: '#/components/schemas/GetAtaHotEntry' + GetAtaInterfaceConfig: + type: object + properties: + allowOwnerOffCurve: + type: boolean + description: Allow PDA/off-curve owners for ATA derivation. + nullable: true + commitment: + $ref: '#/components/schemas/RpcCommitment' + minContextSlot: + $ref: '#/components/schemas/UnsignedInteger' + programId: + $ref: '#/components/schemas/SerializablePubkey' + wrap: + type: boolean + description: Include SPL/T22 hot balances in canonical aggregation (auto mode only). + nullable: true + additionalProperties: false + GetAtaInterfaceRequest: + type: object + description: Request for getAtaInterface + required: + - owner + - mint + properties: + config: + $ref: '#/components/schemas/GetAtaInterfaceConfig' + mint: + $ref: '#/components/schemas/SerializablePubkey' + owner: + $ref: '#/components/schemas/SerializablePubkey' + additionalProperties: false + GetAtaInterfaceResponse: + type: object + description: Response for getAtaInterface + required: + - context + properties: + context: + $ref: '#/components/schemas/Context' + value: + $ref: '#/components/schemas/AtaInterfaceValue' + GetAtaProgramMode: + type: string + description: Program mode for getAtaInterface canonical account selection. + enum: + - auto + - light + - spl + - token2022 GetCompressedAccountProofResponseValue: type: object required: @@ -5065,6 +5317,36 @@ components: treeContext: $ref: '#/components/schemas/TreeContextInfo' additionalProperties: false + GetMultipleAccountInterfacesRequest: + type: object + description: Request for getMultipleAccountInterfaces + required: + - addresses + properties: + addresses: + type: array + items: + $ref: '#/components/schemas/SerializablePubkey' + description: List of account addresses to look up (max 100) + commitment: + $ref: '#/components/schemas/RpcCommitment' + additionalProperties: false + GetMultipleAccountInterfacesResponse: + type: object + description: Response for getMultipleAccountInterfaces + required: + - context + - value + properties: + context: + $ref: '#/components/schemas/Context' + value: + type: array + items: + allOf: + - $ref: '#/components/schemas/AccountInterface' + nullable: true + description: List of account results (Some for found accounts, None for not found) Hash: type: string description: A 32-byte hash represented as a base58 string. @@ -5358,6 +5640,12 @@ components: type: integer format: uint64 minimum: 0 + RpcCommitment: + type: string + enum: + - processed + - confirmed + - finalized SerializablePubkey: type: string description: A Solana public key represented as a base58 string. diff --git a/src/openapi/specs/getAtaInterface.spec.yaml b/src/openapi/specs/getAtaInterface.spec.yaml new file mode 100644 index 00000000..930c70ef --- /dev/null +++ b/src/openapi/specs/getAtaInterface.spec.yaml @@ -0,0 +1,264 @@ +specVersion: 1 +name: getAtaInterface +status: draft +owner: photon-api +lastUpdated: 2026-03-19 + +summary: > + Return canonical ATA interface state for (owner, mint) with server-side + aggregation. This is a read contract only (no server-planned write actions). + +method: + rpc: getAtaInterface + httpPath: /getAtaInterface + transport: json-rpc-2.0 + +request: + type: object + additionalProperties: false + required: + - owner + - mint + properties: + owner: + $ref: "#/components/schemas/SerializablePubkey" + description: Wallet owner used for ATA derivation. + mint: + $ref: "#/components/schemas/SerializablePubkey" + description: Mint used for ATA derivation and cold mint scoping. + config: + $ref: "#/components/schemas/GetAtaInterfaceConfig" + description: Optional Solana-style config object. + +response: + type: object + required: [context, value] + properties: + context: + $ref: "#/components/schemas/Context" + value: + oneOf: + - type: "null" + - $ref: "#/components/schemas/GetAtaInterfaceValue" + description: Null when no relevant hot or cold state is found. + +components: + schemas: + GetAtaInterfaceValue: + type: object + required: + - key + - owner + - mint + - mode + - wrap + - account + - cold + - hot + properties: + key: + $ref: "#/components/schemas/SerializablePubkey" + description: Canonical ATA pubkey for selected mode. + owner: + $ref: "#/components/schemas/SerializablePubkey" + mint: + $ref: "#/components/schemas/SerializablePubkey" + mode: + type: string + enum: [auto, light, spl, token2022] + wrap: + type: boolean + addresses: + $ref: "#/components/schemas/GetAtaDerivedAddresses" + account: + $ref: "#/components/schemas/SolanaAccountData" + description: | + Canonical synthetic account view after aggregation. + For token accounts this is packed SPL token account bytes. + cold: + type: array + nullable: true + items: + $ref: "#/components/schemas/AccountV2" + description: | + Raw compressed inputs used for synthesis (same shape as getAccountInterface). + hot: + $ref: "#/components/schemas/GetAtaHotSources" + description: | + Program-specific hot account snapshot for write planners. + Amounts are full hot balances per account. + + GetAtaHotSources: + type: object + required: [light, spl, token2022] + properties: + light: + $ref: "#/components/schemas/GetAtaHotEntry" + spl: + $ref: "#/components/schemas/GetAtaHotEntry" + token2022: + $ref: "#/components/schemas/GetAtaHotEntry" + + GetAtaHotEntry: + oneOf: + - type: "null" + - type: object + required: [address, amount] + properties: + address: + $ref: "#/components/schemas/SerializablePubkey" + amount: + $ref: "#/components/schemas/UnsignedInteger" + + GetAtaInterfaceConfig: + type: object + additionalProperties: false + properties: + commitment: + type: string + enum: [processed, confirmed, finalized] + default: confirmed + minContextSlot: + $ref: "#/components/schemas/UnsignedInteger" + programId: + $ref: "#/components/schemas/SerializablePubkey" + description: Optional explicit token program id (light/spl/token2022). + wrap: + type: boolean + default: false + allowOwnerOffCurve: + type: boolean + default: false + + GetAtaDerivedAddresses: + type: object + required: [light, spl, token2022, canonical] + properties: + light: + $ref: "#/components/schemas/SerializablePubkey" + spl: + $ref: "#/components/schemas/SerializablePubkey" + token2022: + $ref: "#/components/schemas/SerializablePubkey" + canonical: + $ref: "#/components/schemas/SerializablePubkey" + +behavior: + validation: + - owner and mint must be valid pubkeys. + - if config.allowOwnerOffCurve=false and owner is off-curve, return ValidationError. + - if config.programId is set and config.wrap=true, return ValidationError. + - if config.programId is set to unsupported program, return ValidationError. + - if context.slot < config.minContextSlot, return StaleSlot. + + addressDerivation: + - derive light ATA from (owner, mint, LIGHT_TOKEN_PROGRAM_ID). + - derive SPL ATA from (owner, mint, SPL_TOKEN_PROGRAM_ID). + - derive Token-2022 ATA from (owner, mint, TOKEN_2022_PROGRAM_ID). + - canonical key selection: + - auto/light => light ATA + - spl => SPL ATA + - token2022 => Token-2022 ATA + + sourceFetchPlan: + - hot: + - light ATA always read in auto/light mode + - SPL ATA read in spl mode, and in auto when wrap=true + - Token-2022 ATA read in token2022 mode, and in auto when wrap=true + - cold: + - base query is owner+mint scoped via getCompressedTokenAccountsByOwner(owner, { mint }) + - only token-shaped compressed accounts are retained + + aggregation: + - canonical account is synthesized from selected hot/cold sources. + - source priority: + - auto/wrap=false: light-hot > light-cold + - auto/wrap=true: light-hot > light-cold > spl-hot > token2022-hot + - light: light-hot > light-cold + - spl: spl-hot > spl-cold + - token2022: token2022-hot > token2022-cold + - delegate and frozen semantics follow existing getAccountInterface synthesis rules. + - cold token synthetic owner uses ata_owner metadata when present and valid; + fallback to compressed token owner. + + notFound: + - if no relevant hot/cold state remains after filtering, return value=null. + + partialFailure: + - if at least one valid source family succeeds, return best-effort result. + - if all relevant source families fail, return UnexpectedError. + +errorModel: + - ValidationError: + - invalid pubkeys + - off-curve owner when allowOwnerOffCurve=false + - wrap=true with non-auto mode + - UnexpectedError: + - all-source rpc/db timeout/failure + +e2eAcceptance: + - name: light_hot_only + request: + owner: + mint: + config: + programId: + expect: + - value.key == derived_light_ata + - value.hot.light is not null + - value.hot.spl is null + - value.hot.token2022 is null + + - name: light_cold_only + request: + owner: + mint: + config: + programId: + setup: + - no light hot account + - cold compressed token accounts exist for owner+mint + expect: + - value.account exists + - value.cold not empty + + - name: ata_mode_owner_and_ata_owner_semantics + request: + owner: + mint: + config: + programId: + setup: + - ATA-mode compressed owner semantics present + - ata_owner metadata present with wallet owner + expect: + - lookup includes ATA-mode compressed rows + - synthetic SPL owner uses ata_owner when valid + + - name: unified_wrap_includes_spl_t22_hot + request: + owner: + mint: + config: + wrap: true + setup: + - light hot/cold + SPL hot + T22 hot exist + expect: + - value.hot.light is not null + - value.hot.spl is not null + - value.hot.token2022 is not null + + - name: mode_wrap_validation + request: + owner: + mint: + config: + programId: + wrap: true + expect: + - ValidationError + +notes: + - This contract intentionally avoids client-legacy planner flags. + - Write planners derive load/wrap steps from canonical account + cold + hot fields. + - Keep getAccountInterface/getMultipleAccountInterfaces contracts unchanged. From 6647c27bde108a97e986280a7495d934fcf199bf Mon Sep 17 00:00:00 2001 From: Swenschaeferjohann Date: Fri, 20 Mar 2026 00:17:56 +0000 Subject: [PATCH 16/16] run lookups concurrently --- src/api/method/interface/get_ata_interface.rs | 305 ++++++++++++++---- 1 file changed, 234 insertions(+), 71 deletions(-) diff --git a/src/api/method/interface/get_ata_interface.rs b/src/api/method/interface/get_ata_interface.rs index 9f440ccd..6472dc17 100644 --- a/src/api/method/interface/get_ata_interface.rs +++ b/src/api/method/interface/get_ata_interface.rs @@ -1,4 +1,5 @@ use sea_orm::DatabaseConnection; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use solana_account::Account as SolanaAccount; use solana_client::nonblocking::rpc_client::RpcClient; use solana_program_option::COption; @@ -15,6 +16,7 @@ use crate::common::typedefs::context::Context; use crate::common::typedefs::serializable_pubkey::SerializablePubkey; use crate::common::typedefs::token_data::{AccountState, TokenData}; use crate::common::typedefs::unsigned_integer::UnsignedInteger; +use crate::dao::generated::token_accounts; use crate::ingester::persist::LIGHT_TOKEN_PROGRAM_ID; use super::racing::hot_lookup; @@ -178,6 +180,17 @@ fn token_data_to_spl_account(token_data: &TokenData) -> SplTokenAccount { } } +fn token_data_to_spl_account_with_wallet_owner( + token_data: &TokenData, + wallet_owner: Option<[u8; 32]>, +) -> SplTokenAccount { + let mut spl = token_data_to_spl_account(token_data); + if let Some(owner) = wallet_owner { + spl.owner = Pubkey::from(owner); + } + spl +} + fn source_kind_for_mode(mode: GetAtaProgramMode) -> SourceKind { match mode { GetAtaProgramMode::Auto | GetAtaProgramMode::Light => SourceKind::LightCold, @@ -360,6 +373,36 @@ fn resolve_request_options(request: &GetAtaInterfaceRequest) -> Result, + db_slot: u64, + max_hot_slot: Option, +) -> Result<(), PhotonApiError> { + let Some(min_slot) = min_context_slot else { + return Ok(()); + }; + + if db_slot < min_slot { + return Err(PhotonApiError::StaleSlot(min_slot - db_slot)); + } + + if let Some(hot_slot) = max_hot_slot { + if hot_slot < min_slot { + return Err(PhotonApiError::StaleSlot(min_slot - hot_slot)); + } + } + + Ok(()) +} + +fn should_surface_hot_error( + account_present: bool, + attempted_hot_lookups: usize, + hot_error_present: bool, +) -> bool { + !account_present && attempted_hot_lookups > 0 && hot_error_present +} + /// Return canonical ATA interface for (owner, mint) with hot/cold aggregation. pub async fn get_ata_interface( conn: &DatabaseConnection, @@ -369,12 +412,6 @@ pub async fn get_ata_interface( let context = Context::extract(conn).await?; let options = resolve_request_options(&request)?; - if let Some(min_context_slot) = options.min_context_slot { - if context.slot < min_context_slot { - return Err(PhotonApiError::StaleSlot(min_context_slot - context.slot)); - } - } - if !options.allow_owner_off_curve && !request.owner.0.is_on_curve() { return Err(PhotonApiError::ValidationError( "Owner is off-curve; set allowOwnerOffCurve=true to allow PDA owners".to_string(), @@ -413,86 +450,168 @@ pub async fn get_ata_interface( token2022: None, }; let mut sources: Vec = Vec::new(); + let mut max_hot_slot: Option = None; + let mut first_hot_error: Option = None; + let attempted_hot_lookups = + usize::from(fetch_light_hot) + usize::from(fetch_spl_hot) + usize::from(fetch_t22_hot); + + let light_hot_fut = async { + if fetch_light_hot { + Some( + hot_lookup( + rpc_client, + &Pubkey::from(light_ata.0.to_bytes()), + options.commitment, + ) + .await, + ) + } else { + None + } + }; + let spl_hot_fut = async { + if fetch_spl_hot { + Some( + hot_lookup( + rpc_client, + &Pubkey::from(spl_ata.0.to_bytes()), + options.commitment, + ) + .await, + ) + } else { + None + } + }; + let t22_hot_fut = async { + if fetch_t22_hot { + Some( + hot_lookup( + rpc_client, + &Pubkey::from(token2022_ata.0.to_bytes()), + options.commitment, + ) + .await, + ) + } else { + None + } + }; + let cold_fut = get_compressed_token_accounts_by_owner_v2( + conn, + GetCompressedTokenAccountsByOwner { + owner: request.owner, + mint: Some(request.mint), + cursor: None, + limit: None, + }, + ); - if fetch_light_hot { - if let Ok(hot) = hot_lookup( - rpc_client, - &Pubkey::from(light_ata.0.to_bytes()), - options.commitment, - ) - .await - { - if let Some(account) = hot.account.as_ref() { - if let Some((entry, src)) = hot_entry_from_account( - light_ata, - account, - LIGHT_TOKEN_PROGRAM_ID, - request.mint, - SourceKind::LightHot, - ) { - hot_sources.light = Some(entry); - sources.push(src); + let (light_hot_res, spl_hot_res, t22_hot_res, cold_result) = + tokio::join!(light_hot_fut, spl_hot_fut, t22_hot_fut, cold_fut); + + if let Some(result) = light_hot_res { + match result { + Ok(hot) => { + max_hot_slot = Some(max_hot_slot.map_or(hot.slot, |s| s.max(hot.slot))); + if let Some(account) = hot.account.as_ref() { + if let Some((entry, src)) = hot_entry_from_account( + light_ata, + account, + LIGHT_TOKEN_PROGRAM_ID, + request.mint, + SourceKind::LightHot, + ) { + hot_sources.light = Some(entry); + sources.push(src); + } + } + } + Err(e) => { + if first_hot_error.is_none() { + first_hot_error = Some(e); } } } } - if fetch_spl_hot { - if let Ok(hot) = hot_lookup( - rpc_client, - &Pubkey::from(spl_ata.0.to_bytes()), - options.commitment, - ) - .await - { - if let Some(account) = hot.account.as_ref() { - if let Some((entry, src)) = hot_entry_from_account( - spl_ata, - account, - SPL_TOKEN_PROGRAM_ID, - request.mint, - SourceKind::SplHot, - ) { - hot_sources.spl = Some(entry); - sources.push(src); + if let Some(result) = spl_hot_res { + match result { + Ok(hot) => { + max_hot_slot = Some(max_hot_slot.map_or(hot.slot, |s| s.max(hot.slot))); + if let Some(account) = hot.account.as_ref() { + if let Some((entry, src)) = hot_entry_from_account( + spl_ata, + account, + SPL_TOKEN_PROGRAM_ID, + request.mint, + SourceKind::SplHot, + ) { + hot_sources.spl = Some(entry); + sources.push(src); + } + } + } + Err(e) => { + if first_hot_error.is_none() { + first_hot_error = Some(e); } } } } - if fetch_t22_hot { - if let Ok(hot) = hot_lookup( - rpc_client, - &Pubkey::from(token2022_ata.0.to_bytes()), - options.commitment, - ) - .await - { - if let Some(account) = hot.account.as_ref() { - if let Some((entry, src)) = hot_entry_from_account( - token2022_ata, - account, - TOKEN_2022_PROGRAM_ID, - request.mint, - SourceKind::Token2022Hot, - ) { - hot_sources.token2022 = Some(entry); - sources.push(src); + if let Some(result) = t22_hot_res { + match result { + Ok(hot) => { + max_hot_slot = Some(max_hot_slot.map_or(hot.slot, |s| s.max(hot.slot))); + if let Some(account) = hot.account.as_ref() { + if let Some((entry, src)) = hot_entry_from_account( + token2022_ata, + account, + TOKEN_2022_PROGRAM_ID, + request.mint, + SourceKind::Token2022Hot, + ) { + hot_sources.token2022 = Some(entry); + sources.push(src); + } + } + } + Err(e) => { + if first_hot_error.is_none() { + first_hot_error = Some(e); } } } } - let cold_response = get_compressed_token_accounts_by_owner_v2( - conn, - GetCompressedTokenAccountsByOwner { - owner: request.owner, - mint: Some(request.mint), - cursor: None, - limit: None, - }, - ) - .await?; + validate_min_context_slot(options.min_context_slot, context.slot, max_hot_slot)?; + let cold_response = cold_result?; + + let hashes: Vec> = cold_response + .value + .items + .iter() + .map(|i| i.account.hash.to_vec()) + .collect(); + let token_rows = if hashes.is_empty() { + Vec::new() + } else { + token_accounts::Entity::find() + .filter(token_accounts::Column::Spent.eq(false)) + .filter(token_accounts::Column::Hash.is_in(hashes)) + .all(conn) + .await + .map_err(PhotonApiError::DatabaseError)? + }; + let ata_owner_by_hash: std::collections::HashMap, [u8; 32]> = token_rows + .into_iter() + .filter_map(|row| { + row.ata_owner + .and_then(|bytes| <[u8; 32]>::try_from(bytes.as_slice()).ok()) + .map(|owner| (row.hash, owner)) + }) + .collect(); let mut cold_accounts: Vec = Vec::new(); let mut cold_sources: Vec = cold_response @@ -501,7 +620,8 @@ pub async fn get_ata_interface( .into_iter() .map(|item| { cold_accounts.push(item.account.clone()); - let spl = token_data_to_spl_account(&item.token_data); + let wallet_owner = ata_owner_by_hash.get(&item.account.hash.to_vec()).copied(); + let spl = token_data_to_spl_account_with_wallet_owner(&item.token_data, wallet_owner); Source { kind: source_kind_for_mode(options.mode), amount: item.token_data.amount.0, @@ -525,6 +645,9 @@ pub async fn get_ata_interface( sources.extend(cold_sources); let account = build_synthetic_account_from_sources(&mut sources); + if should_surface_hot_error(account.is_some(), attempted_hot_lookups, first_hot_error.is_some()) { + return Err(first_hot_error.expect("checked Some above")); + } let cold = (!cold_accounts.is_empty()).then_some(cold_accounts); let value = account.map(|account| AtaInterfaceValue { @@ -659,4 +782,44 @@ mod tests { let options = resolve_request_options(&req).expect("expected options"); assert_eq!(options.mode, GetAtaProgramMode::Token2022); } + + #[test] + fn min_context_slot_checks_both_db_and_hot_slots() { + let err = validate_min_context_slot(Some(100), 90, Some(200)) + .expect_err("expected stale db slot error"); + assert_eq!(err, PhotonApiError::StaleSlot(10)); + + let err = validate_min_context_slot(Some(100), 110, Some(95)) + .expect_err("expected stale hot slot error"); + assert_eq!(err, PhotonApiError::StaleSlot(5)); + + validate_min_context_slot(Some(100), 110, Some(120)).expect("should pass"); + validate_min_context_slot(Some(100), 110, None).expect("should pass without hot"); + } + + #[test] + fn wallet_owner_override_is_applied_to_spl_owner() { + let token_data = TokenData { + mint: SerializablePubkey::from(Pubkey::new_unique()), + owner: SerializablePubkey::from(Pubkey::new_unique()), + amount: UnsignedInteger(10), + delegate: None, + state: AccountState::initialized, + tlv: None, + }; + let wallet_owner = Pubkey::new_unique(); + let spl = token_data_to_spl_account_with_wallet_owner( + &token_data, + Some(wallet_owner.to_bytes()), + ); + assert_eq!(spl.owner, wallet_owner); + } + + #[test] + fn hot_error_is_surfaced_only_when_no_aggregate_value_exists() { + assert!(should_surface_hot_error(false, 1, true)); + assert!(!should_surface_hot_error(true, 1, true)); + assert!(!should_surface_hot_error(false, 0, true)); + assert!(!should_surface_hot_error(false, 1, false)); + } }