├── rust-toolchain.toml ├── program ├── src │ ├── tools │ │ ├── mod.rs │ │ └── account.rs │ ├── instruction.rs │ ├── entrypoint.rs │ ├── error.rs │ ├── lib.rs │ └── processor.rs ├── tests │ ├── fixtures │ │ ├── spl_token_2022.so │ │ ├── token-mint-data.bin │ │ └── pinocchio_token_program.so │ ├── spl_token_create.rs │ ├── extended_mint.rs │ ├── create_idempotent.rs │ ├── process_create_associated_token_account.rs │ └── recover_nested.rs └── Cargo.toml ├── README.md ├── package.json ├── .gitignore ├── scripts ├── spellcheck.toml ├── solana.dic └── cliff.toml ├── pnpm-lock.yaml ├── rustfmt.toml ├── interface ├── src │ ├── lib.rs │ ├── address.rs │ └── instruction.rs └── Cargo.toml ├── Cargo.toml ├── .github ├── dependabot.yml └── workflows │ ├── dependabot-auto-merge.yml │ ├── main.yml │ └── publish-rust.yml ├── mollusk_harness ├── Cargo.toml └── src │ └── lib.rs ├── SECURITY.md ├── Makefile ├── LICENSE └── Cargo.lock /rust-toolchain.toml: -------------------------------------------------------------------------------- 1 | [toolchain] 2 | channel = "1.86.0" 3 | -------------------------------------------------------------------------------- /program/src/tools/mod.rs: -------------------------------------------------------------------------------- 1 | //! Utility functions 2 | 3 | pub mod account; 4 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # associated-token-account 2 | The SPL Associated Token Account program and its clients 3 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "spl-associated-token-account", 3 | "private": true, 4 | "packageManager": "pnpm@9.15.4" 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .anchor 2 | .cargo 3 | .DS_Store 4 | **/.DS_Store 5 | **/target 6 | **/*.rs.bk 7 | node_modules 8 | test-ledger 9 | dist 10 | -------------------------------------------------------------------------------- /program/tests/fixtures/spl_token_2022.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solana-program/associated-token-account/HEAD/program/tests/fixtures/spl_token_2022.so -------------------------------------------------------------------------------- /scripts/spellcheck.toml: -------------------------------------------------------------------------------- 1 | [Hunspell] 2 | use_builtin = true 3 | skip_os_lookups = false 4 | search_dirs = ["."] 5 | extra_dictionaries = ["solana.dic"] 6 | 7 | -------------------------------------------------------------------------------- /program/tests/fixtures/token-mint-data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solana-program/associated-token-account/HEAD/program/tests/fixtures/token-mint-data.bin -------------------------------------------------------------------------------- /program/tests/fixtures/pinocchio_token_program.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/solana-program/associated-token-account/HEAD/program/tests/fixtures/pinocchio_token_program.so -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: '9.0' 2 | 3 | settings: 4 | autoInstallPeers: true 5 | excludeLinksFromLockfile: false 6 | 7 | importers: 8 | 9 | .: {} 10 | -------------------------------------------------------------------------------- /rustfmt.toml: -------------------------------------------------------------------------------- 1 | max_width = 100 2 | reorder_imports = true 3 | reorder_modules = true 4 | 5 | # == Nightly only. == 6 | # imports_indent = "Block" 7 | # imports_layout = "Mixed" 8 | # imports_granularity = "Crate" 9 | # group_imports = "Preserve" 10 | # reorder_impl_items = false 11 | -------------------------------------------------------------------------------- /program/src/instruction.rs: -------------------------------------------------------------------------------- 1 | //! Program instructions 2 | #![deprecated( 3 | since = "7.1.0", 4 | note = "Use `spl_associated_token_account_interface::instruction` instead and remove `spl_associated_token_account` as a dependency" 5 | )] 6 | pub use spl_associated_token_account_interface::instruction::*; 7 | -------------------------------------------------------------------------------- /interface/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Client crate for interacting with the spl-associated-token-account program 2 | #![deny(missing_docs)] 3 | #![forbid(unsafe_code)] 4 | 5 | pub mod address; 6 | pub mod instruction; 7 | 8 | /// Module defining the program id 9 | pub mod program { 10 | solana_pubkey::declare_id!("ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL"); 11 | } 12 | -------------------------------------------------------------------------------- /program/src/entrypoint.rs: -------------------------------------------------------------------------------- 1 | //! Program entrypoint 2 | 3 | #![cfg(not(feature = "no-entrypoint"))] 4 | 5 | use { 6 | solana_account_info::AccountInfo, solana_program_error::ProgramResult, solana_pubkey::Pubkey, 7 | }; 8 | 9 | solana_program_entrypoint::entrypoint!(process_instruction); 10 | fn process_instruction( 11 | program_id: &Pubkey, 12 | accounts: &[AccountInfo], 13 | instruction_data: &[u8], 14 | ) -> ProgramResult { 15 | crate::processor::process_instruction(program_id, accounts, instruction_data) 16 | } 17 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | resolver = "2" 3 | members = ["interface", "program", "mollusk_harness"] 4 | 5 | [workspace.metadata.cli] 6 | solana = "3.0.0" 7 | 8 | # Specify Rust toolchains for rustfmt, clippy, and build. 9 | # Any unprovided toolchains default to stable. 10 | [workspace.metadata.toolchains] 11 | format = "nightly-2025-02-16" 12 | lint = "nightly-2025-02-16" 13 | 14 | [workspace.metadata.spellcheck] 15 | config = "scripts/spellcheck.toml" 16 | 17 | [workspace.metadata.release] 18 | pre-release-commit-message = "Publish {{crate_name}} v{{version}}" 19 | tag-message = "Publish {{crate_name}} v{{version}}" 20 | consolidate-commits = false 21 | -------------------------------------------------------------------------------- /program/src/error.rs: -------------------------------------------------------------------------------- 1 | //! Error types 2 | 3 | use {num_derive::FromPrimitive, solana_program_error::ProgramError, thiserror::Error}; 4 | 5 | /// Errors that may be returned by the program. 6 | #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] 7 | pub enum AssociatedTokenAccountError { 8 | // 0 9 | /// Associated token account owner does not match address derivation 10 | #[error("Associated token account owner does not match address derivation")] 11 | InvalidOwner, 12 | } 13 | impl From for ProgramError { 14 | fn from(e: AssociatedTokenAccountError) -> Self { 15 | ProgramError::Custom(e as u32) 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /scripts/solana.dic: -------------------------------------------------------------------------------- 1 | 1000 2 | config 3 | metadata 4 | json 5 | uri 6 | ui 7 | cli 8 | readme/S 9 | arg/S 10 | vec/S 11 | enum/S 12 | noop/S 13 | realloc/S 14 | overallocate/SGD 15 | namespace 16 | serde 17 | deserialize/SRGD 18 | deserialization 19 | struct/S 20 | param/S 21 | tuple/S 22 | metas 23 | infos 24 | async 25 | subcommand 26 | repo 27 | init 28 | solana 29 | sol/S 30 | blockchain/S 31 | permissionless 32 | composability 33 | runtime 34 | onchain 35 | offchain 36 | keypair/S 37 | decrypt/SGD 38 | lamport/S 39 | validator/S 40 | pubkey/S 41 | sysvar/S 42 | timestamp/S 43 | entrypoint/S 44 | spl 45 | pda/S 46 | multisignature/S 47 | multisig/S 48 | staker/S 49 | APY 50 | codama 51 | autogenerated 52 | ATA 53 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | # To get started with Dependabot version updates, you'll need to specify which 2 | # package ecosystems to update and where the package manifests are located. 3 | # Please see the documentation for all configuration options: 4 | # https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file 5 | 6 | version: 2 7 | updates: 8 | - package-ecosystem: cargo 9 | directory: "/" 10 | schedule: 11 | interval: daily 12 | time: "08:00" 13 | timezone: UTC 14 | open-pull-requests-limit: 6 15 | - package-ecosystem: npm 16 | directory: "/" 17 | schedule: 18 | interval: daily 19 | time: "09:00" 20 | timezone: UTC 21 | open-pull-requests-limit: 6 22 | -------------------------------------------------------------------------------- /interface/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spl-associated-token-account-interface" 3 | version = "2.0.0" 4 | description = "Solana Program Library Associated Token Account Interface" 5 | authors = ["Anza Maintainers "] 6 | repository = "https://github.com/solana-program/associated-token-account" 7 | license = "Apache-2.0" 8 | edition = "2021" 9 | 10 | [features] 11 | borsh = ["dep:borsh"] 12 | 13 | [dependencies] 14 | borsh = { version = "1", optional = true, features = ["unstable__schema"] } 15 | solana-instruction = { version = "3.1.0", features = ["std"] } 16 | solana-pubkey = { version = "4.0.0", features = ["curve25519"] } 17 | 18 | [dev-dependencies] 19 | solana-sdk-ids = "3.1.0" 20 | 21 | [package.metadata.docs.rs] 22 | targets = ["x86_64-unknown-linux-gnu"] 23 | -------------------------------------------------------------------------------- /.github/workflows/dependabot-auto-merge.yml: -------------------------------------------------------------------------------- 1 | name: Dependabot auto-merge 2 | on: pull_request 3 | 4 | permissions: 5 | contents: write 6 | pull-requests: write 7 | 8 | jobs: 9 | dependabot: 10 | runs-on: ubuntu-latest 11 | if: github.event.pull_request.user.login == 'dependabot[bot]' && github.repository_owner == 'solana-program' 12 | steps: 13 | - name: Enable auto-merge 14 | run: gh pr merge --auto --squash "$PR_URL" 15 | env: 16 | PR_URL: ${{ github.event.pull_request.html_url }} 17 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 18 | - name: Approve 19 | run: gh pr review --approve "$PR_URL" 20 | env: 21 | PR_URL: ${{ github.event.pull_request.html_url }} 22 | GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} 23 | -------------------------------------------------------------------------------- /program/tests/spl_token_create.rs: -------------------------------------------------------------------------------- 1 | use spl_associated_token_account_mollusk_harness::{AtaTestHarness, CreateAtaInstructionType}; 2 | 3 | #[test] 4 | fn success_create() { 5 | let mut harness = 6 | AtaTestHarness::new(&spl_token_interface::id()).with_wallet_and_mint(1_000_000, 6); 7 | harness.create_ata(CreateAtaInstructionType::default()); 8 | } 9 | 10 | #[test] 11 | fn success_using_deprecated_instruction_creator() { 12 | let mut harness = 13 | AtaTestHarness::new(&spl_token_interface::id()).with_wallet_and_mint(1_000_000, 6); 14 | 15 | harness.create_and_check_ata_with_custom_instruction( 16 | CreateAtaInstructionType::default(), 17 | |instruction| { 18 | instruction.data = vec![]; 19 | instruction 20 | .accounts 21 | .push(solana_instruction::AccountMeta::new_readonly( 22 | solana_sysvar::rent::id(), 23 | false, 24 | )); 25 | }, 26 | ); 27 | } 28 | -------------------------------------------------------------------------------- /mollusk_harness/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spl-associated-token-account-mollusk-harness" 3 | version = "1.0.0" 4 | description = "SPL Associated Token Account Mollusk Testing Harness" 5 | authors = ["Anza Maintainers "] 6 | repository = "https://github.com/solana-program/associated-token-account" 7 | license = "Apache-2.0" 8 | edition = "2021" 9 | 10 | [lib] 11 | crate-type = ["lib"] 12 | 13 | [dependencies] 14 | mollusk-svm = { version = "0.7.2" } 15 | mollusk-svm-programs-token = { version = "0.7.2" } 16 | solana-account = "3.2" 17 | solana-instruction = "3.1" 18 | solana-keypair = "3.0" 19 | solana-program-error = "3.0" 20 | solana-program-option = "3.0" 21 | solana-program-pack = "3.0" 22 | solana-pubkey = "4.0" 23 | solana-rent = "3.1" 24 | solana-signer = "3.0" 25 | solana-system-interface = { version = "3.0", features = ["bincode"] } 26 | solana-sysvar = "3.1" 27 | spl-associated-token-account-interface = { version = "2.0", path = "../interface" } 28 | spl-token-interface = "2.0" 29 | spl-token-2022-interface = "2.1" 30 | -------------------------------------------------------------------------------- /program/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "spl-associated-token-account" 3 | version = "8.0.0" 4 | description = "Solana Program Library Associated Token Account" 5 | authors = ["Anza Maintainers "] 6 | repository = "https://github.com/solana-program/associated-token-account" 7 | license = "Apache-2.0" 8 | edition = "2021" 9 | 10 | [features] 11 | no-entrypoint = [] 12 | test-sbf = [] 13 | 14 | [dependencies] 15 | borsh = "1.6.0" 16 | num-derive = "0.4" 17 | num-traits = "0.2" 18 | solana-account-info = "3.1" 19 | solana-cpi = "3.1" 20 | solana-instruction = "3.1" 21 | solana-msg = "3.0" 22 | solana-program-entrypoint = "3.1" 23 | solana-program-error = "3.0" 24 | solana-pubkey = "4.0" 25 | solana-rent = "3.1" 26 | solana-sdk-ids = "3.1" 27 | solana-system-interface = { version = "3.0", features = ["bincode"] } 28 | solana-sysvar = "3.1" 29 | spl-associated-token-account-interface = { version = "2.0.0", path = "../interface", features = ["borsh"] } 30 | spl-token-interface = "2.0.0" 31 | spl-token-2022-interface = "2.1.0" 32 | thiserror = "2.0" 33 | 34 | [dev-dependencies] 35 | spl-associated-token-account-mollusk-harness = { version = "1.0.0", path = "../mollusk_harness" } 36 | mollusk-svm = { version = "0.7.2" } 37 | solana-keypair = "3.1" 38 | solana-signer = "3.0" 39 | 40 | [lib] 41 | crate-type = ["cdylib", "lib"] 42 | 43 | [package.metadata.docs.rs] 44 | targets = ["x86_64-unknown-linux-gnu"] 45 | -------------------------------------------------------------------------------- /SECURITY.md: -------------------------------------------------------------------------------- 1 | # Security Policy 2 | 3 | ## Reporting security problems 4 | 5 | **DO NOT CREATE A GITHUB ISSUE** to report a security problem. 6 | 7 | Instead please use this [Report a Vulnerability](https://github.com/solana-program/associated-token-account/security/advisories/new) link. 8 | Provide a helpful title and detailed description of the problem. 9 | 10 | If you haven't done so already, please **enable two-factor auth** in your GitHub account. 11 | 12 | Expect a response as fast as possible in the advisory, typically within 72 hours. 13 | 14 | -- 15 | 16 | If you do not receive a response in the advisory, send an email to 17 | with the full URL of the advisory you have created. DO NOT 18 | include attachments or provide detail sufficient for exploitation regarding the 19 | security issue in this email. **Only provide such details in the advisory**. 20 | 21 | If you do not receive a response from please followup with 22 | the team directly. You can do this in one of the `#Dev Tooling` channels of the 23 | [Solana Tech discord server](https://solana.com/discord), by pinging the admins 24 | in the channel and referencing the fact that you submitted a security problem. 25 | 26 | ## Security Bug Bounties 27 | 28 | The Solana Foundation offer bounties for critical security issues. Please 29 | see the [Agave Security Bug 30 | Bounties](https://github.com/anza-xyz/agave/security/policy#security-bug-bounties) 31 | for details on classes of bugs and payment amounts. 32 | 33 | ## Scope 34 | 35 | Only the `spl-associated-token-account` program is included in the bounty scope, 36 | at [program](https://github.com/solana-program/associated-token-account/tree/master/program). 37 | 38 | If you discover a critical security issue in an out-of-scope component, your finding 39 | may still be valuable. 40 | -------------------------------------------------------------------------------- /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: Main 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | env: 10 | SBPF_PROGRAM_PACKAGES: "['program']" 11 | RUST_PACKAGES: "['interface', 'program', 'mollusk_harness']" 12 | WASM_PACKAGES: "['interface', 'program']" 13 | 14 | jobs: 15 | set_env: 16 | name: Set variables to be used in strategy definitions in reusable workflow 17 | runs-on: ubuntu-latest 18 | outputs: 19 | SBPF_PROGRAM_PACKAGES: ${{ steps.compute.outputs.SBPF_PROGRAM_PACKAGES }} 20 | RUST_PACKAGES: ${{ steps.compute.outputs.RUST_PACKAGES }} 21 | WASM_PACKAGES: ${{ steps.compute.outputs.WASM_PACKAGES }} 22 | RUST_TOOLCHAIN_NIGHTLY: ${{ steps.compute.outputs.RUST_TOOLCHAIN_NIGHTLY }} 23 | SOLANA_CLI_VERSION: ${{ steps.compute.outputs.SOLANA_CLI_VERSION }} 24 | steps: 25 | - name: Git Checkout 26 | uses: actions/checkout@v4 27 | 28 | - name: Compute variables 29 | id: compute 30 | shell: bash 31 | run: | 32 | echo "SBPF_PROGRAM_PACKAGES=${{ env.SBPF_PROGRAM_PACKAGES }}" >> $GITHUB_OUTPUT 33 | echo "RUST_PACKAGES=${{ env.RUST_PACKAGES }}" >> $GITHUB_OUTPUT 34 | echo "WASM_PACKAGES=${{ env.WASM_PACKAGES }}" >> $GITHUB_OUTPUT 35 | echo "RUST_TOOLCHAIN_NIGHTLY=$(make rust-toolchain-nightly)" >> "$GITHUB_OUTPUT" 36 | echo "SOLANA_CLI_VERSION=$(make solana-cli-version)" >> "$GITHUB_OUTPUT" 37 | 38 | main: 39 | needs: set_env 40 | uses: solana-program/actions/.github/workflows/main.yml@main 41 | with: 42 | sbpf-program-packages: ${{ needs.set_env.outputs.SBPF_PROGRAM_PACKAGES }} 43 | rust-packages: ${{ needs.set_env.outputs.RUST_PACKAGES }} 44 | wasm-packages: ${{ needs.set_env.outputs.WASM_PACKAGES }} 45 | rustfmt-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }} 46 | clippy-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }} 47 | solana-cli-version: ${{ needs.set_env.outputs.SOLANA_CLI_VERSION }} 48 | -------------------------------------------------------------------------------- /scripts/cliff.toml: -------------------------------------------------------------------------------- 1 | # git-cliff configuration file 2 | # https://git-cliff.org/docs/configuration 3 | # 4 | # Lines starting with "#" are comments. 5 | # Configuration options are organized into tables and keys. 6 | # See documentation for more information on available options. 7 | 8 | [changelog] 9 | header = """ 10 | ## What's new 11 | """ 12 | # template for the changelog body 13 | # https://tera.netlify.app/docs 14 | body = """ 15 | {% for group, commits in commits | group_by(attribute="group") %}\ 16 | {% for commit in commits %} 17 | - {{ commit.message | upper_first | split(pat="\n") | first | trim }}\ 18 | {% if commit.remote.username %} by @{{ commit.remote.username }}{%- endif %}\ 19 | {% endfor %}\ 20 | {% endfor %} 21 | """ 22 | # remove the leading and trailing whitespace from the template 23 | trim = true 24 | footer = """ 25 | """ 26 | postprocessors = [ ] 27 | [git] 28 | # parse the commits based on https://www.conventionalcommits.org 29 | conventional_commits = true 30 | # filter out the commits that are not conventional 31 | filter_unconventional = false 32 | # process each line of a commit as an individual commit 33 | split_commits = false 34 | # regex for preprocessing the commit messages 35 | commit_preprocessors = [] 36 | # regex for parsing and grouping commits 37 | commit_parsers = [ 38 | { message = "^build\\(deps\\)", skip = true }, 39 | { message = "^build\\(deps-dev\\)", skip = true }, 40 | { message = "^ci", skip = true }, 41 | { body = ".*", group = "Changes" }, 42 | ] 43 | # protect breaking changes from being skipped due to matching a skipping commit_parser 44 | protect_breaking_commits = false 45 | # filter out the commits that are not matched by commit parsers 46 | filter_commits = false 47 | # glob pattern for matching git tags 48 | tag_pattern = "v[0-9]*" 49 | # regex for skipping tags 50 | skip_tags = "" 51 | # regex for ignoring tags 52 | ignore_tags = "" 53 | # sort the tags topologically 54 | topo_order = false 55 | # sort the commits inside sections by oldest/newest order 56 | sort_commits = "newest" 57 | # limit the number of commits included in the changelog. 58 | # limit_commits = 42 -------------------------------------------------------------------------------- /interface/src/address.rs: -------------------------------------------------------------------------------- 1 | //! Address derivation functions 2 | 3 | use solana_pubkey::Pubkey; 4 | 5 | /// Derives the associated token account address and bump seed 6 | /// for the given wallet address, token mint and token program id 7 | pub fn get_associated_token_address_and_bump_seed( 8 | wallet_address: &Pubkey, 9 | token_mint_address: &Pubkey, 10 | program_id: &Pubkey, 11 | token_program_id: &Pubkey, 12 | ) -> (Pubkey, u8) { 13 | get_associated_token_address_and_bump_seed_internal( 14 | wallet_address, 15 | token_mint_address, 16 | program_id, 17 | token_program_id, 18 | ) 19 | } 20 | 21 | mod inline_spl_token { 22 | solana_pubkey::declare_id!("TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"); 23 | } 24 | 25 | /// Derives the associated token account address for the given wallet address 26 | /// and token mint 27 | pub fn get_associated_token_address( 28 | wallet_address: &Pubkey, 29 | token_mint_address: &Pubkey, 30 | ) -> Pubkey { 31 | get_associated_token_address_with_program_id( 32 | wallet_address, 33 | token_mint_address, 34 | &inline_spl_token::ID, 35 | ) 36 | } 37 | 38 | /// Derives the associated token account address for the given wallet address, 39 | /// token mint and token program id 40 | pub fn get_associated_token_address_with_program_id( 41 | wallet_address: &Pubkey, 42 | token_mint_address: &Pubkey, 43 | token_program_id: &Pubkey, 44 | ) -> Pubkey { 45 | get_associated_token_address_and_bump_seed( 46 | wallet_address, 47 | token_mint_address, 48 | &crate::program::id(), 49 | token_program_id, 50 | ) 51 | .0 52 | } 53 | 54 | /// For internal use only. 55 | #[doc(hidden)] 56 | pub fn get_associated_token_address_and_bump_seed_internal( 57 | wallet_address: &Pubkey, 58 | token_mint_address: &Pubkey, 59 | program_id: &Pubkey, 60 | token_program_id: &Pubkey, 61 | ) -> (Pubkey, u8) { 62 | Pubkey::find_program_address( 63 | &[ 64 | &wallet_address.to_bytes(), 65 | &token_program_id.to_bytes(), 66 | &token_mint_address.to_bytes(), 67 | ], 68 | program_id, 69 | ) 70 | } 71 | -------------------------------------------------------------------------------- /program/src/lib.rs: -------------------------------------------------------------------------------- 1 | //! Convention for associating token accounts with a user wallet 2 | #![deny(missing_docs)] 3 | #![forbid(unsafe_code)] 4 | 5 | mod entrypoint; 6 | pub mod error; 7 | pub mod instruction; 8 | pub mod processor; 9 | pub mod tools; 10 | 11 | #[deprecated( 12 | since = "4.1.0", 13 | note = "Use `spl_associated_token_account_interface::address` instead and remove `spl_associated_token_account` as a dependency" 14 | )] 15 | pub use spl_associated_token_account_interface::address::{ 16 | get_associated_token_address, get_associated_token_address_with_program_id, 17 | }; 18 | use { 19 | solana_instruction::{AccountMeta, Instruction}, 20 | solana_pubkey::Pubkey, 21 | }; 22 | // Export current SDK types for downstream users building with a different SDK 23 | // version 24 | pub use spl_associated_token_account_interface::program::{check_id, id, ID}; 25 | 26 | /// Create an associated token account for the given wallet address and token 27 | /// mint 28 | /// 29 | /// Accounts expected by this instruction: 30 | /// 31 | /// 0. `[writeable,signer]` Funding account (must be a system account) 32 | /// 1. `[writeable]` Associated token account address to be created 33 | /// 2. `[]` Wallet address for the new associated token account 34 | /// 3. `[]` The token mint for the new associated token account 35 | /// 4. `[]` System program 36 | /// 5. `[]` SPL Token program 37 | #[deprecated( 38 | since = "1.0.5", 39 | note = "please use `instruction::create_associated_token_account` instead" 40 | )] 41 | pub fn create_associated_token_account( 42 | funding_address: &Pubkey, 43 | wallet_address: &Pubkey, 44 | token_mint_address: &Pubkey, 45 | ) -> Instruction { 46 | let associated_account_address = 47 | get_associated_token_address(wallet_address, token_mint_address); 48 | 49 | Instruction { 50 | program_id: id(), 51 | accounts: vec![ 52 | AccountMeta::new(*funding_address, true), 53 | AccountMeta::new(associated_account_address, false), 54 | AccountMeta::new_readonly(*wallet_address, false), 55 | AccountMeta::new_readonly(*token_mint_address, false), 56 | AccountMeta::new_readonly(solana_system_interface::program::id(), false), 57 | AccountMeta::new_readonly(spl_token_interface::id(), false), 58 | AccountMeta::new_readonly(solana_sdk_ids::sysvar::rent::id(), false), 59 | ], 60 | data: vec![], 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /.github/workflows/publish-rust.yml: -------------------------------------------------------------------------------- 1 | name: Publish Rust Crate 2 | 3 | on: 4 | workflow_dispatch: 5 | inputs: 6 | package-path: 7 | description: Path to directory with package to release 8 | required: true 9 | default: 'interface' 10 | type: choice 11 | options: 12 | - interface 13 | - program 14 | level: 15 | description: Level 16 | required: true 17 | default: patch 18 | type: choice 19 | options: 20 | - patch 21 | - minor 22 | - major 23 | - rc 24 | - beta 25 | - alpha 26 | - release 27 | - version 28 | version: 29 | description: Version (used with level "version") 30 | required: false 31 | type: string 32 | dry-run: 33 | description: Dry run 34 | required: true 35 | default: true 36 | type: boolean 37 | create-release: 38 | description: Create a GitHub release 39 | required: true 40 | type: boolean 41 | default: true 42 | 43 | jobs: 44 | set_env: 45 | name: Set variables to be used in strategy definitions 46 | runs-on: ubuntu-latest 47 | outputs: 48 | RUST_TOOLCHAIN_NIGHTLY: ${{ steps.compute.outputs.RUST_TOOLCHAIN_NIGHTLY }} 49 | SOLANA_CLI_VERSION: ${{ steps.compute.outputs.SOLANA_CLI_VERSION }} 50 | TARGET: ${{ steps.compute.outputs.TARGET }} 51 | steps: 52 | - name: Git Checkout 53 | uses: actions/checkout@v4 54 | 55 | - name: Compute variables 56 | id: compute 57 | shell: bash 58 | run: | 59 | echo "RUST_TOOLCHAIN_NIGHTLY=$(make rust-toolchain-nightly)" >> "$GITHUB_OUTPUT" 60 | echo "SOLANA_CLI_VERSION=$(make solana-cli-version)" >> "$GITHUB_OUTPUT" 61 | TARGET=$(echo ${{ inputs.package-path }} | sed 's#/#-#') 62 | echo "TARGET=$TARGET" >> "$GITHUB_OUTPUT" 63 | 64 | main: 65 | needs: set_env 66 | uses: solana-program/actions/.github/workflows/publish-rust.yml@main 67 | with: 68 | sbpf-program-packages: "program" 69 | solana-cli-version: ${{ needs.set_env.outputs.SOLANA_CLI_VERSION }} 70 | clippy-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }} 71 | rustfmt-toolchain: ${{ needs.set_env.outputs.RUST_TOOLCHAIN_NIGHTLY }} 72 | target: ${{ needs.set_env.outputs.TARGET }} 73 | package-path: ${{ inputs.package-path }} 74 | level: ${{ inputs.level }} 75 | version: ${{ inputs.version }} 76 | create-release: ${{ inputs.create-release }} 77 | dry-run: ${{ inputs.dry-run }} 78 | secrets: inherit 79 | -------------------------------------------------------------------------------- /program/tests/extended_mint.rs: -------------------------------------------------------------------------------- 1 | use { 2 | mollusk_svm::result::Check, 3 | solana_program_error::ProgramError, 4 | spl_associated_token_account_mollusk_harness::AtaTestHarness, 5 | spl_token_2022_interface::{ 6 | extension::{ 7 | transfer_fee, BaseStateWithExtensions, ExtensionType, StateWithExtensionsOwned, 8 | }, 9 | state::Account, 10 | }, 11 | }; 12 | 13 | #[test] 14 | fn test_associated_token_account_with_transfer_fees() { 15 | let maximum_fee = 100; 16 | let transfer_fee_basis_points = 1_000; 17 | let (harness, receiver_wallet) = AtaTestHarness::new(&spl_token_2022_interface::id()) 18 | .with_wallet(1_000_000) 19 | .with_additional_wallet(1_000_000); 20 | let mut harness = harness 21 | .with_mint_with_extensions(&[ExtensionType::TransferFeeConfig]) 22 | .initialize_transfer_fee(transfer_fee_basis_points, maximum_fee) 23 | .initialize_mint(0) 24 | .with_ata(); 25 | let (sender_pubkey, mint, sender_ata, receiver_ata) = ( 26 | harness.wallet.unwrap(), 27 | harness.mint.unwrap(), 28 | harness.ata_address.unwrap(), 29 | harness.create_ata_for_owner(receiver_wallet, 1_000_000), 30 | ); 31 | harness.mint_tokens(50 * maximum_fee); 32 | 33 | // Insufficient funds transfer 34 | harness.ctx.process_and_validate_instruction( 35 | &transfer_fee::instruction::transfer_checked_with_fee( 36 | &spl_token_2022_interface::id(), 37 | &sender_ata, 38 | &mint, 39 | &receiver_ata, 40 | &sender_pubkey, 41 | &[], 42 | 10_001, 43 | 0, 44 | maximum_fee, 45 | ) 46 | .unwrap(), 47 | &[Check::err(ProgramError::Custom( 48 | spl_token_2022_interface::error::TokenError::InsufficientFunds as u32, 49 | ))], 50 | ); 51 | 52 | // Successful transfer 53 | let (transfer_amount, fee) = (500, 50); 54 | harness.ctx.process_and_validate_instruction( 55 | &transfer_fee::instruction::transfer_checked_with_fee( 56 | &spl_token_2022_interface::id(), 57 | &sender_ata, 58 | &mint, 59 | &receiver_ata, 60 | &sender_pubkey, 61 | &[], 62 | transfer_amount, 63 | 0, 64 | fee, 65 | ) 66 | .unwrap(), 67 | &[Check::success()], 68 | ); 69 | 70 | // Verify final account states 71 | let sender_state = 72 | StateWithExtensionsOwned::::unpack(harness.get_account(sender_ata).data).unwrap(); 73 | assert_eq!(sender_state.base.amount, 50 * maximum_fee - transfer_amount); 74 | assert_eq!( 75 | sender_state 76 | .get_extension::() 77 | .unwrap() 78 | .withheld_amount, 79 | 0.into() 80 | ); 81 | 82 | let receiver_state = 83 | StateWithExtensionsOwned::::unpack(harness.get_account(receiver_ata).data) 84 | .unwrap(); 85 | assert_eq!(receiver_state.base.amount, transfer_amount - fee); 86 | assert_eq!( 87 | receiver_state 88 | .get_extension::() 89 | .unwrap() 90 | .withheld_amount, 91 | fee.into() 92 | ); 93 | } 94 | -------------------------------------------------------------------------------- /program/src/tools/account.rs: -------------------------------------------------------------------------------- 1 | //! Account utility functions 2 | 3 | use { 4 | solana_account_info::AccountInfo, 5 | solana_cpi::{get_return_data, invoke, invoke_signed}, 6 | solana_program_error::{ProgramError, ProgramResult}, 7 | solana_pubkey::Pubkey, 8 | solana_rent::Rent, 9 | solana_system_interface::instruction as system_instruction, 10 | spl_token_2022_interface::extension::ExtensionType, 11 | std::convert::TryInto, 12 | }; 13 | 14 | /// Creates associated token account using Program Derived Address for the given 15 | /// seeds 16 | pub fn create_pda_account<'a>( 17 | payer: &AccountInfo<'a>, 18 | rent: &Rent, 19 | space: usize, 20 | owner: &Pubkey, 21 | system_program: &AccountInfo<'a>, 22 | new_pda_account: &AccountInfo<'a>, 23 | new_pda_signer_seeds: &[&[u8]], 24 | ) -> ProgramResult { 25 | if new_pda_account.lamports() > 0 { 26 | let required_lamports = rent 27 | .minimum_balance(space) 28 | .max(1) 29 | .saturating_sub(new_pda_account.lamports()); 30 | 31 | if required_lamports > 0 { 32 | invoke( 33 | &system_instruction::transfer(payer.key, new_pda_account.key, required_lamports), 34 | &[ 35 | payer.clone(), 36 | new_pda_account.clone(), 37 | system_program.clone(), 38 | ], 39 | )?; 40 | } 41 | 42 | invoke_signed( 43 | &system_instruction::allocate(new_pda_account.key, space as u64), 44 | &[new_pda_account.clone(), system_program.clone()], 45 | &[new_pda_signer_seeds], 46 | )?; 47 | 48 | invoke_signed( 49 | &system_instruction::assign(new_pda_account.key, owner), 50 | &[new_pda_account.clone(), system_program.clone()], 51 | &[new_pda_signer_seeds], 52 | ) 53 | } else { 54 | invoke_signed( 55 | &system_instruction::create_account( 56 | payer.key, 57 | new_pda_account.key, 58 | rent.minimum_balance(space).max(1), 59 | space as u64, 60 | owner, 61 | ), 62 | &[ 63 | payer.clone(), 64 | new_pda_account.clone(), 65 | system_program.clone(), 66 | ], 67 | &[new_pda_signer_seeds], 68 | ) 69 | } 70 | } 71 | 72 | /// Determines the required initial data length for a new token account based on 73 | /// the extensions initialized on the Mint 74 | pub fn get_account_len<'a>( 75 | mint: &AccountInfo<'a>, 76 | spl_token_program: &AccountInfo<'a>, 77 | extension_types: &[ExtensionType], 78 | ) -> Result { 79 | invoke( 80 | &spl_token_2022_interface::instruction::get_account_data_size( 81 | spl_token_program.key, 82 | mint.key, 83 | extension_types, 84 | )?, 85 | &[mint.clone(), spl_token_program.clone()], 86 | )?; 87 | get_return_data() 88 | .ok_or(ProgramError::InvalidInstructionData) 89 | .and_then(|(key, data)| { 90 | if key != *spl_token_program.key { 91 | return Err(ProgramError::IncorrectProgramId); 92 | } 93 | data.try_into() 94 | .map(usize::from_le_bytes) 95 | .map_err(|_| ProgramError::InvalidInstructionData) 96 | }) 97 | } 98 | -------------------------------------------------------------------------------- /program/tests/create_idempotent.rs: -------------------------------------------------------------------------------- 1 | use { 2 | mollusk_svm::result::Check, 3 | solana_program_error::ProgramError, 4 | solana_pubkey::Pubkey, 5 | spl_associated_token_account_mollusk_harness::{ 6 | build_create_ata_instruction, token_2022_immutable_owner_account_len, 7 | token_2022_immutable_owner_rent_exempt_balance, AtaTestHarness, CreateAtaInstructionType, 8 | }, 9 | }; 10 | 11 | #[test] 12 | fn success_account_exists() { 13 | let mut harness = 14 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 15 | // CreateIdempotent will create the ATA if it doesn't exist 16 | let ata_address = harness.create_ata(CreateAtaInstructionType::CreateIdempotent { bump: None }); 17 | let associated_account = harness 18 | .ctx 19 | .account_store 20 | .borrow() 21 | .get(&ata_address) 22 | .cloned() 23 | .unwrap(); 24 | 25 | // Failure case: try to Create when ATA already exists as token account 26 | harness 27 | .ctx 28 | .account_store 29 | .borrow_mut() 30 | .insert(ata_address, associated_account.clone()); 31 | let instruction = build_create_ata_instruction( 32 | spl_associated_token_account::id(), 33 | harness.payer, 34 | ata_address, 35 | harness.wallet.unwrap(), 36 | harness.mint.unwrap(), 37 | spl_token_2022_interface::id(), 38 | CreateAtaInstructionType::default(), 39 | ); 40 | harness 41 | .ctx 42 | .process_and_validate_instruction(&instruction, &[Check::err(ProgramError::IllegalOwner)]); 43 | 44 | // But CreateIdempotent should succeed when account exists 45 | let instruction = build_create_ata_instruction( 46 | spl_associated_token_account::id(), 47 | harness.payer, 48 | ata_address, 49 | harness.wallet.unwrap(), 50 | harness.mint.unwrap(), 51 | spl_token_2022_interface::id(), 52 | CreateAtaInstructionType::CreateIdempotent { bump: None }, 53 | ); 54 | harness.ctx.process_and_validate_instruction( 55 | &instruction, 56 | &[ 57 | Check::success(), 58 | Check::account(&ata_address) 59 | .space(token_2022_immutable_owner_account_len()) 60 | .owner(&spl_token_2022_interface::id()) 61 | .lamports(token_2022_immutable_owner_rent_exempt_balance()) 62 | .build(), 63 | ], 64 | ); 65 | } 66 | 67 | #[test] 68 | fn fail_account_exists_with_wrong_owner() { 69 | let harness = 70 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 71 | let wrong_owner = Pubkey::new_unique(); 72 | let ata_address = harness.insert_wrong_owner_token_account(wrong_owner); 73 | let instruction = build_create_ata_instruction( 74 | spl_associated_token_account::id(), 75 | harness.payer, 76 | ata_address, 77 | harness.wallet.unwrap(), 78 | harness.mint.unwrap(), 79 | spl_token_2022_interface::id(), 80 | CreateAtaInstructionType::CreateIdempotent { bump: None }, 81 | ); 82 | harness.ctx.process_and_validate_instruction( 83 | &instruction, 84 | &[Check::err(ProgramError::Custom( 85 | spl_associated_token_account::error::AssociatedTokenAccountError::InvalidOwner as u32, 86 | ))], 87 | ); 88 | } 89 | 90 | #[test] 91 | fn fail_non_ata() { 92 | let harness = 93 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 94 | let wrong_account = Pubkey::new_unique(); 95 | harness.execute_with_wrong_account_address(wrong_account, ProgramError::InvalidSeeds); 96 | } 97 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | RUST_TOOLCHAIN_NIGHTLY = nightly-2025-02-16 2 | SOLANA_CLI_VERSION = 3.0.0 3 | 4 | nightly = +${RUST_TOOLCHAIN_NIGHTLY} 5 | 6 | # This is a bit tricky -- findstring returns the found string, so we're looking 7 | # for "directory-", returning that, and replacing "-" with "/" to change the 8 | # first "-" to a "/". But if it isn't found, we replace "" with "", which works 9 | # in the case where there is no subdirectory. 10 | pattern-dir = $(firstword $(subst -, ,$1)) 11 | find-pattern-dir = $(findstring $(call pattern-dir,$1)-,$1) 12 | make-path = $(subst $(call find-pattern-dir,$1),$(subst -,/,$(call find-pattern-dir,$1)),$1) 13 | 14 | rust-toolchain-nightly: 15 | @echo ${RUST_TOOLCHAIN_NIGHTLY} 16 | 17 | solana-cli-version: 18 | @echo ${SOLANA_CLI_VERSION} 19 | 20 | cargo-nightly: 21 | cargo $(nightly) $(ARGS) 22 | 23 | generate-clients: 24 | @echo "No JavaScript clients to generate" 25 | 26 | audit: 27 | cargo audit \ 28 | --ignore RUSTSEC-2022-0093 \ 29 | --ignore RUSTSEC-2024-0344 \ 30 | --ignore RUSTSEC-2024-0376 $(ARGS) 31 | 32 | spellcheck: 33 | cargo spellcheck --code 1 $(ARGS) 34 | 35 | clippy-%: 36 | cargo $(nightly) clippy --manifest-path $(call make-path,$*)/Cargo.toml \ 37 | --all-targets \ 38 | --all-features \ 39 | -- \ 40 | --deny=warnings \ 41 | --deny=clippy::default_trait_access \ 42 | --deny=clippy::arithmetic_side_effects \ 43 | --deny=clippy::manual_let_else \ 44 | --deny=clippy::used_underscore_binding $(ARGS) 45 | 46 | format-check-%: 47 | cargo $(nightly) fmt --check --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 48 | 49 | powerset-%: 50 | cargo $(nightly) hack check --feature-powerset --all-targets --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 51 | 52 | semver-check-%: 53 | cargo semver-checks --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 54 | 55 | shellcheck: 56 | git ls-files -- '*.sh' | xargs shellcheck --color=always --external-sources --shell=bash $(ARGS) 57 | 58 | sort-check: 59 | cargo $(nightly) sort --workspace --check $(ARGS) 60 | 61 | bench-%: 62 | cargo $(nightly) bench --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 63 | 64 | regression-%: 65 | mollusk run-test --proto mollusk --ignore-compute-units $(call make-path,$*)/fuzz/program-mb.so ./target/deploy/$(subst -,_,$(shell toml get $(call make-path,$*)/Cargo.toml package.name)).so $(call make-path,$*)/fuzz/blob $(shell toml get $(call make-path,$*)/Cargo.toml package.metadata.solana.program-id) 66 | 67 | format-rust: 68 | cargo $(nightly) fmt --all $(ARGS) 69 | 70 | build-sbf-%: 71 | cargo build-sbf --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 72 | 73 | build-wasm-%: 74 | cargo build --target wasm32-unknown-unknown --manifest-path $(call make-path,$*)/Cargo.toml --all-features $(ARGS) 75 | 76 | build-doc-%: 77 | RUSTDOCFLAGS="--cfg docsrs -D warnings" cargo $(nightly) doc --all-features --no-deps --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 78 | 79 | test-doc-%: 80 | cargo $(nightly) test --doc --all-features --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 81 | 82 | test-%: 83 | SBF_OUT_DIR=$(PWD)/target/deploy cargo $(nightly) test --manifest-path $(call make-path,$*)/Cargo.toml $(ARGS) 84 | 85 | # Helpers for publishing 86 | tag-name = $(lastword $(subst /, ,$(call make-path,$1))) 87 | preid-arg = $(subst pre,--preid $2,$(findstring pre,$1)) 88 | package-version = $(subst ",,$(shell jq -r '.version' $(call make-path,$1)/package.json)) 89 | crate-version = $(subst ",,$(shell toml get $(call make-path,$1)/Cargo.toml package.version)) 90 | 91 | git-tag-rust-%: 92 | @echo "$(call tag-name,$*)@v$(call crate-version,$*)" 93 | 94 | publish-rust-%: 95 | cd "$(call make-path,$*)" && cargo release $(LEVEL) --tag-name "$(call tag-name,$*)@v{{version}}" --execute --no-confirm --dependent-version fix 96 | 97 | publish-rust-dry-run-%: 98 | cd "$(call make-path,$*)" && cargo release $(LEVEL) --tag-name "$(call tag-name,$*)@v{{version}}" -------------------------------------------------------------------------------- /program/tests/process_create_associated_token_account.rs: -------------------------------------------------------------------------------- 1 | use { 2 | mollusk_svm::result::Check, 3 | solana_instruction::AccountMeta, 4 | solana_program_error::ProgramError, 5 | solana_pubkey::Pubkey, 6 | solana_sysvar as sysvar, 7 | spl_associated_token_account_interface::address::get_associated_token_address_with_program_id, 8 | spl_associated_token_account_mollusk_harness::{ 9 | build_create_ata_instruction, token_2022_immutable_owner_rent_exempt_balance, 10 | AtaTestHarness, CreateAtaInstructionType, 11 | }, 12 | }; 13 | 14 | #[test] 15 | fn test_associated_token_address() { 16 | let mut harness = 17 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 18 | harness.create_ata(CreateAtaInstructionType::default()); 19 | } 20 | 21 | #[test] 22 | fn test_create_with_fewer_lamports() { 23 | let harness = 24 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 25 | 26 | let wallet = harness.wallet.unwrap(); 27 | let mint = harness.mint.unwrap(); 28 | let ata_address = get_associated_token_address_with_program_id( 29 | &wallet, 30 | &mint, 31 | &spl_token_2022_interface::id(), 32 | ); 33 | 34 | let insufficient_lamports = 890880; 35 | harness.ensure_account_exists_with_lamports(ata_address, insufficient_lamports); 36 | 37 | let instruction = build_create_ata_instruction( 38 | spl_associated_token_account_interface::program::id(), 39 | harness.payer, 40 | ata_address, 41 | wallet, 42 | mint, 43 | spl_token_2022_interface::id(), 44 | CreateAtaInstructionType::default(), 45 | ); 46 | 47 | harness.ctx.process_and_validate_instruction( 48 | &instruction, 49 | &[ 50 | Check::success(), 51 | Check::account(&ata_address) 52 | .lamports(token_2022_immutable_owner_rent_exempt_balance()) 53 | .owner(&spl_token_2022_interface::id()) 54 | .build(), 55 | ], 56 | ); 57 | } 58 | 59 | #[test] 60 | fn test_create_with_excess_lamports() { 61 | let harness = 62 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 63 | 64 | let wallet = harness.wallet.unwrap(); 65 | let mint = harness.mint.unwrap(); 66 | let ata_address = get_associated_token_address_with_program_id( 67 | &wallet, 68 | &mint, 69 | &spl_token_2022_interface::id(), 70 | ); 71 | 72 | let excess_lamports = token_2022_immutable_owner_rent_exempt_balance() + 1; 73 | harness.ensure_account_exists_with_lamports(ata_address, excess_lamports); 74 | 75 | let instruction = build_create_ata_instruction( 76 | spl_associated_token_account_interface::program::id(), 77 | harness.payer, 78 | ata_address, 79 | wallet, 80 | mint, 81 | spl_token_2022_interface::id(), 82 | CreateAtaInstructionType::default(), 83 | ); 84 | 85 | harness.ctx.process_and_validate_instruction( 86 | &instruction, 87 | &[ 88 | Check::success(), 89 | Check::account(&ata_address) 90 | .lamports(excess_lamports) 91 | .owner(&spl_token_2022_interface::id()) 92 | .build(), 93 | ], 94 | ); 95 | } 96 | 97 | #[test] 98 | fn test_create_account_mismatch() { 99 | let harness = 100 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 101 | 102 | let wallet = harness.wallet.unwrap(); 103 | let mint = harness.mint.unwrap(); 104 | let ata_address = get_associated_token_address_with_program_id( 105 | &wallet, 106 | &mint, 107 | &spl_token_2022_interface::id(), 108 | ); 109 | 110 | for account_idx in [1, 2, 3] { 111 | let mut instruction = build_create_ata_instruction( 112 | spl_associated_token_account_interface::program::id(), 113 | harness.payer, 114 | ata_address, 115 | wallet, 116 | mint, 117 | spl_token_2022_interface::id(), 118 | CreateAtaInstructionType::default(), 119 | ); 120 | 121 | instruction.accounts[account_idx] = if account_idx == 1 { 122 | AccountMeta::new(Pubkey::default(), false) 123 | } else { 124 | AccountMeta::new_readonly(Pubkey::default(), false) 125 | }; 126 | 127 | harness.ctx.process_and_validate_instruction( 128 | &instruction, 129 | &[Check::err(ProgramError::InvalidSeeds)], 130 | ); 131 | } 132 | } 133 | 134 | #[test] 135 | fn test_create_associated_token_account_using_legacy_implicit_instruction() { 136 | let mut harness = 137 | AtaTestHarness::new(&spl_token_2022_interface::id()).with_wallet_and_mint(1_000_000, 6); 138 | 139 | harness.create_and_check_ata_with_custom_instruction( 140 | CreateAtaInstructionType::default(), 141 | |instruction| { 142 | instruction.data = vec![]; 143 | instruction 144 | .accounts 145 | .push(AccountMeta::new_readonly(sysvar::rent::id(), false)); 146 | }, 147 | ); 148 | } 149 | -------------------------------------------------------------------------------- /interface/src/instruction.rs: -------------------------------------------------------------------------------- 1 | //! Instruction creators for the program 2 | use { 3 | crate::{address::get_associated_token_address_with_program_id, program::id}, 4 | solana_instruction::{AccountMeta, Instruction}, 5 | solana_pubkey::Pubkey, 6 | }; 7 | 8 | const SYSTEM_PROGRAM_ID: Pubkey = Pubkey::from_str_const("11111111111111111111111111111111"); 9 | 10 | #[cfg(feature = "borsh")] 11 | use borsh::{BorshDeserialize, BorshSchema, BorshSerialize}; 12 | 13 | /// Instructions supported by the `AssociatedTokenAccount` program 14 | #[derive(Clone, Debug, PartialEq)] 15 | #[cfg_attr( 16 | feature = "borsh", 17 | derive(BorshDeserialize, BorshSerialize, BorshSchema) 18 | )] 19 | pub enum AssociatedTokenAccountInstruction { 20 | /// Creates an associated token account for the given wallet address and 21 | /// token mint Returns an error if the account exists. 22 | /// 23 | /// 0. `[writeable,signer]` Funding account (must be a system account) 24 | /// 1. `[writeable]` Associated token account address to be created 25 | /// 2. `[]` Wallet address for the new associated token account 26 | /// 3. `[]` The token mint for the new associated token account 27 | /// 4. `[]` System program 28 | /// 5. `[]` SPL Token program 29 | Create, 30 | /// Creates an associated token account for the given wallet address and 31 | /// token mint, if it doesn't already exist. Returns an error if the 32 | /// account exists, but with a different owner. 33 | /// 34 | /// 0. `[writeable,signer]` Funding account (must be a system account) 35 | /// 1. `[writeable]` Associated token account address to be created 36 | /// 2. `[]` Wallet address for the new associated token account 37 | /// 3. `[]` The token mint for the new associated token account 38 | /// 4. `[]` System program 39 | /// 5. `[]` SPL Token program 40 | CreateIdempotent, 41 | /// Transfers from and closes a nested associated token account: an 42 | /// associated token account owned by an associated token account. 43 | /// 44 | /// The tokens are moved from the nested associated token account to the 45 | /// wallet's associated token account, and the nested account lamports are 46 | /// moved to the wallet. 47 | /// 48 | /// Note: Nested token accounts are an anti-pattern, and almost always 49 | /// created unintentionally, so this instruction should only be used to 50 | /// recover from errors. 51 | /// 52 | /// 0. `[writeable]` Nested associated token account, must be owned by `3` 53 | /// 1. `[]` Token mint for the nested associated token account 54 | /// 2. `[writeable]` Wallet's associated token account 55 | /// 3. `[]` Owner associated token account address, must be owned by `5` 56 | /// 4. `[]` Token mint for the owner associated token account 57 | /// 5. `[writeable, signer]` Wallet address for the owner associated token 58 | /// account 59 | /// 6. `[]` SPL Token program 60 | RecoverNested, 61 | } 62 | 63 | fn build_associated_token_account_instruction( 64 | funding_address: &Pubkey, 65 | wallet_address: &Pubkey, 66 | token_mint_address: &Pubkey, 67 | token_program_id: &Pubkey, 68 | instruction: u8, 69 | ) -> Instruction { 70 | let associated_account_address = get_associated_token_address_with_program_id( 71 | wallet_address, 72 | token_mint_address, 73 | token_program_id, 74 | ); 75 | // safety check, assert if not a creation instruction, which is only 0 or 1 76 | assert!(instruction <= 1); 77 | Instruction { 78 | program_id: id(), 79 | accounts: vec![ 80 | AccountMeta::new(*funding_address, true), 81 | AccountMeta::new(associated_account_address, false), 82 | AccountMeta::new_readonly(*wallet_address, false), 83 | AccountMeta::new_readonly(*token_mint_address, false), 84 | AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false), 85 | AccountMeta::new_readonly(*token_program_id, false), 86 | ], 87 | data: vec![instruction], 88 | } 89 | } 90 | 91 | /// Creates `Create` instruction 92 | pub fn create_associated_token_account( 93 | funding_address: &Pubkey, 94 | wallet_address: &Pubkey, 95 | token_mint_address: &Pubkey, 96 | token_program_id: &Pubkey, 97 | ) -> Instruction { 98 | build_associated_token_account_instruction( 99 | funding_address, 100 | wallet_address, 101 | token_mint_address, 102 | token_program_id, 103 | 0, // AssociatedTokenAccountInstruction::Create 104 | ) 105 | } 106 | 107 | /// Creates `CreateIdempotent` instruction 108 | pub fn create_associated_token_account_idempotent( 109 | funding_address: &Pubkey, 110 | wallet_address: &Pubkey, 111 | token_mint_address: &Pubkey, 112 | token_program_id: &Pubkey, 113 | ) -> Instruction { 114 | build_associated_token_account_instruction( 115 | funding_address, 116 | wallet_address, 117 | token_mint_address, 118 | token_program_id, 119 | 1, // AssociatedTokenAccountInstruction::CreateIdempotent 120 | ) 121 | } 122 | 123 | /// Creates a `RecoverNested` instruction 124 | pub fn recover_nested( 125 | wallet_address: &Pubkey, 126 | owner_token_mint_address: &Pubkey, 127 | nested_token_mint_address: &Pubkey, 128 | token_program_id: &Pubkey, 129 | ) -> Instruction { 130 | let owner_associated_account_address = get_associated_token_address_with_program_id( 131 | wallet_address, 132 | owner_token_mint_address, 133 | token_program_id, 134 | ); 135 | let destination_associated_account_address = get_associated_token_address_with_program_id( 136 | wallet_address, 137 | nested_token_mint_address, 138 | token_program_id, 139 | ); 140 | let nested_associated_account_address = get_associated_token_address_with_program_id( 141 | &owner_associated_account_address, // ATA is wrongly used as a wallet_address 142 | nested_token_mint_address, 143 | token_program_id, 144 | ); 145 | 146 | Instruction { 147 | program_id: id(), 148 | accounts: vec![ 149 | AccountMeta::new(nested_associated_account_address, false), 150 | AccountMeta::new_readonly(*nested_token_mint_address, false), 151 | AccountMeta::new(destination_associated_account_address, false), 152 | AccountMeta::new_readonly(owner_associated_account_address, false), 153 | AccountMeta::new_readonly(*owner_token_mint_address, false), 154 | AccountMeta::new(*wallet_address, true), 155 | AccountMeta::new_readonly(*token_program_id, false), 156 | ], 157 | data: vec![2], // AssociatedTokenAccountInstruction::RecoverNested 158 | } 159 | } 160 | 161 | #[cfg(test)] 162 | mod tests { 163 | use {super::*, solana_sdk_ids::system_program}; 164 | 165 | #[test] 166 | fn system_program_id() { 167 | assert_eq!(system_program::id(), SYSTEM_PROGRAM_ID); 168 | } 169 | } 170 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /program/tests/recover_nested.rs: -------------------------------------------------------------------------------- 1 | use { 2 | mollusk_svm::result::Check, 3 | solana_instruction::AccountMeta, 4 | solana_program_error::ProgramError, 5 | solana_pubkey::Pubkey, 6 | spl_associated_token_account_interface::{ 7 | address::get_associated_token_address_with_program_id, instruction, 8 | }, 9 | spl_associated_token_account_mollusk_harness::AtaTestHarness, 10 | spl_token_2022_interface::extension::StateWithExtensionsOwned, 11 | }; 12 | 13 | const TEST_MINT_AMOUNT: u64 = 100; 14 | 15 | fn test_recover_nested_same_mint(program_id: &Pubkey) { 16 | let mut harness = AtaTestHarness::new(program_id) 17 | .with_wallet(1_000_000) 18 | .with_mint(0) 19 | .with_ata(); 20 | 21 | let mint = harness.mint.unwrap(); 22 | let owner_ata = harness.ata_address.unwrap(); 23 | 24 | // Create nested ATA and mint tokens to it (not to the main, canonical ATA) 25 | let nested_ata = harness.create_ata_for_owner(owner_ata, 1_000_000); 26 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 27 | 28 | // Capture pre-state for lamports transfer validation 29 | let wallet_pubkey = harness.wallet.unwrap(); 30 | let pre_wallet_lamports = { 31 | let store = harness.ctx.account_store.borrow(); 32 | store.get(&wallet_pubkey).unwrap().lamports 33 | }; 34 | let nested_lamports = harness.get_account(nested_ata).lamports; 35 | 36 | // Build and execute recover instruction 37 | let recover_instruction = harness.build_recover_nested_instruction(mint, mint); 38 | harness.ctx.process_and_validate_instruction( 39 | &recover_instruction, 40 | &[ 41 | Check::success(), 42 | // Wallet received nested account lamports 43 | Check::account(&wallet_pubkey) 44 | .lamports(pre_wallet_lamports.checked_add(nested_lamports).unwrap()) 45 | .build(), 46 | // Nested account has no lamports 47 | Check::account(&nested_ata).lamports(0).build(), 48 | // Nested account is closed 49 | Check::account(&nested_ata).closed().build(), 50 | ], 51 | ); 52 | 53 | // Validate the recovery worked - tokens should be in the destination ATA (owner_ata) 54 | let destination_account = harness.get_account(owner_ata); 55 | let destination_amount = 56 | StateWithExtensionsOwned::::unpack( 57 | destination_account.data, 58 | ) 59 | .unwrap() 60 | .base 61 | .amount; 62 | assert_eq!(destination_amount, TEST_MINT_AMOUNT); 63 | } 64 | 65 | fn test_fail_missing_wallet_signature(token_program_id: &Pubkey) { 66 | let mut harness = AtaTestHarness::new(token_program_id) 67 | .with_wallet(1_000_000) 68 | .with_mint(0) 69 | .with_ata(); 70 | 71 | let mint = harness.mint.unwrap(); 72 | let owner_ata = harness.ata_address.unwrap(); 73 | let nested_ata = harness.create_ata_for_owner(owner_ata, 1_000_000); 74 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 75 | 76 | let mut recover_instruction = harness.build_recover_nested_instruction(mint, mint); 77 | recover_instruction.accounts[5] = AccountMeta::new(harness.wallet.unwrap(), false); 78 | 79 | harness.ctx.process_and_validate_instruction( 80 | &recover_instruction, 81 | &[Check::err(ProgramError::MissingRequiredSignature)], 82 | ); 83 | } 84 | 85 | fn test_fail_wrong_signer(token_program_id: &Pubkey) { 86 | let mut harness = AtaTestHarness::new(token_program_id) 87 | .with_wallet(1_000_000) 88 | .with_mint(0) 89 | .with_ata(); 90 | 91 | let mint = harness.mint.unwrap(); 92 | let owner_ata = harness.ata_address.unwrap(); 93 | let nested_ata = harness.create_ata_for_owner(owner_ata, 1_000_000); 94 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 95 | 96 | let wrong_wallet = Pubkey::new_unique(); 97 | harness.create_ata_for_owner(wrong_wallet, 1_000_000); 98 | 99 | let recover_instruction = 100 | instruction::recover_nested(&wrong_wallet, &mint, &mint, token_program_id); 101 | 102 | harness.ctx.process_and_validate_instruction( 103 | &recover_instruction, 104 | &[Check::err(ProgramError::IllegalOwner)], 105 | ); 106 | } 107 | 108 | fn test_fail_not_nested(token_program_id: &Pubkey) { 109 | let mut harness = AtaTestHarness::new(token_program_id) 110 | .with_wallet(1_000_000) 111 | .with_mint(0) 112 | .with_ata(); 113 | 114 | let mint = harness.mint.unwrap(); 115 | let wrong_wallet = Pubkey::new_unique(); 116 | 117 | let nested_ata = harness.create_ata_for_owner(wrong_wallet, 0); 118 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 119 | 120 | let recover_instruction = harness.build_recover_nested_instruction(mint, mint); 121 | harness.ctx.process_and_validate_instruction( 122 | &recover_instruction, 123 | &[Check::err(ProgramError::IllegalOwner)], 124 | ); 125 | } 126 | 127 | fn test_fail_wrong_address_derivation_owner(token_program_id: &Pubkey) { 128 | let mut harness = AtaTestHarness::new(token_program_id) 129 | .with_wallet(1_000_000) 130 | .with_mint(0) 131 | .with_ata(); 132 | 133 | let mint = harness.mint.unwrap(); 134 | let owner_ata = harness.ata_address.unwrap(); 135 | let nested_ata = harness.create_ata_for_owner(owner_ata, 1_000_000); 136 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 137 | 138 | let mut recover_instruction = harness.build_recover_nested_instruction(mint, mint); 139 | let wrong_owner_address = Pubkey::new_unique(); 140 | recover_instruction.accounts[3] = AccountMeta::new_readonly(wrong_owner_address, false); 141 | 142 | harness.ensure_accounts_with_lamports(&[(wrong_owner_address, 1_000_000)]); 143 | 144 | harness.ctx.process_and_validate_instruction( 145 | &recover_instruction, 146 | &[Check::err(ProgramError::InvalidSeeds)], 147 | ); 148 | } 149 | 150 | #[test] 151 | fn success_same_mint_2022() { 152 | test_recover_nested_same_mint(&spl_token_2022_interface::id()); 153 | } 154 | 155 | #[test] 156 | fn success_same_mint() { 157 | test_recover_nested_same_mint(&spl_token_interface::id()); 158 | } 159 | 160 | fn test_recover_nested_different_mints(program_id: &Pubkey) { 161 | let harness = AtaTestHarness::new(program_id) 162 | .with_wallet(1_000_000) 163 | .with_mint(0) 164 | .with_ata(); 165 | 166 | let owner_mint = harness.mint.unwrap(); 167 | let owner_ata = harness.ata_address.unwrap(); 168 | 169 | // Create a second mint for the nested token 170 | let mut harness = harness.with_mint(0); 171 | let nested_mint = harness.mint.unwrap(); 172 | 173 | // Create nested ATA and mint tokens to it 174 | let nested_ata = harness.create_ata_for_owner(owner_ata, 1_000_000); 175 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 176 | 177 | // Create destination ATA for the nested token 178 | let destination_ata = harness.create_ata_for_owner(harness.wallet.unwrap(), 1_000_000); 179 | 180 | // Capture pre-state for lamports transfer validation 181 | let wallet_pubkey = harness.wallet.unwrap(); 182 | let pre_wallet_lamports = { 183 | let store = harness.ctx.account_store.borrow(); 184 | store.get(&wallet_pubkey).unwrap().lamports 185 | }; 186 | let nested_lamports = harness.get_account(nested_ata).lamports; 187 | 188 | // Build and execute recover instruction 189 | let recover_instruction = harness.build_recover_nested_instruction(owner_mint, nested_mint); 190 | harness.ctx.process_and_validate_instruction( 191 | &recover_instruction, 192 | &[ 193 | Check::success(), 194 | // Wallet received nested account lamports 195 | Check::account(&wallet_pubkey) 196 | .lamports(pre_wallet_lamports.checked_add(nested_lamports).unwrap()) 197 | .build(), 198 | // Nested account has no lamports 199 | Check::account(&nested_ata).lamports(0).build(), 200 | // Nested account is closed 201 | Check::account(&nested_ata).closed().build(), 202 | ], 203 | ); 204 | 205 | // Validate the recovery worked - tokens should be in the destination ATA 206 | let destination_account = harness.get_account(destination_ata); 207 | let destination_amount = 208 | StateWithExtensionsOwned::::unpack( 209 | destination_account.data, 210 | ) 211 | .unwrap() 212 | .base 213 | .amount; 214 | assert_eq!(destination_amount, TEST_MINT_AMOUNT); 215 | } 216 | 217 | #[test] 218 | fn success_different_mints() { 219 | test_recover_nested_different_mints(&spl_token_interface::id()); 220 | } 221 | 222 | #[test] 223 | fn success_different_mints_2022() { 224 | test_recover_nested_different_mints(&spl_token_2022_interface::id()); 225 | } 226 | 227 | #[test] 228 | fn fail_missing_wallet_signature_2022() { 229 | test_fail_missing_wallet_signature(&spl_token_2022_interface::id()); 230 | } 231 | 232 | #[test] 233 | fn fail_missing_wallet_signature() { 234 | test_fail_missing_wallet_signature(&spl_token_interface::id()); 235 | } 236 | 237 | #[test] 238 | fn fail_wrong_signer_2022() { 239 | test_fail_wrong_signer(&spl_token_2022_interface::id()); 240 | } 241 | 242 | #[test] 243 | fn fail_wrong_signer() { 244 | test_fail_wrong_signer(&spl_token_interface::id()); 245 | } 246 | 247 | #[test] 248 | fn fail_not_nested_2022() { 249 | test_fail_not_nested(&spl_token_2022_interface::id()); 250 | } 251 | 252 | #[test] 253 | fn fail_not_nested() { 254 | test_fail_not_nested(&spl_token_interface::id()); 255 | } 256 | #[test] 257 | fn fail_wrong_address_derivation_owner_2022() { 258 | test_fail_wrong_address_derivation_owner(&spl_token_2022_interface::id()); 259 | } 260 | 261 | #[test] 262 | fn fail_wrong_address_derivation_owner() { 263 | test_fail_wrong_address_derivation_owner(&spl_token_interface::id()); 264 | } 265 | 266 | #[test] 267 | fn fail_owner_account_does_not_exist() { 268 | let mut harness = AtaTestHarness::new(&spl_token_2022_interface::id()) 269 | .with_wallet(1_000_000) 270 | .with_mint(0); 271 | // Note: deliberately NOT calling .with_ata() - owner ATA should not exist 272 | 273 | let mint = harness.mint.unwrap(); 274 | let wallet_pubkey = harness.wallet.unwrap(); 275 | let owner_ata_address = get_associated_token_address_with_program_id( 276 | &wallet_pubkey, 277 | &mint, 278 | &spl_token_2022_interface::id(), 279 | ); 280 | 281 | // Create nested ATA using non-existent owner ATA address 282 | let nested_ata = harness.create_ata_for_owner(owner_ata_address, 0); 283 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 284 | 285 | let recover_instruction = instruction::recover_nested( 286 | &wallet_pubkey, 287 | &mint, 288 | &mint, 289 | &spl_token_2022_interface::id(), 290 | ); 291 | 292 | harness.ctx.process_and_validate_instruction( 293 | &recover_instruction, 294 | &[Check::err(ProgramError::IllegalOwner)], 295 | ); 296 | } 297 | 298 | #[test] 299 | fn fail_wrong_spl_token_program() { 300 | let mut harness = AtaTestHarness::new(&spl_token_2022_interface::id()) 301 | .with_wallet(1_000_000) 302 | .with_mint(0) 303 | .with_ata(); 304 | 305 | let mint = harness.mint.unwrap(); 306 | let owner_ata = harness.ata_address.unwrap(); 307 | let nested_ata = harness.create_ata_for_owner(owner_ata, 1_000_000); 308 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 309 | 310 | // Use wrong program in instruction 311 | let recover_instruction = instruction::recover_nested( 312 | &harness.wallet.unwrap(), 313 | &mint, 314 | &mint, 315 | &spl_token_interface::id(), // Wrong program ID 316 | ); 317 | 318 | harness.ctx.process_and_validate_instruction( 319 | &recover_instruction, 320 | &[Check::err(ProgramError::IllegalOwner)], 321 | ); 322 | } 323 | 324 | #[test] 325 | fn fail_destination_not_wallet_ata() { 326 | let mut harness = AtaTestHarness::new(&spl_token_2022_interface::id()) 327 | .with_wallet(1_000_000) 328 | .with_mint(0) 329 | .with_ata(); 330 | 331 | let mint = harness.mint.unwrap(); 332 | let owner_ata = harness.ata_address.unwrap(); 333 | let nested_ata = harness.create_ata_for_owner(owner_ata, 1_000_000); 334 | harness.mint_tokens_to(nested_ata, TEST_MINT_AMOUNT); 335 | 336 | // Create wrong destination ATA 337 | let wrong_wallet = Pubkey::new_unique(); 338 | let wrong_destination_ata = harness.create_ata_for_owner(wrong_wallet, 1_000_000); 339 | 340 | let mut recover_instruction = harness.build_recover_nested_instruction(mint, mint); 341 | recover_instruction.accounts[2] = AccountMeta::new(wrong_destination_ata, false); 342 | 343 | harness.ctx.process_and_validate_instruction( 344 | &recover_instruction, 345 | &[Check::err(ProgramError::InvalidSeeds)], 346 | ); 347 | } 348 | -------------------------------------------------------------------------------- /program/src/processor.rs: -------------------------------------------------------------------------------- 1 | //! Program state processor 2 | 3 | use { 4 | crate::{ 5 | error::AssociatedTokenAccountError, 6 | tools::account::{create_pda_account, get_account_len}, 7 | }, 8 | borsh::BorshDeserialize, 9 | solana_account_info::{next_account_info, AccountInfo}, 10 | solana_cpi::{invoke, invoke_signed}, 11 | solana_msg::msg, 12 | solana_program_error::{ProgramError, ProgramResult}, 13 | solana_pubkey::Pubkey, 14 | solana_rent::Rent, 15 | solana_system_interface::program as system_program, 16 | solana_sysvar::Sysvar, 17 | spl_associated_token_account_interface::{ 18 | address::get_associated_token_address_and_bump_seed_internal, 19 | instruction::AssociatedTokenAccountInstruction, 20 | }, 21 | spl_token_2022_interface::{ 22 | extension::{ExtensionType, StateWithExtensions}, 23 | state::{Account, Mint}, 24 | }, 25 | }; 26 | 27 | /// Specify when to create the associated token account 28 | #[derive(PartialEq)] 29 | enum CreateMode { 30 | /// Always try to create the associated token account 31 | Always, 32 | /// Only try to create the associated token account if non-existent 33 | Idempotent, 34 | } 35 | 36 | /// Instruction processor 37 | pub fn process_instruction( 38 | program_id: &Pubkey, 39 | accounts: &[AccountInfo], 40 | input: &[u8], 41 | ) -> ProgramResult { 42 | let instruction = if input.is_empty() { 43 | AssociatedTokenAccountInstruction::Create 44 | } else { 45 | AssociatedTokenAccountInstruction::try_from_slice(input) 46 | .map_err(|_| ProgramError::InvalidInstructionData)? 47 | }; 48 | 49 | msg!("{:?}", instruction); 50 | 51 | match instruction { 52 | AssociatedTokenAccountInstruction::Create => { 53 | process_create_associated_token_account(program_id, accounts, CreateMode::Always) 54 | } 55 | AssociatedTokenAccountInstruction::CreateIdempotent => { 56 | process_create_associated_token_account(program_id, accounts, CreateMode::Idempotent) 57 | } 58 | AssociatedTokenAccountInstruction::RecoverNested => { 59 | process_recover_nested(program_id, accounts) 60 | } 61 | } 62 | } 63 | 64 | /// Processes `CreateAssociatedTokenAccount` instruction 65 | fn process_create_associated_token_account( 66 | program_id: &Pubkey, 67 | accounts: &[AccountInfo], 68 | create_mode: CreateMode, 69 | ) -> ProgramResult { 70 | let account_info_iter = &mut accounts.iter(); 71 | 72 | let funder_info = next_account_info(account_info_iter)?; 73 | let associated_token_account_info = next_account_info(account_info_iter)?; 74 | let wallet_account_info = next_account_info(account_info_iter)?; 75 | let spl_token_mint_info = next_account_info(account_info_iter)?; 76 | let system_program_info = next_account_info(account_info_iter)?; 77 | let spl_token_program_info = next_account_info(account_info_iter)?; 78 | let spl_token_program_id = spl_token_program_info.key; 79 | 80 | let (associated_token_address, bump_seed) = get_associated_token_address_and_bump_seed_internal( 81 | wallet_account_info.key, 82 | spl_token_mint_info.key, 83 | program_id, 84 | spl_token_program_id, 85 | ); 86 | if associated_token_address != *associated_token_account_info.key { 87 | msg!("Error: Associated address does not match seed derivation"); 88 | return Err(ProgramError::InvalidSeeds); 89 | } 90 | 91 | if create_mode == CreateMode::Idempotent 92 | && associated_token_account_info.owner == spl_token_program_id 93 | { 94 | let ata_data = associated_token_account_info.data.borrow(); 95 | if let Ok(associated_token_account) = StateWithExtensions::::unpack(&ata_data) { 96 | if associated_token_account.base.owner != *wallet_account_info.key { 97 | let error = AssociatedTokenAccountError::InvalidOwner; 98 | msg!("{}", error); 99 | return Err(error.into()); 100 | } 101 | if associated_token_account.base.mint != *spl_token_mint_info.key { 102 | return Err(ProgramError::InvalidAccountData); 103 | } 104 | return Ok(()); 105 | } 106 | } 107 | if *associated_token_account_info.owner != system_program::id() { 108 | return Err(ProgramError::IllegalOwner); 109 | } 110 | 111 | let rent = Rent::get()?; 112 | 113 | let associated_token_account_signer_seeds: &[&[_]] = &[ 114 | &wallet_account_info.key.to_bytes(), 115 | &spl_token_program_id.to_bytes(), 116 | &spl_token_mint_info.key.to_bytes(), 117 | &[bump_seed], 118 | ]; 119 | 120 | let account_len = get_account_len( 121 | spl_token_mint_info, 122 | spl_token_program_info, 123 | &[ExtensionType::ImmutableOwner], 124 | )?; 125 | 126 | create_pda_account( 127 | funder_info, 128 | &rent, 129 | account_len, 130 | spl_token_program_id, 131 | system_program_info, 132 | associated_token_account_info, 133 | associated_token_account_signer_seeds, 134 | )?; 135 | 136 | msg!("Initialize the associated token account"); 137 | invoke( 138 | &spl_token_2022_interface::instruction::initialize_immutable_owner( 139 | spl_token_program_id, 140 | associated_token_account_info.key, 141 | )?, 142 | &[ 143 | associated_token_account_info.clone(), 144 | spl_token_program_info.clone(), 145 | ], 146 | )?; 147 | invoke( 148 | &spl_token_2022_interface::instruction::initialize_account3( 149 | spl_token_program_id, 150 | associated_token_account_info.key, 151 | spl_token_mint_info.key, 152 | wallet_account_info.key, 153 | )?, 154 | &[ 155 | associated_token_account_info.clone(), 156 | spl_token_mint_info.clone(), 157 | wallet_account_info.clone(), 158 | spl_token_program_info.clone(), 159 | ], 160 | ) 161 | } 162 | 163 | /// Processes `RecoverNested` instruction 164 | pub fn process_recover_nested(program_id: &Pubkey, accounts: &[AccountInfo]) -> ProgramResult { 165 | let account_info_iter = &mut accounts.iter(); 166 | 167 | let nested_associated_token_account_info = next_account_info(account_info_iter)?; 168 | let nested_token_mint_info = next_account_info(account_info_iter)?; 169 | let destination_associated_token_account_info = next_account_info(account_info_iter)?; 170 | let owner_associated_token_account_info = next_account_info(account_info_iter)?; 171 | let owner_token_mint_info = next_account_info(account_info_iter)?; 172 | let wallet_account_info = next_account_info(account_info_iter)?; 173 | let spl_token_program_info = next_account_info(account_info_iter)?; 174 | let spl_token_program_id = spl_token_program_info.key; 175 | 176 | // Check owner address derivation 177 | let (owner_associated_token_address, bump_seed) = 178 | get_associated_token_address_and_bump_seed_internal( 179 | wallet_account_info.key, 180 | owner_token_mint_info.key, 181 | program_id, 182 | spl_token_program_id, 183 | ); 184 | if owner_associated_token_address != *owner_associated_token_account_info.key { 185 | msg!("Error: Owner associated address does not match seed derivation"); 186 | return Err(ProgramError::InvalidSeeds); 187 | } 188 | 189 | // Check nested address derivation 190 | let (nested_associated_token_address, _) = get_associated_token_address_and_bump_seed_internal( 191 | owner_associated_token_account_info.key, 192 | nested_token_mint_info.key, 193 | program_id, 194 | spl_token_program_id, 195 | ); 196 | if nested_associated_token_address != *nested_associated_token_account_info.key { 197 | msg!("Error: Nested associated address does not match seed derivation"); 198 | return Err(ProgramError::InvalidSeeds); 199 | } 200 | 201 | // Check destination address derivation 202 | let (destination_associated_token_address, _) = 203 | get_associated_token_address_and_bump_seed_internal( 204 | wallet_account_info.key, 205 | nested_token_mint_info.key, 206 | program_id, 207 | spl_token_program_id, 208 | ); 209 | if destination_associated_token_address != *destination_associated_token_account_info.key { 210 | msg!("Error: Destination associated address does not match seed derivation"); 211 | return Err(ProgramError::InvalidSeeds); 212 | } 213 | 214 | if !wallet_account_info.is_signer { 215 | msg!("Wallet of the owner associated token account must sign"); 216 | return Err(ProgramError::MissingRequiredSignature); 217 | } 218 | 219 | if owner_token_mint_info.owner != spl_token_program_id { 220 | msg!("Owner mint not owned by provided token program"); 221 | return Err(ProgramError::IllegalOwner); 222 | } 223 | 224 | // Account data is dropped at the end of this, so the CPI can succeed 225 | // without a double-borrow 226 | let (amount, decimals) = { 227 | // Check owner associated token account data 228 | if owner_associated_token_account_info.owner != spl_token_program_id { 229 | msg!("Owner associated token account not owned by provided token program, recreate the owner associated token account first"); 230 | return Err(ProgramError::IllegalOwner); 231 | } 232 | let owner_account_data = owner_associated_token_account_info.data.borrow(); 233 | let owner_account = StateWithExtensions::::unpack(&owner_account_data)?; 234 | if owner_account.base.owner != *wallet_account_info.key { 235 | msg!("Owner associated token account not owned by provided wallet"); 236 | return Err(AssociatedTokenAccountError::InvalidOwner.into()); 237 | } 238 | 239 | // Check nested associated token account data 240 | if nested_associated_token_account_info.owner != spl_token_program_id { 241 | msg!("Nested associated token account not owned by provided token program"); 242 | return Err(ProgramError::IllegalOwner); 243 | } 244 | let nested_account_data = nested_associated_token_account_info.data.borrow(); 245 | let nested_account = StateWithExtensions::::unpack(&nested_account_data)?; 246 | if nested_account.base.owner != *owner_associated_token_account_info.key { 247 | msg!("Nested associated token account not owned by provided associated token account"); 248 | return Err(AssociatedTokenAccountError::InvalidOwner.into()); 249 | } 250 | let amount = nested_account.base.amount; 251 | 252 | // Check nested token mint data 253 | if nested_token_mint_info.owner != spl_token_program_id { 254 | msg!("Nested mint account not owned by provided token program"); 255 | return Err(ProgramError::IllegalOwner); 256 | } 257 | let nested_mint_data = nested_token_mint_info.data.borrow(); 258 | let nested_mint = StateWithExtensions::::unpack(&nested_mint_data)?; 259 | let decimals = nested_mint.base.decimals; 260 | (amount, decimals) 261 | }; 262 | 263 | // Transfer everything out 264 | let owner_associated_token_account_signer_seeds: &[&[_]] = &[ 265 | &wallet_account_info.key.to_bytes(), 266 | &spl_token_program_id.to_bytes(), 267 | &owner_token_mint_info.key.to_bytes(), 268 | &[bump_seed], 269 | ]; 270 | invoke_signed( 271 | &spl_token_2022_interface::instruction::transfer_checked( 272 | spl_token_program_id, 273 | nested_associated_token_account_info.key, 274 | nested_token_mint_info.key, 275 | destination_associated_token_account_info.key, 276 | owner_associated_token_account_info.key, 277 | &[], 278 | amount, 279 | decimals, 280 | )?, 281 | &[ 282 | nested_associated_token_account_info.clone(), 283 | nested_token_mint_info.clone(), 284 | destination_associated_token_account_info.clone(), 285 | owner_associated_token_account_info.clone(), 286 | spl_token_program_info.clone(), 287 | ], 288 | &[owner_associated_token_account_signer_seeds], 289 | )?; 290 | 291 | // Close the nested account so it's never used again 292 | invoke_signed( 293 | &spl_token_2022_interface::instruction::close_account( 294 | spl_token_program_id, 295 | nested_associated_token_account_info.key, 296 | wallet_account_info.key, 297 | owner_associated_token_account_info.key, 298 | &[], 299 | )?, 300 | &[ 301 | nested_associated_token_account_info.clone(), 302 | wallet_account_info.clone(), 303 | owner_associated_token_account_info.clone(), 304 | spl_token_program_info.clone(), 305 | ], 306 | &[owner_associated_token_account_signer_seeds], 307 | ) 308 | } 309 | -------------------------------------------------------------------------------- /mollusk_harness/src/lib.rs: -------------------------------------------------------------------------------- 1 | use { 2 | mollusk_svm::{program::loader_keys::LOADER_V3, result::Check, Mollusk, MolluskContext}, 3 | solana_account::Account, 4 | solana_instruction::{AccountMeta, Instruction}, 5 | solana_program_error::ProgramError, 6 | solana_program_option::COption, 7 | solana_program_pack::Pack, 8 | solana_pubkey::Pubkey, 9 | solana_rent::Rent, 10 | solana_system_interface::program as system_program, 11 | solana_sysvar::rent, 12 | spl_associated_token_account_interface::address::get_associated_token_address_with_program_id, 13 | spl_token_2022_interface::{extension::ExtensionType, state::Account as Token2022Account}, 14 | spl_token_interface::{state::Account as TokenAccount, state::AccountState, state::Mint}, 15 | std::{collections::HashMap, vec::Vec}, 16 | }; 17 | 18 | /// Setup mollusk with local ATA and token programs 19 | pub fn setup_mollusk_with_programs(token_program_id: &Pubkey) -> Mollusk { 20 | let ata_program_id = spl_associated_token_account_interface::program::id(); 21 | let mut mollusk = Mollusk::new(&ata_program_id, "spl_associated_token_account"); 22 | 23 | if *token_program_id == spl_token_2022_interface::id() { 24 | mollusk.add_program(token_program_id, "spl_token_2022", &LOADER_V3); 25 | } else { 26 | mollusk.add_program(token_program_id, "pinocchio_token_program", &LOADER_V3); 27 | } 28 | 29 | mollusk 30 | } 31 | 32 | /// The type of ATA creation instruction to build. 33 | #[derive(Debug)] 34 | pub enum CreateAtaInstructionType { 35 | /// The standard `Create` instruction, which can optionally include a bump seed and account length. 36 | Create { 37 | bump: Option, 38 | account_len: Option, 39 | }, 40 | /// The `CreateIdempotent` instruction, which can optionally include a bump seed. 41 | CreateIdempotent { bump: Option }, 42 | } 43 | 44 | impl Default for CreateAtaInstructionType { 45 | fn default() -> Self { 46 | Self::Create { 47 | bump: None, 48 | account_len: None, 49 | } 50 | } 51 | } 52 | 53 | /// Calculate the expected account length for a Token-2022 account with `ImmutableOwner` extension 54 | pub fn token_2022_immutable_owner_account_len() -> usize { 55 | ExtensionType::try_calculate_account_len::(&[ExtensionType::ImmutableOwner]) 56 | .expect("Failed to calculate Token-2022 account length") 57 | } 58 | 59 | /// Calculate the rent-exempt balance for a Token-2022 account with `ImmutableOwner` extension 60 | pub fn token_2022_immutable_owner_rent_exempt_balance() -> u64 { 61 | Rent::default().minimum_balance(token_2022_immutable_owner_account_len()) 62 | } 63 | 64 | /// Calculate the rent-exempt balance for a standard SPL token account 65 | pub fn token_account_rent_exempt_balance() -> u64 { 66 | Rent::default().minimum_balance(TokenAccount::LEN) 67 | } 68 | 69 | /// Test harness for ATA testing scenarios 70 | pub struct AtaTestHarness { 71 | pub ctx: MolluskContext>, 72 | pub token_program_id: Pubkey, 73 | pub payer: Pubkey, 74 | pub wallet: Option, 75 | pub mint: Option, 76 | pub mint_authority: Option, 77 | pub ata_address: Option, 78 | } 79 | 80 | impl AtaTestHarness { 81 | /// Ensure an account exists in the context store with the given lamports. 82 | /// If the account does not exist, it will be created as a system account. 83 | /// However, this can be called on a non-system account (to be used for 84 | /// example when testing accidental nested owners). 85 | pub fn ensure_account_exists_with_lamports(&self, address: Pubkey, lamports: u64) { 86 | let mut store = self.ctx.account_store.borrow_mut(); 87 | if let Some(existing) = store.get_mut(&address) { 88 | if existing.lamports < lamports { 89 | existing.lamports = lamports; 90 | } 91 | } else { 92 | store.insert(address, AccountBuilder::system_account(lamports)); 93 | } 94 | } 95 | 96 | /// Ensure multiple accounts exist in the context store with the provided lamports 97 | pub fn ensure_accounts_with_lamports(&self, entries: &[(Pubkey, u64)]) { 98 | for (address, lamports) in entries.iter().copied() { 99 | self.ensure_account_exists_with_lamports(address, lamports); 100 | } 101 | } 102 | 103 | /// Internal: create the mint account owned by the token program with given space 104 | fn create_mint_account(&mut self, mint_account: Pubkey, space: usize, mint_program_id: Pubkey) { 105 | let mint_rent = Rent::default().minimum_balance(space); 106 | let create_mint_ix = solana_system_interface::instruction::create_account( 107 | &self.payer, 108 | &mint_account, 109 | mint_rent, 110 | space as u64, 111 | &mint_program_id, 112 | ); 113 | 114 | self.ctx 115 | .process_and_validate_instruction(&create_mint_ix, &[Check::success()]); 116 | } 117 | 118 | /// Create a new test harness with the specified token program 119 | pub fn new(token_program_id: &Pubkey) -> Self { 120 | let mollusk = setup_mollusk_with_programs(token_program_id); 121 | let payer = Pubkey::new_unique(); 122 | let ctx = mollusk.with_context(HashMap::new()); 123 | 124 | let harness = Self { 125 | ctx, 126 | token_program_id: *token_program_id, 127 | payer, 128 | wallet: None, 129 | mint: None, 130 | mint_authority: None, 131 | ata_address: None, 132 | }; 133 | harness.ensure_account_exists_with_lamports(payer, 10_000_000_000); 134 | harness 135 | } 136 | 137 | /// Add a wallet with the specified lamports 138 | pub fn with_wallet(mut self, lamports: u64) -> Self { 139 | let wallet = Pubkey::new_unique(); 140 | self.ensure_accounts_with_lamports(&[(wallet, lamports)]); 141 | self.wallet = Some(wallet); 142 | self 143 | } 144 | 145 | /// Add an additional wallet (e.g. for sender/receiver scenarios) - returns harness and the new wallet 146 | pub fn with_additional_wallet(self, lamports: u64) -> (Self, Pubkey) { 147 | let additional_wallet = Pubkey::new_unique(); 148 | self.ensure_accounts_with_lamports(&[(additional_wallet, lamports)]); 149 | (self, additional_wallet) 150 | } 151 | 152 | /// Create and initialize a mint with the specified decimals 153 | pub fn with_mint(mut self, decimals: u8) -> Self { 154 | let [mint_authority, mint_account] = [Pubkey::new_unique(); 2]; 155 | 156 | self.create_mint_account(mint_account, Mint::LEN, self.token_program_id); 157 | 158 | self.mint = Some(mint_account); 159 | self.mint_authority = Some(mint_authority); 160 | self.initialize_mint(decimals) 161 | } 162 | 163 | /// Create and initialize a Token-2022 mint with specific extensions 164 | pub fn with_mint_with_extensions(mut self, extensions: &[ExtensionType]) -> Self { 165 | if self.token_program_id != spl_token_2022_interface::id() { 166 | panic!("with_mint_with_extensions() can only be used with Token-2022 program"); 167 | } 168 | 169 | let [mint_authority, mint_account] = [Pubkey::new_unique(); 2]; 170 | 171 | // Calculate space needed for extensions 172 | let space = 173 | ExtensionType::try_calculate_account_len::( 174 | extensions, 175 | ) 176 | .expect("Failed to calculate mint space with extensions"); 177 | 178 | self.create_mint_account(mint_account, space, spl_token_2022_interface::id()); 179 | 180 | self.mint = Some(mint_account); 181 | self.mint_authority = Some(mint_authority); 182 | self 183 | } 184 | 185 | /// Initialize transfer fee extension on the current mint (requires Token-2022 mint with `TransferFeeConfig` extension) 186 | pub fn initialize_transfer_fee(self, transfer_fee_basis_points: u16, maximum_fee: u64) -> Self { 187 | let mint = self.mint.expect("Mint must be set"); 188 | let mint_authority = self.mint_authority.expect("Mint authority must be set"); 189 | 190 | let init_fee_ix = spl_token_2022_interface::extension::transfer_fee::instruction::initialize_transfer_fee_config( 191 | &spl_token_2022_interface::id(), 192 | &mint, 193 | Some(&mint_authority), 194 | Some(&mint_authority), 195 | transfer_fee_basis_points, 196 | maximum_fee, 197 | ) 198 | .expect("Failed to create initialize_transfer_fee_config instruction"); 199 | 200 | self.ctx 201 | .process_and_validate_instruction(&init_fee_ix, &[Check::success()]); 202 | self 203 | } 204 | 205 | /// Initialize mint (must be called after extensions are initialized) 206 | pub fn initialize_mint(self, decimals: u8) -> Self { 207 | let mint = self.mint.expect("Mint must be set"); 208 | let mint_authority = self.mint_authority.expect("Mint authority must be set"); 209 | 210 | let init_mint_ix = spl_token_2022_interface::instruction::initialize_mint( 211 | &self.token_program_id, 212 | &mint, 213 | &mint_authority, 214 | Some(&mint_authority), 215 | decimals, 216 | ) 217 | .expect("Failed to create initialize_mint instruction"); 218 | 219 | self.ctx 220 | .process_and_validate_instruction(&init_mint_ix, &[Check::success()]); 221 | self 222 | } 223 | 224 | /// Create an ATA for the wallet and mint (requires wallet and mint to be set) 225 | pub fn with_ata(mut self) -> Self { 226 | let wallet = self.wallet.expect("Wallet must be set before creating ATA"); 227 | let mint = self.mint.expect("Mint must be set before creating ATA"); 228 | 229 | let ata_address = 230 | get_associated_token_address_with_program_id(&wallet, &mint, &self.token_program_id); 231 | 232 | let instruction = build_create_ata_instruction( 233 | spl_associated_token_account_interface::program::id(), 234 | self.payer, 235 | ata_address, 236 | wallet, 237 | mint, 238 | self.token_program_id, 239 | CreateAtaInstructionType::default(), 240 | ); 241 | 242 | self.ctx 243 | .process_and_validate_instruction(&instruction, &[Check::success()]); 244 | 245 | self.ata_address = Some(ata_address); 246 | self 247 | } 248 | 249 | /// Get a reference to an account by pubkey 250 | pub fn get_account(&self, pubkey: Pubkey) -> Account { 251 | self.ctx 252 | .account_store 253 | .borrow() 254 | .get(&pubkey) 255 | .expect("account not found") 256 | .clone() 257 | } 258 | 259 | /// Mint tokens to the ATA (requires `mint`, `mint_authority` and `ata_address` to be set) 260 | pub fn mint_tokens(&mut self, amount: u64) { 261 | let ata_address = self.ata_address.expect("ATA must be set"); 262 | self.mint_tokens_to(ata_address, amount); 263 | } 264 | 265 | /// Mint tokens to a specific address 266 | pub fn mint_tokens_to(&mut self, destination: Pubkey, amount: u64) { 267 | let mint = self.mint.expect("Mint must be set"); 268 | let mint_authority = self 269 | .mint_authority 270 | .as_ref() 271 | .expect("Mint authority must be set"); 272 | 273 | let mint_to_ix = spl_token_2022_interface::instruction::mint_to( 274 | &self.token_program_id, 275 | &mint, 276 | &destination, 277 | mint_authority, 278 | &[], 279 | amount, 280 | ) 281 | .unwrap(); 282 | 283 | self.ctx 284 | .process_and_validate_instruction(&mint_to_ix, &[Check::success()]); 285 | } 286 | 287 | /// Build a create ATA instruction for the current wallet and mint 288 | pub fn build_create_ata_instruction( 289 | &mut self, 290 | instruction_type: CreateAtaInstructionType, 291 | ) -> solana_instruction::Instruction { 292 | let wallet = self.wallet.expect("Wallet must be set"); 293 | let mint = self.mint.expect("Mint must be set"); 294 | let ata_address = 295 | get_associated_token_address_with_program_id(&wallet, &mint, &self.token_program_id); 296 | 297 | self.ata_address = Some(ata_address); 298 | 299 | build_create_ata_instruction( 300 | spl_associated_token_account_interface::program::id(), 301 | self.payer, 302 | ata_address, 303 | wallet, 304 | mint, 305 | self.token_program_id, 306 | instruction_type, 307 | ) 308 | } 309 | 310 | /// Create an ATA for any owner. Ensure the owner exists as a system account, 311 | /// creating it with the given lamports if it does not exist. 312 | pub fn create_ata_for_owner(&mut self, owner: Pubkey, owner_lamports: u64) -> Pubkey { 313 | let mint = self.mint.expect("Mint must be set"); 314 | self.ensure_accounts_with_lamports(&[(owner, owner_lamports)]); 315 | 316 | let ata_address = 317 | get_associated_token_address_with_program_id(&owner, &mint, &self.token_program_id); 318 | 319 | let instruction = build_create_ata_instruction( 320 | spl_associated_token_account_interface::program::id(), 321 | self.payer, 322 | ata_address, 323 | owner, 324 | mint, 325 | self.token_program_id, 326 | CreateAtaInstructionType::default(), 327 | ); 328 | 329 | self.ctx 330 | .process_and_validate_instruction(&instruction, &[Check::success()]); 331 | 332 | ata_address 333 | } 334 | 335 | /// Build a `recover_nested` instruction and ensure all required accounts exist 336 | pub fn build_recover_nested_instruction( 337 | &mut self, 338 | owner_mint: Pubkey, 339 | nested_mint: Pubkey, 340 | ) -> solana_instruction::Instruction { 341 | let wallet = self.wallet.as_ref().expect("Wallet must be set"); 342 | 343 | spl_associated_token_account_interface::instruction::recover_nested( 344 | wallet, 345 | &owner_mint, 346 | &nested_mint, 347 | &self.token_program_id, 348 | ) 349 | } 350 | 351 | /// Add a wallet and mint (convenience method) 352 | pub fn with_wallet_and_mint(self, wallet_lamports: u64, decimals: u8) -> Self { 353 | self.with_wallet(wallet_lamports).with_mint(decimals) 354 | } 355 | 356 | /// Build and execute a create ATA instruction 357 | pub fn create_ata(&mut self, instruction_type: CreateAtaInstructionType) -> Pubkey { 358 | let wallet = self.wallet.expect("Wallet must be set"); 359 | let mint = self.mint.expect("Mint must be set"); 360 | let ata_address = 361 | get_associated_token_address_with_program_id(&wallet, &mint, &self.token_program_id); 362 | 363 | let instruction = build_create_ata_instruction( 364 | spl_associated_token_account_interface::program::id(), 365 | self.payer, 366 | ata_address, 367 | wallet, 368 | mint, 369 | self.token_program_id, 370 | instruction_type, 371 | ); 372 | 373 | let expected_len = if self.token_program_id == spl_token_2022_interface::id() { 374 | token_2022_immutable_owner_account_len() 375 | } else { 376 | TokenAccount::LEN 377 | }; 378 | 379 | let expected_balance = if self.token_program_id == spl_token_2022_interface::id() { 380 | token_2022_immutable_owner_rent_exempt_balance() 381 | } else { 382 | token_account_rent_exempt_balance() 383 | }; 384 | 385 | self.ctx.process_and_validate_instruction( 386 | &instruction, 387 | &[ 388 | Check::success(), 389 | Check::account(&ata_address) 390 | .space(expected_len) 391 | .owner(&self.token_program_id) 392 | .lamports(expected_balance) 393 | .build(), 394 | ], 395 | ); 396 | 397 | self.ata_address = Some(ata_address); 398 | ata_address 399 | } 400 | 401 | /// Create a token account with wrong owner at the ATA address (for error testing) 402 | pub fn insert_wrong_owner_token_account(&self, wrong_owner: Pubkey) -> Pubkey { 403 | let wallet = self.wallet.as_ref().expect("Wallet must be set"); 404 | let mint = self.mint.expect("Mint must be set"); 405 | self.ensure_accounts_with_lamports(&[(wrong_owner, 1_000_000)]); 406 | let ata_address = 407 | get_associated_token_address_with_program_id(wallet, &mint, &self.token_program_id); 408 | // Create token account with wrong owner at the ATA address 409 | let wrong_account = 410 | AccountBuilder::token_account(&mint, &wrong_owner, 0, &self.token_program_id); 411 | self.ctx 412 | .account_store 413 | .borrow_mut() 414 | .insert(ata_address, wrong_account); 415 | ata_address 416 | } 417 | 418 | /// Execute an instruction with a modified account address (for testing non-ATA addresses) 419 | pub fn execute_with_wrong_account_address( 420 | &self, 421 | wrong_account: Pubkey, 422 | expected_error: ProgramError, 423 | ) { 424 | let wallet = self.wallet.expect("Wallet must be set"); 425 | let mint = self.mint.expect("Mint must be set"); 426 | 427 | // Create a token account at the wrong address 428 | self.ctx.account_store.borrow_mut().insert( 429 | wrong_account, 430 | AccountBuilder::token_account(&mint, &wallet, 0, &self.token_program_id), 431 | ); 432 | 433 | let mut instruction = build_create_ata_instruction( 434 | spl_associated_token_account_interface::program::id(), 435 | self.payer, 436 | get_associated_token_address_with_program_id(&wallet, &mint, &self.token_program_id), 437 | wallet, 438 | mint, 439 | self.token_program_id, 440 | CreateAtaInstructionType::CreateIdempotent { bump: None }, 441 | ); 442 | 443 | // Replace the ATA address with the wrong account address 444 | instruction.accounts[1] = AccountMeta::new(wrong_account, false); 445 | 446 | self.ctx 447 | .process_and_validate_instruction(&instruction, &[Check::err(expected_error)]); 448 | } 449 | 450 | /// Create ATA instruction with custom modifications (for special cases like legacy empty data) 451 | pub fn create_and_check_ata_with_custom_instruction( 452 | &mut self, 453 | instruction_type: CreateAtaInstructionType, 454 | modify_instruction: F, 455 | ) -> Pubkey 456 | where 457 | F: FnOnce(&mut solana_instruction::Instruction), 458 | { 459 | let wallet = self.wallet.expect("Wallet must be set"); 460 | let mint = self.mint.expect("Mint must be set"); 461 | let ata_address = 462 | get_associated_token_address_with_program_id(&wallet, &mint, &self.token_program_id); 463 | 464 | let mut instruction = build_create_ata_instruction( 465 | spl_associated_token_account_interface::program::id(), 466 | self.payer, 467 | ata_address, 468 | wallet, 469 | mint, 470 | self.token_program_id, 471 | instruction_type, 472 | ); 473 | 474 | // Apply custom modification 475 | modify_instruction(&mut instruction); 476 | 477 | let expected_len = if self.token_program_id == spl_token_2022_interface::id() { 478 | token_2022_immutable_owner_account_len() 479 | } else { 480 | TokenAccount::LEN 481 | }; 482 | 483 | let expected_balance = if self.token_program_id == spl_token_2022_interface::id() { 484 | token_2022_immutable_owner_rent_exempt_balance() 485 | } else { 486 | token_account_rent_exempt_balance() 487 | }; 488 | 489 | self.ctx.process_and_validate_instruction( 490 | &instruction, 491 | &[ 492 | Check::success(), 493 | Check::account(&ata_address) 494 | .space(expected_len) 495 | .owner(&self.token_program_id) 496 | .lamports(expected_balance) 497 | .build(), 498 | ], 499 | ); 500 | 501 | self.ata_address = Some(ata_address); 502 | ata_address 503 | } 504 | } 505 | 506 | /// Encodes the instruction data payload for ATA creation-related instructions. 507 | pub fn encode_create_ata_instruction_data(instruction_type: &CreateAtaInstructionType) -> Vec { 508 | match instruction_type { 509 | CreateAtaInstructionType::Create { bump, account_len } => { 510 | let mut data = vec![0]; // Discriminator for Create 511 | if let Some(b) = bump { 512 | data.push(*b); 513 | if let Some(len) = account_len { 514 | data.extend_from_slice(&len.to_le_bytes()); 515 | } 516 | } 517 | data 518 | } 519 | CreateAtaInstructionType::CreateIdempotent { bump } => { 520 | let mut data = vec![1]; // Discriminator for CreateIdempotent 521 | if let Some(b) = bump { 522 | data.push(*b); 523 | } 524 | data 525 | } 526 | } 527 | } 528 | 529 | /// Build a create associated token account instruction with a given discriminator 530 | pub fn build_create_ata_instruction( 531 | ata_program_id: Pubkey, 532 | payer: Pubkey, 533 | ata_address: Pubkey, 534 | wallet: Pubkey, 535 | mint: Pubkey, 536 | token_program: Pubkey, 537 | instruction_type: CreateAtaInstructionType, 538 | ) -> Instruction { 539 | Instruction { 540 | program_id: ata_program_id, 541 | accounts: vec![ 542 | AccountMeta::new(payer, true), 543 | AccountMeta::new(ata_address, false), 544 | AccountMeta::new_readonly(wallet, false), 545 | AccountMeta::new_readonly(mint, false), 546 | AccountMeta::new_readonly(system_program::id(), false), 547 | AccountMeta::new_readonly(token_program, false), 548 | AccountMeta::new_readonly(rent::id(), false), 549 | ], 550 | data: encode_create_ata_instruction_data(&instruction_type), 551 | } 552 | } 553 | 554 | pub struct AccountBuilder; 555 | 556 | impl AccountBuilder { 557 | pub fn system_account(lamports: u64) -> Account { 558 | Account { 559 | lamports, 560 | data: Vec::new(), 561 | owner: solana_system_interface::program::id(), 562 | executable: false, 563 | rent_epoch: 0, 564 | } 565 | } 566 | 567 | pub fn token_account( 568 | mint: &Pubkey, 569 | owner: &Pubkey, 570 | amount: u64, 571 | token_program: &Pubkey, 572 | ) -> Account { 573 | let account_data = TokenAccount { 574 | mint: *mint, 575 | owner: *owner, 576 | amount, 577 | delegate: COption::None, 578 | state: AccountState::Initialized, 579 | is_native: COption::None, 580 | delegated_amount: 0, 581 | close_authority: COption::None, 582 | }; 583 | 584 | if *token_program == spl_token_2022_interface::id() { 585 | mollusk_svm_programs_token::token2022::create_account_for_token_account(account_data) 586 | } else { 587 | mollusk_svm_programs_token::token::create_account_for_token_account(account_data) 588 | } 589 | } 590 | } 591 | -------------------------------------------------------------------------------- /Cargo.lock: -------------------------------------------------------------------------------- 1 | # This file is automatically @generated by Cargo. 2 | # It is not intended for manual editing. 3 | version = 4 4 | 5 | [[package]] 6 | name = "aead" 7 | version = "0.5.2" 8 | source = "registry+https://github.com/rust-lang/crates.io-index" 9 | checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" 10 | dependencies = [ 11 | "crypto-common", 12 | "generic-array", 13 | ] 14 | 15 | [[package]] 16 | name = "aes" 17 | version = "0.8.4" 18 | source = "registry+https://github.com/rust-lang/crates.io-index" 19 | checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" 20 | dependencies = [ 21 | "cfg-if", 22 | "cipher", 23 | "cpufeatures", 24 | ] 25 | 26 | [[package]] 27 | name = "aes-gcm-siv" 28 | version = "0.11.1" 29 | source = "registry+https://github.com/rust-lang/crates.io-index" 30 | checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" 31 | dependencies = [ 32 | "aead", 33 | "aes", 34 | "cipher", 35 | "ctr", 36 | "polyval", 37 | "subtle", 38 | "zeroize", 39 | ] 40 | 41 | [[package]] 42 | name = "agave-feature-set" 43 | version = "3.0.10" 44 | source = "registry+https://github.com/rust-lang/crates.io-index" 45 | checksum = "be80c9787c7f30819e2999987cc6208c1ec6f775d7ed2b70f61a00a6e8acc0c8" 46 | dependencies = [ 47 | "ahash", 48 | "solana-epoch-schedule", 49 | "solana-hash 3.1.0", 50 | "solana-pubkey 3.0.0", 51 | "solana-sha256-hasher", 52 | "solana-svm-feature-set", 53 | ] 54 | 55 | [[package]] 56 | name = "agave-syscalls" 57 | version = "3.0.10" 58 | source = "registry+https://github.com/rust-lang/crates.io-index" 59 | checksum = "a8605fba7ba3e97426ab19179d565a7cd9d6b5566ff49004784c99e302ac7953" 60 | dependencies = [ 61 | "bincode", 62 | "libsecp256k1", 63 | "num-traits", 64 | "solana-account", 65 | "solana-account-info", 66 | "solana-big-mod-exp", 67 | "solana-blake3-hasher", 68 | "solana-bn254", 69 | "solana-clock", 70 | "solana-cpi", 71 | "solana-curve25519 3.0.10", 72 | "solana-hash 3.1.0", 73 | "solana-instruction", 74 | "solana-keccak-hasher", 75 | "solana-loader-v3-interface", 76 | "solana-poseidon", 77 | "solana-program-entrypoint", 78 | "solana-program-runtime", 79 | "solana-pubkey 3.0.0", 80 | "solana-sbpf", 81 | "solana-sdk-ids", 82 | "solana-secp256k1-recover", 83 | "solana-sha256-hasher", 84 | "solana-stable-layout", 85 | "solana-stake-interface", 86 | "solana-svm-callback", 87 | "solana-svm-feature-set", 88 | "solana-svm-log-collector", 89 | "solana-svm-measure", 90 | "solana-svm-timings", 91 | "solana-svm-type-overrides", 92 | "solana-sysvar", 93 | "solana-sysvar-id", 94 | "solana-transaction-context", 95 | "thiserror 2.0.17", 96 | ] 97 | 98 | [[package]] 99 | name = "ahash" 100 | version = "0.8.12" 101 | source = "registry+https://github.com/rust-lang/crates.io-index" 102 | checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" 103 | dependencies = [ 104 | "cfg-if", 105 | "getrandom 0.3.3", 106 | "once_cell", 107 | "version_check", 108 | "zerocopy", 109 | ] 110 | 111 | [[package]] 112 | name = "aho-corasick" 113 | version = "1.1.3" 114 | source = "registry+https://github.com/rust-lang/crates.io-index" 115 | checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" 116 | dependencies = [ 117 | "memchr", 118 | ] 119 | 120 | [[package]] 121 | name = "anstream" 122 | version = "0.6.20" 123 | source = "registry+https://github.com/rust-lang/crates.io-index" 124 | checksum = "3ae563653d1938f79b1ab1b5e668c87c76a9930414574a6583a7b7e11a8e6192" 125 | dependencies = [ 126 | "anstyle", 127 | "anstyle-parse", 128 | "anstyle-query", 129 | "anstyle-wincon", 130 | "colorchoice", 131 | "is_terminal_polyfill", 132 | "utf8parse", 133 | ] 134 | 135 | [[package]] 136 | name = "anstyle" 137 | version = "1.0.11" 138 | source = "registry+https://github.com/rust-lang/crates.io-index" 139 | checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" 140 | 141 | [[package]] 142 | name = "anstyle-parse" 143 | version = "0.2.7" 144 | source = "registry+https://github.com/rust-lang/crates.io-index" 145 | checksum = "4e7644824f0aa2c7b9384579234ef10eb7efb6a0deb83f9630a49594dd9c15c2" 146 | dependencies = [ 147 | "utf8parse", 148 | ] 149 | 150 | [[package]] 151 | name = "anstyle-query" 152 | version = "1.1.4" 153 | source = "registry+https://github.com/rust-lang/crates.io-index" 154 | checksum = "9e231f6134f61b71076a3eab506c379d4f36122f2af15a9ff04415ea4c3339e2" 155 | dependencies = [ 156 | "windows-sys", 157 | ] 158 | 159 | [[package]] 160 | name = "anstyle-wincon" 161 | version = "3.0.10" 162 | source = "registry+https://github.com/rust-lang/crates.io-index" 163 | checksum = "3e0633414522a32ffaac8ac6cc8f748e090c5717661fddeea04219e2344f5f2a" 164 | dependencies = [ 165 | "anstyle", 166 | "once_cell_polyfill", 167 | "windows-sys", 168 | ] 169 | 170 | [[package]] 171 | name = "ark-bn254" 172 | version = "0.4.0" 173 | source = "registry+https://github.com/rust-lang/crates.io-index" 174 | checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" 175 | dependencies = [ 176 | "ark-ec", 177 | "ark-ff", 178 | "ark-std", 179 | ] 180 | 181 | [[package]] 182 | name = "ark-ec" 183 | version = "0.4.2" 184 | source = "registry+https://github.com/rust-lang/crates.io-index" 185 | checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" 186 | dependencies = [ 187 | "ark-ff", 188 | "ark-poly", 189 | "ark-serialize", 190 | "ark-std", 191 | "derivative", 192 | "hashbrown 0.13.2", 193 | "itertools 0.10.5", 194 | "num-traits", 195 | "zeroize", 196 | ] 197 | 198 | [[package]] 199 | name = "ark-ff" 200 | version = "0.4.2" 201 | source = "registry+https://github.com/rust-lang/crates.io-index" 202 | checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" 203 | dependencies = [ 204 | "ark-ff-asm", 205 | "ark-ff-macros", 206 | "ark-serialize", 207 | "ark-std", 208 | "derivative", 209 | "digest 0.10.7", 210 | "itertools 0.10.5", 211 | "num-bigint 0.4.6", 212 | "num-traits", 213 | "paste", 214 | "rustc_version", 215 | "zeroize", 216 | ] 217 | 218 | [[package]] 219 | name = "ark-ff-asm" 220 | version = "0.4.2" 221 | source = "registry+https://github.com/rust-lang/crates.io-index" 222 | checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" 223 | dependencies = [ 224 | "quote", 225 | "syn 1.0.109", 226 | ] 227 | 228 | [[package]] 229 | name = "ark-ff-macros" 230 | version = "0.4.2" 231 | source = "registry+https://github.com/rust-lang/crates.io-index" 232 | checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" 233 | dependencies = [ 234 | "num-bigint 0.4.6", 235 | "num-traits", 236 | "proc-macro2", 237 | "quote", 238 | "syn 1.0.109", 239 | ] 240 | 241 | [[package]] 242 | name = "ark-poly" 243 | version = "0.4.2" 244 | source = "registry+https://github.com/rust-lang/crates.io-index" 245 | checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" 246 | dependencies = [ 247 | "ark-ff", 248 | "ark-serialize", 249 | "ark-std", 250 | "derivative", 251 | "hashbrown 0.13.2", 252 | ] 253 | 254 | [[package]] 255 | name = "ark-serialize" 256 | version = "0.4.2" 257 | source = "registry+https://github.com/rust-lang/crates.io-index" 258 | checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" 259 | dependencies = [ 260 | "ark-serialize-derive", 261 | "ark-std", 262 | "digest 0.10.7", 263 | "num-bigint 0.4.6", 264 | ] 265 | 266 | [[package]] 267 | name = "ark-serialize-derive" 268 | version = "0.4.2" 269 | source = "registry+https://github.com/rust-lang/crates.io-index" 270 | checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" 271 | dependencies = [ 272 | "proc-macro2", 273 | "quote", 274 | "syn 1.0.109", 275 | ] 276 | 277 | [[package]] 278 | name = "ark-std" 279 | version = "0.4.0" 280 | source = "registry+https://github.com/rust-lang/crates.io-index" 281 | checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" 282 | dependencies = [ 283 | "num-traits", 284 | "rand 0.8.5", 285 | ] 286 | 287 | [[package]] 288 | name = "arrayref" 289 | version = "0.3.9" 290 | source = "registry+https://github.com/rust-lang/crates.io-index" 291 | checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" 292 | 293 | [[package]] 294 | name = "arrayvec" 295 | version = "0.7.6" 296 | source = "registry+https://github.com/rust-lang/crates.io-index" 297 | checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" 298 | 299 | [[package]] 300 | name = "ascii" 301 | version = "0.9.3" 302 | source = "registry+https://github.com/rust-lang/crates.io-index" 303 | checksum = "eab1c04a571841102f5345a8fc0f6bb3d31c315dec879b5c6e42e40ce7ffa34e" 304 | 305 | [[package]] 306 | name = "autocfg" 307 | version = "1.5.0" 308 | source = "registry+https://github.com/rust-lang/crates.io-index" 309 | checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" 310 | 311 | [[package]] 312 | name = "base16ct" 313 | version = "0.2.0" 314 | source = "registry+https://github.com/rust-lang/crates.io-index" 315 | checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" 316 | 317 | [[package]] 318 | name = "base64" 319 | version = "0.12.3" 320 | source = "registry+https://github.com/rust-lang/crates.io-index" 321 | checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" 322 | 323 | [[package]] 324 | name = "base64" 325 | version = "0.22.1" 326 | source = "registry+https://github.com/rust-lang/crates.io-index" 327 | checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" 328 | 329 | [[package]] 330 | name = "base64ct" 331 | version = "1.6.0" 332 | source = "registry+https://github.com/rust-lang/crates.io-index" 333 | checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" 334 | 335 | [[package]] 336 | name = "bincode" 337 | version = "1.3.3" 338 | source = "registry+https://github.com/rust-lang/crates.io-index" 339 | checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" 340 | dependencies = [ 341 | "serde", 342 | ] 343 | 344 | [[package]] 345 | name = "bitflags" 346 | version = "2.9.3" 347 | source = "registry+https://github.com/rust-lang/crates.io-index" 348 | checksum = "34efbcccd345379ca2868b2b2c9d3782e9cc58ba87bc7d79d5b53d9c9ae6f25d" 349 | 350 | [[package]] 351 | name = "blake3" 352 | version = "1.8.2" 353 | source = "registry+https://github.com/rust-lang/crates.io-index" 354 | checksum = "3888aaa89e4b2a40fca9848e400f6a658a5a3978de7be858e209cafa8be9a4a0" 355 | dependencies = [ 356 | "arrayref", 357 | "arrayvec", 358 | "cc", 359 | "cfg-if", 360 | "constant_time_eq", 361 | ] 362 | 363 | [[package]] 364 | name = "block-buffer" 365 | version = "0.9.0" 366 | source = "registry+https://github.com/rust-lang/crates.io-index" 367 | checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" 368 | dependencies = [ 369 | "generic-array", 370 | ] 371 | 372 | [[package]] 373 | name = "block-buffer" 374 | version = "0.10.4" 375 | source = "registry+https://github.com/rust-lang/crates.io-index" 376 | checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" 377 | dependencies = [ 378 | "generic-array", 379 | ] 380 | 381 | [[package]] 382 | name = "borsh" 383 | version = "1.6.0" 384 | source = "registry+https://github.com/rust-lang/crates.io-index" 385 | checksum = "d1da5ab77c1437701eeff7c88d968729e7766172279eab0676857b3d63af7a6f" 386 | dependencies = [ 387 | "borsh-derive", 388 | "cfg_aliases", 389 | ] 390 | 391 | [[package]] 392 | name = "borsh-derive" 393 | version = "1.6.0" 394 | source = "registry+https://github.com/rust-lang/crates.io-index" 395 | checksum = "0686c856aa6aac0c4498f936d7d6a02df690f614c03e4d906d1018062b5c5e2c" 396 | dependencies = [ 397 | "once_cell", 398 | "proc-macro-crate", 399 | "proc-macro2", 400 | "quote", 401 | "syn 2.0.106", 402 | ] 403 | 404 | [[package]] 405 | name = "bs58" 406 | version = "0.5.1" 407 | source = "registry+https://github.com/rust-lang/crates.io-index" 408 | checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" 409 | dependencies = [ 410 | "tinyvec", 411 | ] 412 | 413 | [[package]] 414 | name = "bumpalo" 415 | version = "3.19.0" 416 | source = "registry+https://github.com/rust-lang/crates.io-index" 417 | checksum = "46c5e41b57b8bba42a04676d81cb89e9ee8e859a1a66f80a5a72e1cb76b34d43" 418 | 419 | [[package]] 420 | name = "bv" 421 | version = "0.11.1" 422 | source = "registry+https://github.com/rust-lang/crates.io-index" 423 | checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340" 424 | dependencies = [ 425 | "feature-probe", 426 | "serde", 427 | ] 428 | 429 | [[package]] 430 | name = "bytemuck" 431 | version = "1.24.0" 432 | source = "registry+https://github.com/rust-lang/crates.io-index" 433 | checksum = "1fbdf580320f38b612e485521afda1ee26d10cc9884efaaa750d383e13e3c5f4" 434 | dependencies = [ 435 | "bytemuck_derive", 436 | ] 437 | 438 | [[package]] 439 | name = "bytemuck_derive" 440 | version = "1.10.2" 441 | source = "registry+https://github.com/rust-lang/crates.io-index" 442 | checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" 443 | dependencies = [ 444 | "proc-macro2", 445 | "quote", 446 | "syn 2.0.106", 447 | ] 448 | 449 | [[package]] 450 | name = "byteorder" 451 | version = "1.5.0" 452 | source = "registry+https://github.com/rust-lang/crates.io-index" 453 | checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" 454 | 455 | [[package]] 456 | name = "cc" 457 | version = "1.2.34" 458 | source = "registry+https://github.com/rust-lang/crates.io-index" 459 | checksum = "42bc4aea80032b7bf409b0bc7ccad88853858911b7713a8062fdc0623867bedc" 460 | dependencies = [ 461 | "shlex", 462 | ] 463 | 464 | [[package]] 465 | name = "cfg-if" 466 | version = "1.0.3" 467 | source = "registry+https://github.com/rust-lang/crates.io-index" 468 | checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" 469 | 470 | [[package]] 471 | name = "cfg_aliases" 472 | version = "0.2.1" 473 | source = "registry+https://github.com/rust-lang/crates.io-index" 474 | checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" 475 | 476 | [[package]] 477 | name = "cipher" 478 | version = "0.4.4" 479 | source = "registry+https://github.com/rust-lang/crates.io-index" 480 | checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" 481 | dependencies = [ 482 | "crypto-common", 483 | "inout", 484 | ] 485 | 486 | [[package]] 487 | name = "colorchoice" 488 | version = "1.0.4" 489 | source = "registry+https://github.com/rust-lang/crates.io-index" 490 | checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" 491 | 492 | [[package]] 493 | name = "combine" 494 | version = "3.8.1" 495 | source = "registry+https://github.com/rust-lang/crates.io-index" 496 | checksum = "da3da6baa321ec19e1cc41d31bf599f00c783d0517095cdaf0332e3fe8d20680" 497 | dependencies = [ 498 | "ascii", 499 | "byteorder", 500 | "either", 501 | "memchr", 502 | "unreachable", 503 | ] 504 | 505 | [[package]] 506 | name = "const-oid" 507 | version = "0.9.6" 508 | source = "registry+https://github.com/rust-lang/crates.io-index" 509 | checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" 510 | 511 | [[package]] 512 | name = "constant_time_eq" 513 | version = "0.3.1" 514 | source = "registry+https://github.com/rust-lang/crates.io-index" 515 | checksum = "7c74b8349d32d297c9134b8c88677813a227df8f779daa29bfc29c183fe3dca6" 516 | 517 | [[package]] 518 | name = "cpufeatures" 519 | version = "0.2.17" 520 | source = "registry+https://github.com/rust-lang/crates.io-index" 521 | checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" 522 | dependencies = [ 523 | "libc", 524 | ] 525 | 526 | [[package]] 527 | name = "crunchy" 528 | version = "0.2.4" 529 | source = "registry+https://github.com/rust-lang/crates.io-index" 530 | checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" 531 | 532 | [[package]] 533 | name = "crypto-bigint" 534 | version = "0.5.5" 535 | source = "registry+https://github.com/rust-lang/crates.io-index" 536 | checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" 537 | dependencies = [ 538 | "generic-array", 539 | "rand_core 0.6.4", 540 | "subtle", 541 | "zeroize", 542 | ] 543 | 544 | [[package]] 545 | name = "crypto-common" 546 | version = "0.1.6" 547 | source = "registry+https://github.com/rust-lang/crates.io-index" 548 | checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" 549 | dependencies = [ 550 | "generic-array", 551 | "rand_core 0.6.4", 552 | "typenum", 553 | ] 554 | 555 | [[package]] 556 | name = "ctr" 557 | version = "0.9.2" 558 | source = "registry+https://github.com/rust-lang/crates.io-index" 559 | checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" 560 | dependencies = [ 561 | "cipher", 562 | ] 563 | 564 | [[package]] 565 | name = "curve25519-dalek" 566 | version = "4.1.3" 567 | source = "registry+https://github.com/rust-lang/crates.io-index" 568 | checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" 569 | dependencies = [ 570 | "cfg-if", 571 | "cpufeatures", 572 | "curve25519-dalek-derive", 573 | "digest 0.10.7", 574 | "fiat-crypto", 575 | "rand_core 0.6.4", 576 | "rustc_version", 577 | "serde", 578 | "subtle", 579 | "zeroize", 580 | ] 581 | 582 | [[package]] 583 | name = "curve25519-dalek-derive" 584 | version = "0.1.1" 585 | source = "registry+https://github.com/rust-lang/crates.io-index" 586 | checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" 587 | dependencies = [ 588 | "proc-macro2", 589 | "quote", 590 | "syn 2.0.106", 591 | ] 592 | 593 | [[package]] 594 | name = "der" 595 | version = "0.7.10" 596 | source = "registry+https://github.com/rust-lang/crates.io-index" 597 | checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" 598 | dependencies = [ 599 | "const-oid", 600 | "zeroize", 601 | ] 602 | 603 | [[package]] 604 | name = "derivation-path" 605 | version = "0.2.0" 606 | source = "registry+https://github.com/rust-lang/crates.io-index" 607 | checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0" 608 | 609 | [[package]] 610 | name = "derivative" 611 | version = "2.2.0" 612 | source = "registry+https://github.com/rust-lang/crates.io-index" 613 | checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" 614 | dependencies = [ 615 | "proc-macro2", 616 | "quote", 617 | "syn 1.0.109", 618 | ] 619 | 620 | [[package]] 621 | name = "digest" 622 | version = "0.9.0" 623 | source = "registry+https://github.com/rust-lang/crates.io-index" 624 | checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" 625 | dependencies = [ 626 | "generic-array", 627 | ] 628 | 629 | [[package]] 630 | name = "digest" 631 | version = "0.10.7" 632 | source = "registry+https://github.com/rust-lang/crates.io-index" 633 | checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" 634 | dependencies = [ 635 | "block-buffer 0.10.4", 636 | "const-oid", 637 | "crypto-common", 638 | "subtle", 639 | ] 640 | 641 | [[package]] 642 | name = "eager" 643 | version = "0.1.0" 644 | source = "registry+https://github.com/rust-lang/crates.io-index" 645 | checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" 646 | 647 | [[package]] 648 | name = "ecdsa" 649 | version = "0.16.9" 650 | source = "registry+https://github.com/rust-lang/crates.io-index" 651 | checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" 652 | dependencies = [ 653 | "der", 654 | "digest 0.10.7", 655 | "elliptic-curve", 656 | "rfc6979", 657 | "signature", 658 | "spki", 659 | ] 660 | 661 | [[package]] 662 | name = "ed25519" 663 | version = "2.2.3" 664 | source = "registry+https://github.com/rust-lang/crates.io-index" 665 | checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" 666 | dependencies = [ 667 | "pkcs8", 668 | "signature", 669 | ] 670 | 671 | [[package]] 672 | name = "ed25519-dalek" 673 | version = "2.2.0" 674 | source = "registry+https://github.com/rust-lang/crates.io-index" 675 | checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" 676 | dependencies = [ 677 | "curve25519-dalek", 678 | "ed25519", 679 | "rand_core 0.6.4", 680 | "serde", 681 | "sha2 0.10.9", 682 | "subtle", 683 | "zeroize", 684 | ] 685 | 686 | [[package]] 687 | name = "either" 688 | version = "1.15.0" 689 | source = "registry+https://github.com/rust-lang/crates.io-index" 690 | checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" 691 | 692 | [[package]] 693 | name = "elliptic-curve" 694 | version = "0.13.8" 695 | source = "registry+https://github.com/rust-lang/crates.io-index" 696 | checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" 697 | dependencies = [ 698 | "base16ct", 699 | "crypto-bigint", 700 | "digest 0.10.7", 701 | "ff", 702 | "generic-array", 703 | "group", 704 | "pkcs8", 705 | "rand_core 0.6.4", 706 | "sec1", 707 | "subtle", 708 | "zeroize", 709 | ] 710 | 711 | [[package]] 712 | name = "enum-iterator" 713 | version = "1.5.0" 714 | source = "registry+https://github.com/rust-lang/crates.io-index" 715 | checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" 716 | dependencies = [ 717 | "enum-iterator-derive", 718 | ] 719 | 720 | [[package]] 721 | name = "enum-iterator-derive" 722 | version = "1.4.0" 723 | source = "registry+https://github.com/rust-lang/crates.io-index" 724 | checksum = "a1ab991c1362ac86c61ab6f556cff143daa22e5a15e4e189df818b2fd19fe65b" 725 | dependencies = [ 726 | "proc-macro2", 727 | "quote", 728 | "syn 2.0.106", 729 | ] 730 | 731 | [[package]] 732 | name = "env_filter" 733 | version = "0.1.3" 734 | source = "registry+https://github.com/rust-lang/crates.io-index" 735 | checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" 736 | dependencies = [ 737 | "log", 738 | "regex", 739 | ] 740 | 741 | [[package]] 742 | name = "env_logger" 743 | version = "0.11.8" 744 | source = "registry+https://github.com/rust-lang/crates.io-index" 745 | checksum = "13c863f0904021b108aa8b2f55046443e6b1ebde8fd4a15c399893aae4fa069f" 746 | dependencies = [ 747 | "anstream", 748 | "anstyle", 749 | "env_filter", 750 | "jiff", 751 | "log", 752 | ] 753 | 754 | [[package]] 755 | name = "equivalent" 756 | version = "1.0.2" 757 | source = "registry+https://github.com/rust-lang/crates.io-index" 758 | checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" 759 | 760 | [[package]] 761 | name = "feature-probe" 762 | version = "0.1.1" 763 | source = "registry+https://github.com/rust-lang/crates.io-index" 764 | checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" 765 | 766 | [[package]] 767 | name = "ff" 768 | version = "0.13.1" 769 | source = "registry+https://github.com/rust-lang/crates.io-index" 770 | checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" 771 | dependencies = [ 772 | "rand_core 0.6.4", 773 | "subtle", 774 | ] 775 | 776 | [[package]] 777 | name = "fiat-crypto" 778 | version = "0.2.9" 779 | source = "registry+https://github.com/rust-lang/crates.io-index" 780 | checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" 781 | 782 | [[package]] 783 | name = "five8" 784 | version = "0.2.1" 785 | source = "registry+https://github.com/rust-lang/crates.io-index" 786 | checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" 787 | dependencies = [ 788 | "five8_core", 789 | ] 790 | 791 | [[package]] 792 | name = "five8" 793 | version = "1.0.0" 794 | source = "registry+https://github.com/rust-lang/crates.io-index" 795 | checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" 796 | dependencies = [ 797 | "five8_core", 798 | ] 799 | 800 | [[package]] 801 | name = "five8_const" 802 | version = "1.0.0" 803 | source = "registry+https://github.com/rust-lang/crates.io-index" 804 | checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" 805 | dependencies = [ 806 | "five8_core", 807 | ] 808 | 809 | [[package]] 810 | name = "five8_core" 811 | version = "0.1.2" 812 | source = "registry+https://github.com/rust-lang/crates.io-index" 813 | checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" 814 | 815 | [[package]] 816 | name = "fnv" 817 | version = "1.0.7" 818 | source = "registry+https://github.com/rust-lang/crates.io-index" 819 | checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" 820 | 821 | [[package]] 822 | name = "generic-array" 823 | version = "0.14.7" 824 | source = "registry+https://github.com/rust-lang/crates.io-index" 825 | checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" 826 | dependencies = [ 827 | "typenum", 828 | "version_check", 829 | "zeroize", 830 | ] 831 | 832 | [[package]] 833 | name = "getrandom" 834 | version = "0.1.16" 835 | source = "registry+https://github.com/rust-lang/crates.io-index" 836 | checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" 837 | dependencies = [ 838 | "cfg-if", 839 | "libc", 840 | "wasi 0.9.0+wasi-snapshot-preview1", 841 | ] 842 | 843 | [[package]] 844 | name = "getrandom" 845 | version = "0.2.16" 846 | source = "registry+https://github.com/rust-lang/crates.io-index" 847 | checksum = "335ff9f135e4384c8150d6f27c6daed433577f86b4750418338c01a1a2528592" 848 | dependencies = [ 849 | "cfg-if", 850 | "js-sys", 851 | "libc", 852 | "wasi 0.11.1+wasi-snapshot-preview1", 853 | "wasm-bindgen", 854 | ] 855 | 856 | [[package]] 857 | name = "getrandom" 858 | version = "0.3.3" 859 | source = "registry+https://github.com/rust-lang/crates.io-index" 860 | checksum = "26145e563e54f2cadc477553f1ec5ee650b00862f0a58bcd12cbdc5f0ea2d2f4" 861 | dependencies = [ 862 | "cfg-if", 863 | "libc", 864 | "r-efi", 865 | "wasi 0.14.2+wasi-0.2.4", 866 | ] 867 | 868 | [[package]] 869 | name = "group" 870 | version = "0.13.0" 871 | source = "registry+https://github.com/rust-lang/crates.io-index" 872 | checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" 873 | dependencies = [ 874 | "ff", 875 | "rand_core 0.6.4", 876 | "subtle", 877 | ] 878 | 879 | [[package]] 880 | name = "hash32" 881 | version = "0.3.1" 882 | source = "registry+https://github.com/rust-lang/crates.io-index" 883 | checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" 884 | dependencies = [ 885 | "byteorder", 886 | ] 887 | 888 | [[package]] 889 | name = "hashbrown" 890 | version = "0.13.2" 891 | source = "registry+https://github.com/rust-lang/crates.io-index" 892 | checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" 893 | dependencies = [ 894 | "ahash", 895 | ] 896 | 897 | [[package]] 898 | name = "hashbrown" 899 | version = "0.15.5" 900 | source = "registry+https://github.com/rust-lang/crates.io-index" 901 | checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" 902 | 903 | [[package]] 904 | name = "hmac" 905 | version = "0.12.1" 906 | source = "registry+https://github.com/rust-lang/crates.io-index" 907 | checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" 908 | dependencies = [ 909 | "digest 0.10.7", 910 | ] 911 | 912 | [[package]] 913 | name = "indexmap" 914 | version = "2.11.0" 915 | source = "registry+https://github.com/rust-lang/crates.io-index" 916 | checksum = "f2481980430f9f78649238835720ddccc57e52df14ffce1c6f37391d61b563e9" 917 | dependencies = [ 918 | "equivalent", 919 | "hashbrown 0.15.5", 920 | ] 921 | 922 | [[package]] 923 | name = "inout" 924 | version = "0.1.4" 925 | source = "registry+https://github.com/rust-lang/crates.io-index" 926 | checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" 927 | dependencies = [ 928 | "generic-array", 929 | ] 930 | 931 | [[package]] 932 | name = "is_terminal_polyfill" 933 | version = "1.70.1" 934 | source = "registry+https://github.com/rust-lang/crates.io-index" 935 | checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" 936 | 937 | [[package]] 938 | name = "itertools" 939 | version = "0.10.5" 940 | source = "registry+https://github.com/rust-lang/crates.io-index" 941 | checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" 942 | dependencies = [ 943 | "either", 944 | ] 945 | 946 | [[package]] 947 | name = "itertools" 948 | version = "0.12.1" 949 | source = "registry+https://github.com/rust-lang/crates.io-index" 950 | checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" 951 | dependencies = [ 952 | "either", 953 | ] 954 | 955 | [[package]] 956 | name = "itoa" 957 | version = "1.0.15" 958 | source = "registry+https://github.com/rust-lang/crates.io-index" 959 | checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" 960 | 961 | [[package]] 962 | name = "jiff" 963 | version = "0.2.15" 964 | source = "registry+https://github.com/rust-lang/crates.io-index" 965 | checksum = "be1f93b8b1eb69c77f24bbb0afdf66f54b632ee39af40ca21c4365a1d7347e49" 966 | dependencies = [ 967 | "jiff-static", 968 | "log", 969 | "portable-atomic", 970 | "portable-atomic-util", 971 | "serde", 972 | ] 973 | 974 | [[package]] 975 | name = "jiff-static" 976 | version = "0.2.15" 977 | source = "registry+https://github.com/rust-lang/crates.io-index" 978 | checksum = "03343451ff899767262ec32146f6d559dd759fdadf42ff0e227c7c48f72594b4" 979 | dependencies = [ 980 | "proc-macro2", 981 | "quote", 982 | "syn 2.0.106", 983 | ] 984 | 985 | [[package]] 986 | name = "js-sys" 987 | version = "0.3.77" 988 | source = "registry+https://github.com/rust-lang/crates.io-index" 989 | checksum = "1cfaf33c695fc6e08064efbc1f72ec937429614f25eef83af942d0e227c3a28f" 990 | dependencies = [ 991 | "once_cell", 992 | "wasm-bindgen", 993 | ] 994 | 995 | [[package]] 996 | name = "k256" 997 | version = "0.13.4" 998 | source = "registry+https://github.com/rust-lang/crates.io-index" 999 | checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" 1000 | dependencies = [ 1001 | "cfg-if", 1002 | "ecdsa", 1003 | "elliptic-curve", 1004 | "once_cell", 1005 | "sha2 0.10.9", 1006 | "signature", 1007 | ] 1008 | 1009 | [[package]] 1010 | name = "keccak" 1011 | version = "0.1.5" 1012 | source = "registry+https://github.com/rust-lang/crates.io-index" 1013 | checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" 1014 | dependencies = [ 1015 | "cpufeatures", 1016 | ] 1017 | 1018 | [[package]] 1019 | name = "lazy_static" 1020 | version = "1.5.0" 1021 | source = "registry+https://github.com/rust-lang/crates.io-index" 1022 | checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" 1023 | 1024 | [[package]] 1025 | name = "libc" 1026 | version = "0.2.175" 1027 | source = "registry+https://github.com/rust-lang/crates.io-index" 1028 | checksum = "6a82ae493e598baaea5209805c49bbf2ea7de956d50d7da0da1164f9c6d28543" 1029 | 1030 | [[package]] 1031 | name = "libsecp256k1" 1032 | version = "0.6.0" 1033 | source = "registry+https://github.com/rust-lang/crates.io-index" 1034 | checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73" 1035 | dependencies = [ 1036 | "arrayref", 1037 | "base64 0.12.3", 1038 | "digest 0.9.0", 1039 | "libsecp256k1-core", 1040 | "libsecp256k1-gen-ecmult", 1041 | "libsecp256k1-gen-genmult", 1042 | "rand 0.7.3", 1043 | "serde", 1044 | "sha2 0.9.9", 1045 | ] 1046 | 1047 | [[package]] 1048 | name = "libsecp256k1-core" 1049 | version = "0.2.2" 1050 | source = "registry+https://github.com/rust-lang/crates.io-index" 1051 | checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80" 1052 | dependencies = [ 1053 | "crunchy", 1054 | "digest 0.9.0", 1055 | "subtle", 1056 | ] 1057 | 1058 | [[package]] 1059 | name = "libsecp256k1-gen-ecmult" 1060 | version = "0.2.1" 1061 | source = "registry+https://github.com/rust-lang/crates.io-index" 1062 | checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3" 1063 | dependencies = [ 1064 | "libsecp256k1-core", 1065 | ] 1066 | 1067 | [[package]] 1068 | name = "libsecp256k1-gen-genmult" 1069 | version = "0.2.1" 1070 | source = "registry+https://github.com/rust-lang/crates.io-index" 1071 | checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d" 1072 | dependencies = [ 1073 | "libsecp256k1-core", 1074 | ] 1075 | 1076 | [[package]] 1077 | name = "light-poseidon" 1078 | version = "0.2.0" 1079 | source = "registry+https://github.com/rust-lang/crates.io-index" 1080 | checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" 1081 | dependencies = [ 1082 | "ark-bn254", 1083 | "ark-ff", 1084 | "num-bigint 0.4.6", 1085 | "thiserror 1.0.69", 1086 | ] 1087 | 1088 | [[package]] 1089 | name = "lock_api" 1090 | version = "0.4.13" 1091 | source = "registry+https://github.com/rust-lang/crates.io-index" 1092 | checksum = "96936507f153605bddfcda068dd804796c84324ed2510809e5b2a624c81da765" 1093 | dependencies = [ 1094 | "autocfg", 1095 | "scopeguard", 1096 | ] 1097 | 1098 | [[package]] 1099 | name = "log" 1100 | version = "0.4.27" 1101 | source = "registry+https://github.com/rust-lang/crates.io-index" 1102 | checksum = "13dc2df351e3202783a1fe0d44375f7295ffb4049267b0f3018346dc122a1d94" 1103 | 1104 | [[package]] 1105 | name = "memchr" 1106 | version = "2.7.5" 1107 | source = "registry+https://github.com/rust-lang/crates.io-index" 1108 | checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" 1109 | 1110 | [[package]] 1111 | name = "merlin" 1112 | version = "3.0.0" 1113 | source = "registry+https://github.com/rust-lang/crates.io-index" 1114 | checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d" 1115 | dependencies = [ 1116 | "byteorder", 1117 | "keccak", 1118 | "rand_core 0.6.4", 1119 | "zeroize", 1120 | ] 1121 | 1122 | [[package]] 1123 | name = "mollusk-svm" 1124 | version = "0.7.2" 1125 | source = "registry+https://github.com/rust-lang/crates.io-index" 1126 | checksum = "6ed52e82370cbf4f266a65603d7d1cbe7faf94fcf769d068c0b89bb934a882e3" 1127 | dependencies = [ 1128 | "agave-feature-set", 1129 | "agave-syscalls", 1130 | "bincode", 1131 | "mollusk-svm-error", 1132 | "mollusk-svm-keys", 1133 | "mollusk-svm-result", 1134 | "solana-account", 1135 | "solana-bpf-loader-program", 1136 | "solana-clock", 1137 | "solana-compute-budget", 1138 | "solana-epoch-rewards", 1139 | "solana-epoch-schedule", 1140 | "solana-hash 3.1.0", 1141 | "solana-instruction", 1142 | "solana-instruction-error", 1143 | "solana-loader-v3-interface", 1144 | "solana-loader-v4-interface", 1145 | "solana-logger", 1146 | "solana-precompile-error", 1147 | "solana-program-error", 1148 | "solana-program-runtime", 1149 | "solana-pubkey 3.0.0", 1150 | "solana-rent", 1151 | "solana-sdk-ids", 1152 | "solana-slot-hashes", 1153 | "solana-stake-interface", 1154 | "solana-svm-callback", 1155 | "solana-svm-log-collector", 1156 | "solana-svm-timings", 1157 | "solana-system-program", 1158 | "solana-sysvar", 1159 | "solana-sysvar-id", 1160 | "solana-transaction-context", 1161 | ] 1162 | 1163 | [[package]] 1164 | name = "mollusk-svm-error" 1165 | version = "0.7.2" 1166 | source = "registry+https://github.com/rust-lang/crates.io-index" 1167 | checksum = "682ad3a990ae8f336ee10f402da2e900a37cff38730e29aa8cda2d82e1b2e9f1" 1168 | dependencies = [ 1169 | "solana-pubkey 3.0.0", 1170 | "thiserror 1.0.69", 1171 | ] 1172 | 1173 | [[package]] 1174 | name = "mollusk-svm-keys" 1175 | version = "0.7.2" 1176 | source = "registry+https://github.com/rust-lang/crates.io-index" 1177 | checksum = "b97ddf2442ea621ea5ae25b0c21ae2861588ea34abce0d059cb601de24cd646f" 1178 | dependencies = [ 1179 | "mollusk-svm-error", 1180 | "solana-account", 1181 | "solana-instruction", 1182 | "solana-pubkey 3.0.0", 1183 | "solana-transaction-context", 1184 | ] 1185 | 1186 | [[package]] 1187 | name = "mollusk-svm-programs-token" 1188 | version = "0.7.2" 1189 | source = "registry+https://github.com/rust-lang/crates.io-index" 1190 | checksum = "bd40afe1a3aa5cef8a9c031ef9cd292d9570ea73ede073257b08aa2da349c6b1" 1191 | dependencies = [ 1192 | "mollusk-svm", 1193 | "solana-account", 1194 | "solana-program-pack", 1195 | "solana-pubkey 3.0.0", 1196 | "solana-rent", 1197 | "spl-associated-token-account-interface 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", 1198 | "spl-token-interface", 1199 | ] 1200 | 1201 | [[package]] 1202 | name = "mollusk-svm-result" 1203 | version = "0.7.2" 1204 | source = "registry+https://github.com/rust-lang/crates.io-index" 1205 | checksum = "4f23d402bb19bac3b25b02ada2cf1f58dd4bc8e4b12a38fc1f58aef0090ff0f6" 1206 | dependencies = [ 1207 | "solana-account", 1208 | "solana-instruction", 1209 | "solana-program-error", 1210 | "solana-pubkey 3.0.0", 1211 | "solana-rent", 1212 | ] 1213 | 1214 | [[package]] 1215 | name = "num" 1216 | version = "0.2.1" 1217 | source = "registry+https://github.com/rust-lang/crates.io-index" 1218 | checksum = "b8536030f9fea7127f841b45bb6243b27255787fb4eb83958aa1ef9d2fdc0c36" 1219 | dependencies = [ 1220 | "num-bigint 0.2.6", 1221 | "num-complex", 1222 | "num-integer", 1223 | "num-iter", 1224 | "num-rational", 1225 | "num-traits", 1226 | ] 1227 | 1228 | [[package]] 1229 | name = "num-bigint" 1230 | version = "0.2.6" 1231 | source = "registry+https://github.com/rust-lang/crates.io-index" 1232 | checksum = "090c7f9998ee0ff65aa5b723e4009f7b217707f1fb5ea551329cc4d6231fb304" 1233 | dependencies = [ 1234 | "autocfg", 1235 | "num-integer", 1236 | "num-traits", 1237 | ] 1238 | 1239 | [[package]] 1240 | name = "num-bigint" 1241 | version = "0.4.6" 1242 | source = "registry+https://github.com/rust-lang/crates.io-index" 1243 | checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" 1244 | dependencies = [ 1245 | "num-integer", 1246 | "num-traits", 1247 | ] 1248 | 1249 | [[package]] 1250 | name = "num-complex" 1251 | version = "0.2.4" 1252 | source = "registry+https://github.com/rust-lang/crates.io-index" 1253 | checksum = "b6b19411a9719e753aff12e5187b74d60d3dc449ec3f4dc21e3989c3f554bc95" 1254 | dependencies = [ 1255 | "autocfg", 1256 | "num-traits", 1257 | ] 1258 | 1259 | [[package]] 1260 | name = "num-derive" 1261 | version = "0.4.2" 1262 | source = "registry+https://github.com/rust-lang/crates.io-index" 1263 | checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" 1264 | dependencies = [ 1265 | "proc-macro2", 1266 | "quote", 1267 | "syn 2.0.106", 1268 | ] 1269 | 1270 | [[package]] 1271 | name = "num-integer" 1272 | version = "0.1.46" 1273 | source = "registry+https://github.com/rust-lang/crates.io-index" 1274 | checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" 1275 | dependencies = [ 1276 | "num-traits", 1277 | ] 1278 | 1279 | [[package]] 1280 | name = "num-iter" 1281 | version = "0.1.45" 1282 | source = "registry+https://github.com/rust-lang/crates.io-index" 1283 | checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" 1284 | dependencies = [ 1285 | "autocfg", 1286 | "num-integer", 1287 | "num-traits", 1288 | ] 1289 | 1290 | [[package]] 1291 | name = "num-rational" 1292 | version = "0.2.4" 1293 | source = "registry+https://github.com/rust-lang/crates.io-index" 1294 | checksum = "5c000134b5dbf44adc5cb772486d335293351644b801551abe8f75c84cfa4aef" 1295 | dependencies = [ 1296 | "autocfg", 1297 | "num-bigint 0.2.6", 1298 | "num-integer", 1299 | "num-traits", 1300 | ] 1301 | 1302 | [[package]] 1303 | name = "num-traits" 1304 | version = "0.2.19" 1305 | source = "registry+https://github.com/rust-lang/crates.io-index" 1306 | checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" 1307 | dependencies = [ 1308 | "autocfg", 1309 | ] 1310 | 1311 | [[package]] 1312 | name = "num_enum" 1313 | version = "0.7.5" 1314 | source = "registry+https://github.com/rust-lang/crates.io-index" 1315 | checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" 1316 | dependencies = [ 1317 | "num_enum_derive", 1318 | "rustversion", 1319 | ] 1320 | 1321 | [[package]] 1322 | name = "num_enum_derive" 1323 | version = "0.7.5" 1324 | source = "registry+https://github.com/rust-lang/crates.io-index" 1325 | checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" 1326 | dependencies = [ 1327 | "proc-macro-crate", 1328 | "proc-macro2", 1329 | "quote", 1330 | "syn 2.0.106", 1331 | ] 1332 | 1333 | [[package]] 1334 | name = "once_cell" 1335 | version = "1.21.3" 1336 | source = "registry+https://github.com/rust-lang/crates.io-index" 1337 | checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" 1338 | 1339 | [[package]] 1340 | name = "once_cell_polyfill" 1341 | version = "1.70.1" 1342 | source = "registry+https://github.com/rust-lang/crates.io-index" 1343 | checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" 1344 | 1345 | [[package]] 1346 | name = "opaque-debug" 1347 | version = "0.3.1" 1348 | source = "registry+https://github.com/rust-lang/crates.io-index" 1349 | checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" 1350 | 1351 | [[package]] 1352 | name = "parking_lot" 1353 | version = "0.12.4" 1354 | source = "registry+https://github.com/rust-lang/crates.io-index" 1355 | checksum = "70d58bf43669b5795d1576d0641cfb6fbb2057bf629506267a92807158584a13" 1356 | dependencies = [ 1357 | "lock_api", 1358 | "parking_lot_core", 1359 | ] 1360 | 1361 | [[package]] 1362 | name = "parking_lot_core" 1363 | version = "0.9.11" 1364 | source = "registry+https://github.com/rust-lang/crates.io-index" 1365 | checksum = "bc838d2a56b5b1a6c25f55575dfc605fabb63bb2365f6c2353ef9159aa69e4a5" 1366 | dependencies = [ 1367 | "cfg-if", 1368 | "libc", 1369 | "redox_syscall", 1370 | "smallvec", 1371 | "windows-targets 0.52.6", 1372 | ] 1373 | 1374 | [[package]] 1375 | name = "paste" 1376 | version = "1.0.15" 1377 | source = "registry+https://github.com/rust-lang/crates.io-index" 1378 | checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" 1379 | 1380 | [[package]] 1381 | name = "pbkdf2" 1382 | version = "0.11.0" 1383 | source = "registry+https://github.com/rust-lang/crates.io-index" 1384 | checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917" 1385 | dependencies = [ 1386 | "digest 0.10.7", 1387 | ] 1388 | 1389 | [[package]] 1390 | name = "percent-encoding" 1391 | version = "2.3.2" 1392 | source = "registry+https://github.com/rust-lang/crates.io-index" 1393 | checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" 1394 | 1395 | [[package]] 1396 | name = "percentage" 1397 | version = "0.1.0" 1398 | source = "registry+https://github.com/rust-lang/crates.io-index" 1399 | checksum = "2fd23b938276f14057220b707937bcb42fa76dda7560e57a2da30cb52d557937" 1400 | dependencies = [ 1401 | "num", 1402 | ] 1403 | 1404 | [[package]] 1405 | name = "pkcs8" 1406 | version = "0.10.2" 1407 | source = "registry+https://github.com/rust-lang/crates.io-index" 1408 | checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" 1409 | dependencies = [ 1410 | "der", 1411 | "spki", 1412 | ] 1413 | 1414 | [[package]] 1415 | name = "polyval" 1416 | version = "0.6.2" 1417 | source = "registry+https://github.com/rust-lang/crates.io-index" 1418 | checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" 1419 | dependencies = [ 1420 | "cfg-if", 1421 | "cpufeatures", 1422 | "opaque-debug", 1423 | "universal-hash", 1424 | ] 1425 | 1426 | [[package]] 1427 | name = "portable-atomic" 1428 | version = "1.11.1" 1429 | source = "registry+https://github.com/rust-lang/crates.io-index" 1430 | checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" 1431 | 1432 | [[package]] 1433 | name = "portable-atomic-util" 1434 | version = "0.2.4" 1435 | source = "registry+https://github.com/rust-lang/crates.io-index" 1436 | checksum = "d8a2f0d8d040d7848a709caf78912debcc3f33ee4b3cac47d73d1e1069e83507" 1437 | dependencies = [ 1438 | "portable-atomic", 1439 | ] 1440 | 1441 | [[package]] 1442 | name = "ppv-lite86" 1443 | version = "0.2.21" 1444 | source = "registry+https://github.com/rust-lang/crates.io-index" 1445 | checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" 1446 | dependencies = [ 1447 | "zerocopy", 1448 | ] 1449 | 1450 | [[package]] 1451 | name = "proc-macro-crate" 1452 | version = "3.3.0" 1453 | source = "registry+https://github.com/rust-lang/crates.io-index" 1454 | checksum = "edce586971a4dfaa28950c6f18ed55e0406c1ab88bbce2c6f6293a7aaba73d35" 1455 | dependencies = [ 1456 | "toml_edit", 1457 | ] 1458 | 1459 | [[package]] 1460 | name = "proc-macro2" 1461 | version = "1.0.101" 1462 | source = "registry+https://github.com/rust-lang/crates.io-index" 1463 | checksum = "89ae43fd86e4158d6db51ad8e2b80f313af9cc74f5c0e03ccb87de09998732de" 1464 | dependencies = [ 1465 | "unicode-ident", 1466 | ] 1467 | 1468 | [[package]] 1469 | name = "qstring" 1470 | version = "0.7.2" 1471 | source = "registry+https://github.com/rust-lang/crates.io-index" 1472 | checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e" 1473 | dependencies = [ 1474 | "percent-encoding", 1475 | ] 1476 | 1477 | [[package]] 1478 | name = "qualifier_attr" 1479 | version = "0.2.2" 1480 | source = "registry+https://github.com/rust-lang/crates.io-index" 1481 | checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" 1482 | dependencies = [ 1483 | "proc-macro2", 1484 | "quote", 1485 | "syn 2.0.106", 1486 | ] 1487 | 1488 | [[package]] 1489 | name = "quote" 1490 | version = "1.0.40" 1491 | source = "registry+https://github.com/rust-lang/crates.io-index" 1492 | checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" 1493 | dependencies = [ 1494 | "proc-macro2", 1495 | ] 1496 | 1497 | [[package]] 1498 | name = "r-efi" 1499 | version = "5.3.0" 1500 | source = "registry+https://github.com/rust-lang/crates.io-index" 1501 | checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" 1502 | 1503 | [[package]] 1504 | name = "rand" 1505 | version = "0.7.3" 1506 | source = "registry+https://github.com/rust-lang/crates.io-index" 1507 | checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" 1508 | dependencies = [ 1509 | "getrandom 0.1.16", 1510 | "libc", 1511 | "rand_chacha 0.2.2", 1512 | "rand_core 0.5.1", 1513 | "rand_hc", 1514 | ] 1515 | 1516 | [[package]] 1517 | name = "rand" 1518 | version = "0.8.5" 1519 | source = "registry+https://github.com/rust-lang/crates.io-index" 1520 | checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" 1521 | dependencies = [ 1522 | "libc", 1523 | "rand_chacha 0.3.1", 1524 | "rand_core 0.6.4", 1525 | ] 1526 | 1527 | [[package]] 1528 | name = "rand_chacha" 1529 | version = "0.2.2" 1530 | source = "registry+https://github.com/rust-lang/crates.io-index" 1531 | checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" 1532 | dependencies = [ 1533 | "ppv-lite86", 1534 | "rand_core 0.5.1", 1535 | ] 1536 | 1537 | [[package]] 1538 | name = "rand_chacha" 1539 | version = "0.3.1" 1540 | source = "registry+https://github.com/rust-lang/crates.io-index" 1541 | checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" 1542 | dependencies = [ 1543 | "ppv-lite86", 1544 | "rand_core 0.6.4", 1545 | ] 1546 | 1547 | [[package]] 1548 | name = "rand_core" 1549 | version = "0.5.1" 1550 | source = "registry+https://github.com/rust-lang/crates.io-index" 1551 | checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" 1552 | dependencies = [ 1553 | "getrandom 0.1.16", 1554 | ] 1555 | 1556 | [[package]] 1557 | name = "rand_core" 1558 | version = "0.6.4" 1559 | source = "registry+https://github.com/rust-lang/crates.io-index" 1560 | checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" 1561 | dependencies = [ 1562 | "getrandom 0.2.16", 1563 | ] 1564 | 1565 | [[package]] 1566 | name = "rand_hc" 1567 | version = "0.2.0" 1568 | source = "registry+https://github.com/rust-lang/crates.io-index" 1569 | checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" 1570 | dependencies = [ 1571 | "rand_core 0.5.1", 1572 | ] 1573 | 1574 | [[package]] 1575 | name = "redox_syscall" 1576 | version = "0.5.17" 1577 | source = "registry+https://github.com/rust-lang/crates.io-index" 1578 | checksum = "5407465600fb0548f1442edf71dd20683c6ed326200ace4b1ef0763521bb3b77" 1579 | dependencies = [ 1580 | "bitflags", 1581 | ] 1582 | 1583 | [[package]] 1584 | name = "regex" 1585 | version = "1.11.2" 1586 | source = "registry+https://github.com/rust-lang/crates.io-index" 1587 | checksum = "23d7fd106d8c02486a8d64e778353d1cffe08ce79ac2e82f540c86d0facf6912" 1588 | dependencies = [ 1589 | "aho-corasick", 1590 | "memchr", 1591 | "regex-automata", 1592 | "regex-syntax", 1593 | ] 1594 | 1595 | [[package]] 1596 | name = "regex-automata" 1597 | version = "0.4.10" 1598 | source = "registry+https://github.com/rust-lang/crates.io-index" 1599 | checksum = "6b9458fa0bfeeac22b5ca447c63aaf45f28439a709ccd244698632f9aa6394d6" 1600 | dependencies = [ 1601 | "aho-corasick", 1602 | "memchr", 1603 | "regex-syntax", 1604 | ] 1605 | 1606 | [[package]] 1607 | name = "regex-syntax" 1608 | version = "0.8.6" 1609 | source = "registry+https://github.com/rust-lang/crates.io-index" 1610 | checksum = "caf4aa5b0f434c91fe5c7f1ecb6a5ece2130b02ad2a590589dda5146df959001" 1611 | 1612 | [[package]] 1613 | name = "rfc6979" 1614 | version = "0.4.0" 1615 | source = "registry+https://github.com/rust-lang/crates.io-index" 1616 | checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" 1617 | dependencies = [ 1618 | "hmac", 1619 | "subtle", 1620 | ] 1621 | 1622 | [[package]] 1623 | name = "rustc-demangle" 1624 | version = "0.1.26" 1625 | source = "registry+https://github.com/rust-lang/crates.io-index" 1626 | checksum = "56f7d92ca342cea22a06f2121d944b4fd82af56988c270852495420f961d4ace" 1627 | 1628 | [[package]] 1629 | name = "rustc_version" 1630 | version = "0.4.1" 1631 | source = "registry+https://github.com/rust-lang/crates.io-index" 1632 | checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" 1633 | dependencies = [ 1634 | "semver", 1635 | ] 1636 | 1637 | [[package]] 1638 | name = "rustversion" 1639 | version = "1.0.22" 1640 | source = "registry+https://github.com/rust-lang/crates.io-index" 1641 | checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" 1642 | 1643 | [[package]] 1644 | name = "ryu" 1645 | version = "1.0.20" 1646 | source = "registry+https://github.com/rust-lang/crates.io-index" 1647 | checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f" 1648 | 1649 | [[package]] 1650 | name = "scopeguard" 1651 | version = "1.2.0" 1652 | source = "registry+https://github.com/rust-lang/crates.io-index" 1653 | checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" 1654 | 1655 | [[package]] 1656 | name = "sec1" 1657 | version = "0.7.3" 1658 | source = "registry+https://github.com/rust-lang/crates.io-index" 1659 | checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" 1660 | dependencies = [ 1661 | "base16ct", 1662 | "der", 1663 | "generic-array", 1664 | "pkcs8", 1665 | "subtle", 1666 | "zeroize", 1667 | ] 1668 | 1669 | [[package]] 1670 | name = "semver" 1671 | version = "1.0.26" 1672 | source = "registry+https://github.com/rust-lang/crates.io-index" 1673 | checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0" 1674 | 1675 | [[package]] 1676 | name = "serde" 1677 | version = "1.0.228" 1678 | source = "registry+https://github.com/rust-lang/crates.io-index" 1679 | checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" 1680 | dependencies = [ 1681 | "serde_core", 1682 | "serde_derive", 1683 | ] 1684 | 1685 | [[package]] 1686 | name = "serde_bytes" 1687 | version = "0.11.17" 1688 | source = "registry+https://github.com/rust-lang/crates.io-index" 1689 | checksum = "8437fd221bde2d4ca316d61b90e337e9e702b3820b87d63caa9ba6c02bd06d96" 1690 | dependencies = [ 1691 | "serde", 1692 | ] 1693 | 1694 | [[package]] 1695 | name = "serde_core" 1696 | version = "1.0.228" 1697 | source = "registry+https://github.com/rust-lang/crates.io-index" 1698 | checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" 1699 | dependencies = [ 1700 | "serde_derive", 1701 | ] 1702 | 1703 | [[package]] 1704 | name = "serde_derive" 1705 | version = "1.0.228" 1706 | source = "registry+https://github.com/rust-lang/crates.io-index" 1707 | checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" 1708 | dependencies = [ 1709 | "proc-macro2", 1710 | "quote", 1711 | "syn 2.0.106", 1712 | ] 1713 | 1714 | [[package]] 1715 | name = "serde_json" 1716 | version = "1.0.143" 1717 | source = "registry+https://github.com/rust-lang/crates.io-index" 1718 | checksum = "d401abef1d108fbd9cbaebc3e46611f4b1021f714a0597a71f41ee463f5f4a5a" 1719 | dependencies = [ 1720 | "itoa", 1721 | "memchr", 1722 | "ryu", 1723 | "serde", 1724 | ] 1725 | 1726 | [[package]] 1727 | name = "sha2" 1728 | version = "0.9.9" 1729 | source = "registry+https://github.com/rust-lang/crates.io-index" 1730 | checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" 1731 | dependencies = [ 1732 | "block-buffer 0.9.0", 1733 | "cfg-if", 1734 | "cpufeatures", 1735 | "digest 0.9.0", 1736 | "opaque-debug", 1737 | ] 1738 | 1739 | [[package]] 1740 | name = "sha2" 1741 | version = "0.10.9" 1742 | source = "registry+https://github.com/rust-lang/crates.io-index" 1743 | checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" 1744 | dependencies = [ 1745 | "cfg-if", 1746 | "cpufeatures", 1747 | "digest 0.10.7", 1748 | ] 1749 | 1750 | [[package]] 1751 | name = "sha3" 1752 | version = "0.10.8" 1753 | source = "registry+https://github.com/rust-lang/crates.io-index" 1754 | checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" 1755 | dependencies = [ 1756 | "digest 0.10.7", 1757 | "keccak", 1758 | ] 1759 | 1760 | [[package]] 1761 | name = "shlex" 1762 | version = "1.3.0" 1763 | source = "registry+https://github.com/rust-lang/crates.io-index" 1764 | checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" 1765 | 1766 | [[package]] 1767 | name = "signal-hook" 1768 | version = "0.3.18" 1769 | source = "registry+https://github.com/rust-lang/crates.io-index" 1770 | checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" 1771 | dependencies = [ 1772 | "libc", 1773 | "signal-hook-registry", 1774 | ] 1775 | 1776 | [[package]] 1777 | name = "signal-hook-registry" 1778 | version = "1.4.6" 1779 | source = "registry+https://github.com/rust-lang/crates.io-index" 1780 | checksum = "b2a4719bff48cee6b39d12c020eeb490953ad2443b7055bd0b21fca26bd8c28b" 1781 | dependencies = [ 1782 | "libc", 1783 | ] 1784 | 1785 | [[package]] 1786 | name = "signature" 1787 | version = "2.2.0" 1788 | source = "registry+https://github.com/rust-lang/crates.io-index" 1789 | checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" 1790 | dependencies = [ 1791 | "digest 0.10.7", 1792 | "rand_core 0.6.4", 1793 | ] 1794 | 1795 | [[package]] 1796 | name = "smallvec" 1797 | version = "1.15.1" 1798 | source = "registry+https://github.com/rust-lang/crates.io-index" 1799 | checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" 1800 | 1801 | [[package]] 1802 | name = "solana-account" 1803 | version = "3.2.0" 1804 | source = "registry+https://github.com/rust-lang/crates.io-index" 1805 | checksum = "014dcb9293341241dd153b35f89ea906e4170914f4a347a95e7fb07ade47cd6f" 1806 | dependencies = [ 1807 | "bincode", 1808 | "qualifier_attr", 1809 | "serde", 1810 | "serde_bytes", 1811 | "serde_derive", 1812 | "solana-account-info", 1813 | "solana-clock", 1814 | "solana-instruction-error", 1815 | "solana-pubkey 3.0.0", 1816 | "solana-sdk-ids", 1817 | "solana-sysvar", 1818 | ] 1819 | 1820 | [[package]] 1821 | name = "solana-account-info" 1822 | version = "3.1.0" 1823 | source = "registry+https://github.com/rust-lang/crates.io-index" 1824 | checksum = "fc3397241392f5756925029acaa8515dc70fcbe3d8059d4885d7d6533baf64fd" 1825 | dependencies = [ 1826 | "solana-address 2.0.0", 1827 | "solana-program-error", 1828 | "solana-program-memory", 1829 | ] 1830 | 1831 | [[package]] 1832 | name = "solana-address" 1833 | version = "1.1.0" 1834 | source = "registry+https://github.com/rust-lang/crates.io-index" 1835 | checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" 1836 | dependencies = [ 1837 | "solana-address 2.0.0", 1838 | ] 1839 | 1840 | [[package]] 1841 | name = "solana-address" 1842 | version = "2.0.0" 1843 | source = "registry+https://github.com/rust-lang/crates.io-index" 1844 | checksum = "e37320fd2945c5d654b2c6210624a52d66c3f1f73b653ed211ab91a703b35bdd" 1845 | dependencies = [ 1846 | "borsh", 1847 | "bytemuck", 1848 | "bytemuck_derive", 1849 | "curve25519-dalek", 1850 | "five8 1.0.0", 1851 | "five8_const", 1852 | "serde", 1853 | "serde_derive", 1854 | "solana-atomic-u64", 1855 | "solana-define-syscall 4.0.1", 1856 | "solana-program-error", 1857 | "solana-sanitize", 1858 | "solana-sha256-hasher", 1859 | ] 1860 | 1861 | [[package]] 1862 | name = "solana-atomic-u64" 1863 | version = "3.0.0" 1864 | source = "registry+https://github.com/rust-lang/crates.io-index" 1865 | checksum = "a933ff1e50aff72d02173cfcd7511bd8540b027ee720b75f353f594f834216d0" 1866 | dependencies = [ 1867 | "parking_lot", 1868 | ] 1869 | 1870 | [[package]] 1871 | name = "solana-big-mod-exp" 1872 | version = "3.0.0" 1873 | source = "registry+https://github.com/rust-lang/crates.io-index" 1874 | checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" 1875 | dependencies = [ 1876 | "num-bigint 0.4.6", 1877 | "num-traits", 1878 | "solana-define-syscall 3.0.0", 1879 | ] 1880 | 1881 | [[package]] 1882 | name = "solana-bincode" 1883 | version = "3.0.0" 1884 | source = "registry+https://github.com/rust-lang/crates.io-index" 1885 | checksum = "534a37aecd21986089224d0c01006a75b96ac6fb2f418c24edc15baf0d2a4c99" 1886 | dependencies = [ 1887 | "bincode", 1888 | "serde", 1889 | "solana-instruction-error", 1890 | ] 1891 | 1892 | [[package]] 1893 | name = "solana-blake3-hasher" 1894 | version = "3.0.0" 1895 | source = "registry+https://github.com/rust-lang/crates.io-index" 1896 | checksum = "ffa2e3bdac3339c6d0423275e45dafc5ac25f4d43bf344d026a3cc9a85e244a6" 1897 | dependencies = [ 1898 | "blake3", 1899 | "solana-define-syscall 3.0.0", 1900 | "solana-hash 3.1.0", 1901 | ] 1902 | 1903 | [[package]] 1904 | name = "solana-bn254" 1905 | version = "3.0.0" 1906 | source = "registry+https://github.com/rust-lang/crates.io-index" 1907 | checksum = "20a5f01e99addb316d95d4ed31aa6eacfda557fffc00ae316b919e8ba0fc5b91" 1908 | dependencies = [ 1909 | "ark-bn254", 1910 | "ark-ec", 1911 | "ark-ff", 1912 | "ark-serialize", 1913 | "bytemuck", 1914 | "solana-define-syscall 3.0.0", 1915 | "thiserror 2.0.17", 1916 | ] 1917 | 1918 | [[package]] 1919 | name = "solana-borsh" 1920 | version = "3.0.0" 1921 | source = "registry+https://github.com/rust-lang/crates.io-index" 1922 | checksum = "dc402b16657abbfa9991cd5cbfac5a11d809f7e7d28d3bb291baeb088b39060e" 1923 | dependencies = [ 1924 | "borsh", 1925 | ] 1926 | 1927 | [[package]] 1928 | name = "solana-bpf-loader-program" 1929 | version = "3.0.10" 1930 | source = "registry+https://github.com/rust-lang/crates.io-index" 1931 | checksum = "a5a2b7914cebd827003d2a1c21cc48bcad2c1857a9ec34656a2caa578707f53a" 1932 | dependencies = [ 1933 | "agave-syscalls", 1934 | "bincode", 1935 | "qualifier_attr", 1936 | "solana-account", 1937 | "solana-bincode", 1938 | "solana-clock", 1939 | "solana-instruction", 1940 | "solana-loader-v3-interface", 1941 | "solana-loader-v4-interface", 1942 | "solana-packet", 1943 | "solana-program-entrypoint", 1944 | "solana-program-runtime", 1945 | "solana-pubkey 3.0.0", 1946 | "solana-sbpf", 1947 | "solana-sdk-ids", 1948 | "solana-svm-feature-set", 1949 | "solana-svm-log-collector", 1950 | "solana-svm-measure", 1951 | "solana-svm-type-overrides", 1952 | "solana-system-interface 2.0.0", 1953 | "solana-transaction-context", 1954 | ] 1955 | 1956 | [[package]] 1957 | name = "solana-clock" 1958 | version = "3.0.0" 1959 | source = "registry+https://github.com/rust-lang/crates.io-index" 1960 | checksum = "fb62e9381182459a4520b5fe7fb22d423cae736239a6427fc398a88743d0ed59" 1961 | dependencies = [ 1962 | "serde", 1963 | "serde_derive", 1964 | "solana-sdk-ids", 1965 | "solana-sdk-macro", 1966 | "solana-sysvar-id", 1967 | ] 1968 | 1969 | [[package]] 1970 | name = "solana-compute-budget" 1971 | version = "3.0.10" 1972 | source = "registry+https://github.com/rust-lang/crates.io-index" 1973 | checksum = "df3b2d4cca7050320d13653ab369e21a0573b4a4f5dd82c509b0640e87f34d84" 1974 | dependencies = [ 1975 | "solana-fee-structure", 1976 | "solana-program-runtime", 1977 | ] 1978 | 1979 | [[package]] 1980 | name = "solana-cpi" 1981 | version = "3.1.0" 1982 | source = "registry+https://github.com/rust-lang/crates.io-index" 1983 | checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" 1984 | dependencies = [ 1985 | "solana-account-info", 1986 | "solana-define-syscall 4.0.1", 1987 | "solana-instruction", 1988 | "solana-program-error", 1989 | "solana-pubkey 4.0.0", 1990 | "solana-stable-layout", 1991 | ] 1992 | 1993 | [[package]] 1994 | name = "solana-curve25519" 1995 | version = "2.3.7" 1996 | source = "registry+https://github.com/rust-lang/crates.io-index" 1997 | checksum = "b162f50499b391b785d57b2f2c73e3b9754d88fd4894bef444960b00bda8dcca" 1998 | dependencies = [ 1999 | "bytemuck", 2000 | "bytemuck_derive", 2001 | "curve25519-dalek", 2002 | "solana-define-syscall 2.3.0", 2003 | "subtle", 2004 | "thiserror 2.0.17", 2005 | ] 2006 | 2007 | [[package]] 2008 | name = "solana-curve25519" 2009 | version = "3.0.10" 2010 | source = "registry+https://github.com/rust-lang/crates.io-index" 2011 | checksum = "be2ca224d51d8a1cc20f221706968d8f851586e6b05937cb518bedc156596dee" 2012 | dependencies = [ 2013 | "bytemuck", 2014 | "bytemuck_derive", 2015 | "curve25519-dalek", 2016 | "solana-define-syscall 3.0.0", 2017 | "subtle", 2018 | "thiserror 2.0.17", 2019 | ] 2020 | 2021 | [[package]] 2022 | name = "solana-define-syscall" 2023 | version = "2.3.0" 2024 | source = "registry+https://github.com/rust-lang/crates.io-index" 2025 | checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" 2026 | 2027 | [[package]] 2028 | name = "solana-define-syscall" 2029 | version = "3.0.0" 2030 | source = "registry+https://github.com/rust-lang/crates.io-index" 2031 | checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" 2032 | 2033 | [[package]] 2034 | name = "solana-define-syscall" 2035 | version = "4.0.1" 2036 | source = "registry+https://github.com/rust-lang/crates.io-index" 2037 | checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" 2038 | 2039 | [[package]] 2040 | name = "solana-derivation-path" 2041 | version = "3.0.0" 2042 | source = "registry+https://github.com/rust-lang/crates.io-index" 2043 | checksum = "ff71743072690fdbdfcdc37700ae1cb77485aaad49019473a81aee099b1e0b8c" 2044 | dependencies = [ 2045 | "derivation-path", 2046 | "qstring", 2047 | "uriparse", 2048 | ] 2049 | 2050 | [[package]] 2051 | name = "solana-epoch-rewards" 2052 | version = "3.0.0" 2053 | source = "registry+https://github.com/rust-lang/crates.io-index" 2054 | checksum = "b319a4ed70390af911090c020571f0ff1f4ec432522d05ab89f5c08080381995" 2055 | dependencies = [ 2056 | "serde", 2057 | "serde_derive", 2058 | "solana-hash 3.1.0", 2059 | "solana-sdk-ids", 2060 | "solana-sdk-macro", 2061 | "solana-sysvar-id", 2062 | ] 2063 | 2064 | [[package]] 2065 | name = "solana-epoch-schedule" 2066 | version = "3.0.0" 2067 | source = "registry+https://github.com/rust-lang/crates.io-index" 2068 | checksum = "6e5481e72cc4d52c169db73e4c0cd16de8bc943078aac587ec4817a75cc6388f" 2069 | dependencies = [ 2070 | "serde", 2071 | "serde_derive", 2072 | "solana-sdk-ids", 2073 | "solana-sdk-macro", 2074 | "solana-sysvar-id", 2075 | ] 2076 | 2077 | [[package]] 2078 | name = "solana-fee-calculator" 2079 | version = "3.0.0" 2080 | source = "registry+https://github.com/rust-lang/crates.io-index" 2081 | checksum = "2a73cc03ca4bed871ca174558108835f8323e85917bb38b9c81c7af2ab853efe" 2082 | dependencies = [ 2083 | "log", 2084 | "serde", 2085 | "serde_derive", 2086 | ] 2087 | 2088 | [[package]] 2089 | name = "solana-fee-structure" 2090 | version = "3.0.0" 2091 | source = "registry+https://github.com/rust-lang/crates.io-index" 2092 | checksum = "5e2abdb1223eea8ec64136f39cb1ffcf257e00f915c957c35c0dd9e3f4e700b0" 2093 | 2094 | [[package]] 2095 | name = "solana-hash" 2096 | version = "3.1.0" 2097 | source = "registry+https://github.com/rust-lang/crates.io-index" 2098 | checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" 2099 | dependencies = [ 2100 | "solana-hash 4.0.1", 2101 | ] 2102 | 2103 | [[package]] 2104 | name = "solana-hash" 2105 | version = "4.0.1" 2106 | source = "registry+https://github.com/rust-lang/crates.io-index" 2107 | checksum = "6a5d48a6ee7b91fc7b998944ab026ed7b3e2fc8ee3bc58452644a86c2648152f" 2108 | dependencies = [ 2109 | "borsh", 2110 | "bytemuck", 2111 | "bytemuck_derive", 2112 | "five8 1.0.0", 2113 | "serde", 2114 | "serde_derive", 2115 | "solana-atomic-u64", 2116 | "solana-sanitize", 2117 | ] 2118 | 2119 | [[package]] 2120 | name = "solana-instruction" 2121 | version = "3.1.0" 2122 | source = "registry+https://github.com/rust-lang/crates.io-index" 2123 | checksum = "ee1b699a2c1518028a9982e255e0eca10c44d90006542d9d7f9f40dbce3f7c78" 2124 | dependencies = [ 2125 | "bincode", 2126 | "borsh", 2127 | "serde", 2128 | "serde_derive", 2129 | "solana-define-syscall 4.0.1", 2130 | "solana-instruction-error", 2131 | "solana-pubkey 4.0.0", 2132 | ] 2133 | 2134 | [[package]] 2135 | name = "solana-instruction-error" 2136 | version = "2.0.0" 2137 | source = "registry+https://github.com/rust-lang/crates.io-index" 2138 | checksum = "b1f0d483b8ae387178d9210e0575b666b05cdd4bd0f2f188128249f6e454d39d" 2139 | dependencies = [ 2140 | "num-traits", 2141 | "serde", 2142 | "serde_derive", 2143 | "solana-program-error", 2144 | ] 2145 | 2146 | [[package]] 2147 | name = "solana-instructions-sysvar" 2148 | version = "3.0.0" 2149 | source = "registry+https://github.com/rust-lang/crates.io-index" 2150 | checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" 2151 | dependencies = [ 2152 | "bitflags", 2153 | "solana-account-info", 2154 | "solana-instruction", 2155 | "solana-instruction-error", 2156 | "solana-program-error", 2157 | "solana-pubkey 3.0.0", 2158 | "solana-sanitize", 2159 | "solana-sdk-ids", 2160 | "solana-serialize-utils", 2161 | "solana-sysvar-id", 2162 | ] 2163 | 2164 | [[package]] 2165 | name = "solana-keccak-hasher" 2166 | version = "3.0.0" 2167 | source = "registry+https://github.com/rust-lang/crates.io-index" 2168 | checksum = "57eebd3012946913c8c1b8b43cdf8a6249edb09c0b6be3604ae910332a3acd97" 2169 | dependencies = [ 2170 | "sha3", 2171 | "solana-define-syscall 3.0.0", 2172 | "solana-hash 3.1.0", 2173 | ] 2174 | 2175 | [[package]] 2176 | name = "solana-keypair" 2177 | version = "3.1.0" 2178 | source = "registry+https://github.com/rust-lang/crates.io-index" 2179 | checksum = "5ac8be597c9e231b0cab2928ce3bc3e4ee77d9c0ad92977b9d901f3879f25a7a" 2180 | dependencies = [ 2181 | "ed25519-dalek", 2182 | "five8 1.0.0", 2183 | "rand 0.8.5", 2184 | "solana-address 2.0.0", 2185 | "solana-seed-phrase", 2186 | "solana-signature", 2187 | "solana-signer", 2188 | ] 2189 | 2190 | [[package]] 2191 | name = "solana-last-restart-slot" 2192 | version = "3.0.0" 2193 | source = "registry+https://github.com/rust-lang/crates.io-index" 2194 | checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" 2195 | dependencies = [ 2196 | "serde", 2197 | "serde_derive", 2198 | "solana-sdk-ids", 2199 | "solana-sdk-macro", 2200 | "solana-sysvar-id", 2201 | ] 2202 | 2203 | [[package]] 2204 | name = "solana-loader-v3-interface" 2205 | version = "6.1.0" 2206 | source = "registry+https://github.com/rust-lang/crates.io-index" 2207 | checksum = "dee44c9b1328c5c712c68966fb8de07b47f3e7bac006e74ddd1bb053d3e46e5d" 2208 | dependencies = [ 2209 | "serde", 2210 | "serde_bytes", 2211 | "serde_derive", 2212 | "solana-instruction", 2213 | "solana-pubkey 3.0.0", 2214 | "solana-sdk-ids", 2215 | ] 2216 | 2217 | [[package]] 2218 | name = "solana-loader-v4-interface" 2219 | version = "3.1.0" 2220 | source = "registry+https://github.com/rust-lang/crates.io-index" 2221 | checksum = "e4c948b33ff81fa89699911b207059e493defdba9647eaf18f23abdf3674e0fb" 2222 | dependencies = [ 2223 | "serde", 2224 | "serde_bytes", 2225 | "serde_derive", 2226 | "solana-instruction", 2227 | "solana-pubkey 3.0.0", 2228 | "solana-sdk-ids", 2229 | "solana-system-interface 2.0.0", 2230 | ] 2231 | 2232 | [[package]] 2233 | name = "solana-logger" 2234 | version = "3.0.0" 2235 | source = "registry+https://github.com/rust-lang/crates.io-index" 2236 | checksum = "ef7421d1092680d72065edbf5c7605856719b021bf5f173656c71febcdd5d003" 2237 | dependencies = [ 2238 | "env_logger", 2239 | "lazy_static", 2240 | "libc", 2241 | "log", 2242 | "signal-hook", 2243 | ] 2244 | 2245 | [[package]] 2246 | name = "solana-message" 2247 | version = "3.0.0" 2248 | source = "registry+https://github.com/rust-lang/crates.io-index" 2249 | checksum = "2c33e9fa7871147ac3235a7320386afa2dc64bbb21ca3cf9d79a6f6827313176" 2250 | dependencies = [ 2251 | "lazy_static", 2252 | "solana-hash 3.1.0", 2253 | "solana-instruction", 2254 | "solana-pubkey 3.0.0", 2255 | "solana-sanitize", 2256 | "solana-sdk-ids", 2257 | "solana-transaction-error", 2258 | ] 2259 | 2260 | [[package]] 2261 | name = "solana-msg" 2262 | version = "3.0.0" 2263 | source = "registry+https://github.com/rust-lang/crates.io-index" 2264 | checksum = "264275c556ea7e22b9d3f87d56305546a38d4eee8ec884f3b126236cb7dcbbb4" 2265 | dependencies = [ 2266 | "solana-define-syscall 3.0.0", 2267 | ] 2268 | 2269 | [[package]] 2270 | name = "solana-nonce" 2271 | version = "3.0.0" 2272 | source = "registry+https://github.com/rust-lang/crates.io-index" 2273 | checksum = "abbdc6c8caf1c08db9f36a50967539d0f72b9f1d4aea04fec5430f532e5afadc" 2274 | dependencies = [ 2275 | "serde", 2276 | "serde_derive", 2277 | "solana-fee-calculator", 2278 | "solana-hash 3.1.0", 2279 | "solana-pubkey 3.0.0", 2280 | "solana-sha256-hasher", 2281 | ] 2282 | 2283 | [[package]] 2284 | name = "solana-nonce-account" 2285 | version = "3.0.0" 2286 | source = "registry+https://github.com/rust-lang/crates.io-index" 2287 | checksum = "805fd25b29e5a1a0e6c3dd6320c9da80f275fbe4ff6e392617c303a2085c435e" 2288 | dependencies = [ 2289 | "solana-account", 2290 | "solana-hash 3.1.0", 2291 | "solana-nonce", 2292 | "solana-sdk-ids", 2293 | ] 2294 | 2295 | [[package]] 2296 | name = "solana-packet" 2297 | version = "3.0.0" 2298 | source = "registry+https://github.com/rust-lang/crates.io-index" 2299 | checksum = "6edf2f25743c95229ac0fdc32f8f5893ef738dbf332c669e9861d33ddb0f469d" 2300 | dependencies = [ 2301 | "bitflags", 2302 | ] 2303 | 2304 | [[package]] 2305 | name = "solana-poseidon" 2306 | version = "3.0.10" 2307 | source = "registry+https://github.com/rust-lang/crates.io-index" 2308 | checksum = "794ff76c70d6f4c5d9c86c626069225c0066043405c0c9d6b96f00c8525dade5" 2309 | dependencies = [ 2310 | "ark-bn254", 2311 | "light-poseidon", 2312 | "solana-define-syscall 3.0.0", 2313 | "thiserror 2.0.17", 2314 | ] 2315 | 2316 | [[package]] 2317 | name = "solana-precompile-error" 2318 | version = "3.0.0" 2319 | source = "registry+https://github.com/rust-lang/crates.io-index" 2320 | checksum = "cafcd950de74c6c39d55dc8ca108bbb007799842ab370ef26cf45a34453c31e1" 2321 | dependencies = [ 2322 | "num-traits", 2323 | ] 2324 | 2325 | [[package]] 2326 | name = "solana-program-entrypoint" 2327 | version = "3.1.1" 2328 | source = "registry+https://github.com/rust-lang/crates.io-index" 2329 | checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" 2330 | dependencies = [ 2331 | "solana-account-info", 2332 | "solana-define-syscall 4.0.1", 2333 | "solana-program-error", 2334 | "solana-pubkey 4.0.0", 2335 | ] 2336 | 2337 | [[package]] 2338 | name = "solana-program-error" 2339 | version = "3.0.0" 2340 | source = "registry+https://github.com/rust-lang/crates.io-index" 2341 | checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" 2342 | dependencies = [ 2343 | "borsh", 2344 | ] 2345 | 2346 | [[package]] 2347 | name = "solana-program-memory" 2348 | version = "3.0.0" 2349 | source = "registry+https://github.com/rust-lang/crates.io-index" 2350 | checksum = "10e5660c60749c7bfb30b447542529758e4dbcecd31b1e8af1fdc92e2bdde90a" 2351 | dependencies = [ 2352 | "solana-define-syscall 3.0.0", 2353 | ] 2354 | 2355 | [[package]] 2356 | name = "solana-program-option" 2357 | version = "3.0.0" 2358 | source = "registry+https://github.com/rust-lang/crates.io-index" 2359 | checksum = "8e7b4ddb464f274deb4a497712664c3b612e3f5f82471d4e47710fc4ab1c3095" 2360 | 2361 | [[package]] 2362 | name = "solana-program-pack" 2363 | version = "3.0.0" 2364 | source = "registry+https://github.com/rust-lang/crates.io-index" 2365 | checksum = "c169359de21f6034a63ebf96d6b380980307df17a8d371344ff04a883ec4e9d0" 2366 | dependencies = [ 2367 | "solana-program-error", 2368 | ] 2369 | 2370 | [[package]] 2371 | name = "solana-program-runtime" 2372 | version = "3.0.10" 2373 | source = "registry+https://github.com/rust-lang/crates.io-index" 2374 | checksum = "8d6ec3fec9e5f8c01aa76e0d63911af6acb4ee840b6f7ec5ddee284552c0de60" 2375 | dependencies = [ 2376 | "base64 0.22.1", 2377 | "bincode", 2378 | "itertools 0.12.1", 2379 | "log", 2380 | "percentage", 2381 | "rand 0.8.5", 2382 | "serde", 2383 | "solana-account", 2384 | "solana-clock", 2385 | "solana-epoch-rewards", 2386 | "solana-epoch-schedule", 2387 | "solana-fee-structure", 2388 | "solana-hash 3.1.0", 2389 | "solana-instruction", 2390 | "solana-last-restart-slot", 2391 | "solana-program-entrypoint", 2392 | "solana-pubkey 3.0.0", 2393 | "solana-rent", 2394 | "solana-sbpf", 2395 | "solana-sdk-ids", 2396 | "solana-slot-hashes", 2397 | "solana-stake-interface", 2398 | "solana-svm-callback", 2399 | "solana-svm-feature-set", 2400 | "solana-svm-log-collector", 2401 | "solana-svm-measure", 2402 | "solana-svm-timings", 2403 | "solana-svm-transaction", 2404 | "solana-svm-type-overrides", 2405 | "solana-system-interface 2.0.0", 2406 | "solana-sysvar", 2407 | "solana-sysvar-id", 2408 | "solana-transaction-context", 2409 | ] 2410 | 2411 | [[package]] 2412 | name = "solana-pubkey" 2413 | version = "3.0.0" 2414 | source = "registry+https://github.com/rust-lang/crates.io-index" 2415 | checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" 2416 | dependencies = [ 2417 | "solana-address 1.1.0", 2418 | ] 2419 | 2420 | [[package]] 2421 | name = "solana-pubkey" 2422 | version = "4.0.0" 2423 | source = "registry+https://github.com/rust-lang/crates.io-index" 2424 | checksum = "a6f7104d456b58e1418c21a8581e89810278d1190f70f27ece7fc0b2c9282a57" 2425 | dependencies = [ 2426 | "solana-address 2.0.0", 2427 | ] 2428 | 2429 | [[package]] 2430 | name = "solana-rent" 2431 | version = "3.1.0" 2432 | source = "registry+https://github.com/rust-lang/crates.io-index" 2433 | checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" 2434 | dependencies = [ 2435 | "serde", 2436 | "serde_derive", 2437 | "solana-sdk-ids", 2438 | "solana-sdk-macro", 2439 | "solana-sysvar-id", 2440 | ] 2441 | 2442 | [[package]] 2443 | name = "solana-sanitize" 2444 | version = "3.0.0" 2445 | source = "registry+https://github.com/rust-lang/crates.io-index" 2446 | checksum = "927e833259588ac8f860861db0f6e2668c3cc46d917798ade116858960acfe8a" 2447 | 2448 | [[package]] 2449 | name = "solana-sbpf" 2450 | version = "0.12.2" 2451 | source = "registry+https://github.com/rust-lang/crates.io-index" 2452 | checksum = "0f224d906c14efc7ed7f42bc5fe9588f3f09db8cabe7f6023adda62a69678e1a" 2453 | dependencies = [ 2454 | "byteorder", 2455 | "combine", 2456 | "hash32", 2457 | "libc", 2458 | "log", 2459 | "rand 0.8.5", 2460 | "rustc-demangle", 2461 | "thiserror 2.0.17", 2462 | "winapi", 2463 | ] 2464 | 2465 | [[package]] 2466 | name = "solana-sdk-ids" 2467 | version = "3.1.0" 2468 | source = "registry+https://github.com/rust-lang/crates.io-index" 2469 | checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" 2470 | dependencies = [ 2471 | "solana-address 2.0.0", 2472 | ] 2473 | 2474 | [[package]] 2475 | name = "solana-sdk-macro" 2476 | version = "3.0.0" 2477 | source = "registry+https://github.com/rust-lang/crates.io-index" 2478 | checksum = "d6430000e97083460b71d9fbadc52a2ab2f88f53b3a4c5e58c5ae3640a0e8c00" 2479 | dependencies = [ 2480 | "bs58", 2481 | "proc-macro2", 2482 | "quote", 2483 | "syn 2.0.106", 2484 | ] 2485 | 2486 | [[package]] 2487 | name = "solana-secp256k1-recover" 2488 | version = "3.0.0" 2489 | source = "registry+https://github.com/rust-lang/crates.io-index" 2490 | checksum = "394a4470477d66296af5217970a905b1c5569032a7732c367fb69e5666c8607e" 2491 | dependencies = [ 2492 | "k256", 2493 | "solana-define-syscall 3.0.0", 2494 | "thiserror 2.0.17", 2495 | ] 2496 | 2497 | [[package]] 2498 | name = "solana-seed-derivable" 2499 | version = "3.0.0" 2500 | source = "registry+https://github.com/rust-lang/crates.io-index" 2501 | checksum = "ff7bdb72758e3bec33ed0e2658a920f1f35dfb9ed576b951d20d63cb61ecd95c" 2502 | dependencies = [ 2503 | "solana-derivation-path", 2504 | ] 2505 | 2506 | [[package]] 2507 | name = "solana-seed-phrase" 2508 | version = "3.0.0" 2509 | source = "registry+https://github.com/rust-lang/crates.io-index" 2510 | checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" 2511 | dependencies = [ 2512 | "hmac", 2513 | "pbkdf2", 2514 | "sha2 0.10.9", 2515 | ] 2516 | 2517 | [[package]] 2518 | name = "solana-serialize-utils" 2519 | version = "3.0.0" 2520 | source = "registry+https://github.com/rust-lang/crates.io-index" 2521 | checksum = "e7665da4f6e07b58c93ef6aaf9fb6a923fd11b0922ffc53ba74c3cadfa490f26" 2522 | dependencies = [ 2523 | "solana-instruction-error", 2524 | "solana-pubkey 3.0.0", 2525 | "solana-sanitize", 2526 | ] 2527 | 2528 | [[package]] 2529 | name = "solana-sha256-hasher" 2530 | version = "3.0.0" 2531 | source = "registry+https://github.com/rust-lang/crates.io-index" 2532 | checksum = "a9b912ba6f71cb202c0c3773ec77bf898fa9fe0c78691a2d6859b3b5b8954719" 2533 | dependencies = [ 2534 | "sha2 0.10.9", 2535 | "solana-define-syscall 3.0.0", 2536 | "solana-hash 3.1.0", 2537 | ] 2538 | 2539 | [[package]] 2540 | name = "solana-signature" 2541 | version = "3.1.0" 2542 | source = "registry+https://github.com/rust-lang/crates.io-index" 2543 | checksum = "4bb8057cc0e9f7b5e89883d49de6f407df655bb6f3a71d0b7baf9986a2218fd9" 2544 | dependencies = [ 2545 | "ed25519-dalek", 2546 | "five8 0.2.1", 2547 | "solana-sanitize", 2548 | ] 2549 | 2550 | [[package]] 2551 | name = "solana-signer" 2552 | version = "3.0.0" 2553 | source = "registry+https://github.com/rust-lang/crates.io-index" 2554 | checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" 2555 | dependencies = [ 2556 | "solana-pubkey 3.0.0", 2557 | "solana-signature", 2558 | "solana-transaction-error", 2559 | ] 2560 | 2561 | [[package]] 2562 | name = "solana-slot-hashes" 2563 | version = "3.0.0" 2564 | source = "registry+https://github.com/rust-lang/crates.io-index" 2565 | checksum = "80a293f952293281443c04f4d96afd9d547721923d596e92b4377ed2360f1746" 2566 | dependencies = [ 2567 | "serde", 2568 | "serde_derive", 2569 | "solana-hash 3.1.0", 2570 | "solana-sdk-ids", 2571 | "solana-sysvar-id", 2572 | ] 2573 | 2574 | [[package]] 2575 | name = "solana-slot-history" 2576 | version = "3.0.0" 2577 | source = "registry+https://github.com/rust-lang/crates.io-index" 2578 | checksum = "f914f6b108f5bba14a280b458d023e3621c9973f27f015a4d755b50e88d89e97" 2579 | dependencies = [ 2580 | "bv", 2581 | "serde", 2582 | "serde_derive", 2583 | "solana-sdk-ids", 2584 | "solana-sysvar-id", 2585 | ] 2586 | 2587 | [[package]] 2588 | name = "solana-stable-layout" 2589 | version = "3.0.0" 2590 | source = "registry+https://github.com/rust-lang/crates.io-index" 2591 | checksum = "1da74507795b6e8fb60b7c7306c0c36e2c315805d16eaaf479452661234685ac" 2592 | dependencies = [ 2593 | "solana-instruction", 2594 | "solana-pubkey 3.0.0", 2595 | ] 2596 | 2597 | [[package]] 2598 | name = "solana-stake-interface" 2599 | version = "2.0.1" 2600 | source = "registry+https://github.com/rust-lang/crates.io-index" 2601 | checksum = "f6f912ae679b683365348dea482dbd9468d22ff258b554fd36e3d3683c2122e3" 2602 | dependencies = [ 2603 | "num-traits", 2604 | "serde", 2605 | "serde_derive", 2606 | "solana-clock", 2607 | "solana-cpi", 2608 | "solana-instruction", 2609 | "solana-program-error", 2610 | "solana-pubkey 3.0.0", 2611 | "solana-system-interface 2.0.0", 2612 | "solana-sysvar", 2613 | "solana-sysvar-id", 2614 | ] 2615 | 2616 | [[package]] 2617 | name = "solana-svm-callback" 2618 | version = "3.0.10" 2619 | source = "registry+https://github.com/rust-lang/crates.io-index" 2620 | checksum = "8d2211ecefc92a3d6db1206eca32aa579bb112eb1a2823ac227d8cbd5cdb0465" 2621 | dependencies = [ 2622 | "solana-account", 2623 | "solana-clock", 2624 | "solana-precompile-error", 2625 | "solana-pubkey 3.0.0", 2626 | ] 2627 | 2628 | [[package]] 2629 | name = "solana-svm-feature-set" 2630 | version = "3.0.10" 2631 | source = "registry+https://github.com/rust-lang/crates.io-index" 2632 | checksum = "6a35cded5bc9e32d84c98d81bb9811239d3aea03d0f5ef09aa2f1e8cdaf2d0ff" 2633 | 2634 | [[package]] 2635 | name = "solana-svm-log-collector" 2636 | version = "3.0.10" 2637 | source = "registry+https://github.com/rust-lang/crates.io-index" 2638 | checksum = "455455f9ef91bb738c2363284cd8b6f5956726b0a366ab85976dca23ee1611a4" 2639 | dependencies = [ 2640 | "log", 2641 | ] 2642 | 2643 | [[package]] 2644 | name = "solana-svm-measure" 2645 | version = "3.0.10" 2646 | source = "registry+https://github.com/rust-lang/crates.io-index" 2647 | checksum = "3e3c0ecb1caf08e9d70e41ca99bb18550e05e9a40dce8866fd1c360e67fa78c5" 2648 | 2649 | [[package]] 2650 | name = "solana-svm-timings" 2651 | version = "3.0.10" 2652 | source = "registry+https://github.com/rust-lang/crates.io-index" 2653 | checksum = "62606f820fe99b72ee8e26b8e20eed3c2ccc2f6e3146f537c4cb22a442c69170" 2654 | dependencies = [ 2655 | "eager", 2656 | "enum-iterator", 2657 | "solana-pubkey 3.0.0", 2658 | ] 2659 | 2660 | [[package]] 2661 | name = "solana-svm-transaction" 2662 | version = "3.0.10" 2663 | source = "registry+https://github.com/rust-lang/crates.io-index" 2664 | checksum = "336583f8418964f7050b98996e13151857995604fe057c0d8f2f3512a16d3a8b" 2665 | dependencies = [ 2666 | "solana-hash 3.1.0", 2667 | "solana-message", 2668 | "solana-pubkey 3.0.0", 2669 | "solana-sdk-ids", 2670 | "solana-signature", 2671 | "solana-transaction", 2672 | ] 2673 | 2674 | [[package]] 2675 | name = "solana-svm-type-overrides" 2676 | version = "3.0.10" 2677 | source = "registry+https://github.com/rust-lang/crates.io-index" 2678 | checksum = "f802b43ced1f9c6a2bf3b8c740dd43e194f33b3c98a6b3e3d0f989f632ec3ccc" 2679 | dependencies = [ 2680 | "rand 0.8.5", 2681 | ] 2682 | 2683 | [[package]] 2684 | name = "solana-system-interface" 2685 | version = "2.0.0" 2686 | source = "registry+https://github.com/rust-lang/crates.io-index" 2687 | checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" 2688 | dependencies = [ 2689 | "num-traits", 2690 | "serde", 2691 | "serde_derive", 2692 | "solana-instruction", 2693 | "solana-msg", 2694 | "solana-program-error", 2695 | "solana-pubkey 3.0.0", 2696 | ] 2697 | 2698 | [[package]] 2699 | name = "solana-system-interface" 2700 | version = "3.0.0" 2701 | source = "registry+https://github.com/rust-lang/crates.io-index" 2702 | checksum = "14591d6508042ebefb110305d3ba761615927146a26917ade45dc332d8e1ecde" 2703 | dependencies = [ 2704 | "num-traits", 2705 | "serde", 2706 | "serde_derive", 2707 | "solana-address 2.0.0", 2708 | "solana-instruction", 2709 | "solana-msg", 2710 | "solana-program-error", 2711 | ] 2712 | 2713 | [[package]] 2714 | name = "solana-system-program" 2715 | version = "3.0.10" 2716 | source = "registry+https://github.com/rust-lang/crates.io-index" 2717 | checksum = "b4c68c4e74ea2d55e59cab3346781156c456850a781f07cb6bc0fdbd52fba55b" 2718 | dependencies = [ 2719 | "bincode", 2720 | "log", 2721 | "serde", 2722 | "serde_derive", 2723 | "solana-account", 2724 | "solana-bincode", 2725 | "solana-fee-calculator", 2726 | "solana-instruction", 2727 | "solana-nonce", 2728 | "solana-nonce-account", 2729 | "solana-packet", 2730 | "solana-program-runtime", 2731 | "solana-pubkey 3.0.0", 2732 | "solana-sdk-ids", 2733 | "solana-svm-log-collector", 2734 | "solana-svm-type-overrides", 2735 | "solana-system-interface 2.0.0", 2736 | "solana-sysvar", 2737 | "solana-transaction-context", 2738 | ] 2739 | 2740 | [[package]] 2741 | name = "solana-sysvar" 2742 | version = "3.1.1" 2743 | source = "registry+https://github.com/rust-lang/crates.io-index" 2744 | checksum = "6690d3dd88f15c21edff68eb391ef8800df7a1f5cec84ee3e8d1abf05affdf74" 2745 | dependencies = [ 2746 | "base64 0.22.1", 2747 | "bincode", 2748 | "lazy_static", 2749 | "serde", 2750 | "serde_derive", 2751 | "solana-account-info", 2752 | "solana-clock", 2753 | "solana-define-syscall 4.0.1", 2754 | "solana-epoch-rewards", 2755 | "solana-epoch-schedule", 2756 | "solana-fee-calculator", 2757 | "solana-hash 4.0.1", 2758 | "solana-instruction", 2759 | "solana-last-restart-slot", 2760 | "solana-program-entrypoint", 2761 | "solana-program-error", 2762 | "solana-program-memory", 2763 | "solana-pubkey 4.0.0", 2764 | "solana-rent", 2765 | "solana-sdk-ids", 2766 | "solana-sdk-macro", 2767 | "solana-slot-hashes", 2768 | "solana-slot-history", 2769 | "solana-sysvar-id", 2770 | ] 2771 | 2772 | [[package]] 2773 | name = "solana-sysvar-id" 2774 | version = "3.0.0" 2775 | source = "registry+https://github.com/rust-lang/crates.io-index" 2776 | checksum = "5051bc1a16d5d96a96bc33b5b2ec707495c48fe978097bdaba68d3c47987eb32" 2777 | dependencies = [ 2778 | "solana-pubkey 3.0.0", 2779 | "solana-sdk-ids", 2780 | ] 2781 | 2782 | [[package]] 2783 | name = "solana-transaction" 2784 | version = "3.0.0" 2785 | source = "registry+https://github.com/rust-lang/crates.io-index" 2786 | checksum = "2db6ac3984042d9248fd9b06761ece438ed9ba412c001240052ce6216fee3141" 2787 | dependencies = [ 2788 | "solana-hash 3.1.0", 2789 | "solana-instruction", 2790 | "solana-message", 2791 | "solana-pubkey 3.0.0", 2792 | "solana-sanitize", 2793 | "solana-sdk-ids", 2794 | "solana-signature", 2795 | "solana-transaction-error", 2796 | ] 2797 | 2798 | [[package]] 2799 | name = "solana-transaction-context" 2800 | version = "3.0.10" 2801 | source = "registry+https://github.com/rust-lang/crates.io-index" 2802 | checksum = "f9c6820c3a14bd07b2256640bd64af4a44ac49f505dca93cc11f77bc79cfd44a" 2803 | dependencies = [ 2804 | "bincode", 2805 | "qualifier_attr", 2806 | "serde", 2807 | "serde_derive", 2808 | "solana-account", 2809 | "solana-instruction", 2810 | "solana-instructions-sysvar", 2811 | "solana-pubkey 3.0.0", 2812 | "solana-rent", 2813 | "solana-sbpf", 2814 | "solana-sdk-ids", 2815 | ] 2816 | 2817 | [[package]] 2818 | name = "solana-transaction-error" 2819 | version = "3.0.0" 2820 | source = "registry+https://github.com/rust-lang/crates.io-index" 2821 | checksum = "4222065402340d7e6aec9dc3e54d22992ddcf923d91edcd815443c2bfca3144a" 2822 | dependencies = [ 2823 | "solana-instruction-error", 2824 | "solana-sanitize", 2825 | ] 2826 | 2827 | [[package]] 2828 | name = "solana-zk-sdk" 2829 | version = "4.0.0" 2830 | source = "registry+https://github.com/rust-lang/crates.io-index" 2831 | checksum = "9602bcb1f7af15caef92b91132ec2347e1c51a72ecdbefdaefa3eac4b8711475" 2832 | dependencies = [ 2833 | "aes-gcm-siv", 2834 | "base64 0.22.1", 2835 | "bincode", 2836 | "bytemuck", 2837 | "bytemuck_derive", 2838 | "curve25519-dalek", 2839 | "getrandom 0.2.16", 2840 | "itertools 0.12.1", 2841 | "js-sys", 2842 | "merlin", 2843 | "num-derive", 2844 | "num-traits", 2845 | "rand 0.8.5", 2846 | "serde", 2847 | "serde_derive", 2848 | "serde_json", 2849 | "sha3", 2850 | "solana-derivation-path", 2851 | "solana-instruction", 2852 | "solana-pubkey 3.0.0", 2853 | "solana-sdk-ids", 2854 | "solana-seed-derivable", 2855 | "solana-seed-phrase", 2856 | "solana-signature", 2857 | "solana-signer", 2858 | "subtle", 2859 | "thiserror 2.0.17", 2860 | "wasm-bindgen", 2861 | "zeroize", 2862 | ] 2863 | 2864 | [[package]] 2865 | name = "spki" 2866 | version = "0.7.3" 2867 | source = "registry+https://github.com/rust-lang/crates.io-index" 2868 | checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" 2869 | dependencies = [ 2870 | "base64ct", 2871 | "der", 2872 | ] 2873 | 2874 | [[package]] 2875 | name = "spl-associated-token-account" 2876 | version = "8.0.0" 2877 | dependencies = [ 2878 | "borsh", 2879 | "mollusk-svm", 2880 | "num-derive", 2881 | "num-traits", 2882 | "solana-account-info", 2883 | "solana-cpi", 2884 | "solana-instruction", 2885 | "solana-keypair", 2886 | "solana-msg", 2887 | "solana-program-entrypoint", 2888 | "solana-program-error", 2889 | "solana-pubkey 4.0.0", 2890 | "solana-rent", 2891 | "solana-sdk-ids", 2892 | "solana-signer", 2893 | "solana-system-interface 3.0.0", 2894 | "solana-sysvar", 2895 | "spl-associated-token-account-interface 2.0.0", 2896 | "spl-associated-token-account-mollusk-harness", 2897 | "spl-token-2022-interface", 2898 | "spl-token-interface", 2899 | "thiserror 2.0.17", 2900 | ] 2901 | 2902 | [[package]] 2903 | name = "spl-associated-token-account-interface" 2904 | version = "2.0.0" 2905 | dependencies = [ 2906 | "borsh", 2907 | "solana-instruction", 2908 | "solana-pubkey 4.0.0", 2909 | "solana-sdk-ids", 2910 | ] 2911 | 2912 | [[package]] 2913 | name = "spl-associated-token-account-interface" 2914 | version = "2.0.0" 2915 | source = "registry+https://github.com/rust-lang/crates.io-index" 2916 | checksum = "e6433917b60441d68d99a17e121d9db0ea15a9a69c0e5afa34649cf5ba12612f" 2917 | dependencies = [ 2918 | "solana-instruction", 2919 | "solana-pubkey 3.0.0", 2920 | ] 2921 | 2922 | [[package]] 2923 | name = "spl-associated-token-account-mollusk-harness" 2924 | version = "1.0.0" 2925 | dependencies = [ 2926 | "mollusk-svm", 2927 | "mollusk-svm-programs-token", 2928 | "solana-account", 2929 | "solana-instruction", 2930 | "solana-keypair", 2931 | "solana-program-error", 2932 | "solana-program-option", 2933 | "solana-program-pack", 2934 | "solana-pubkey 4.0.0", 2935 | "solana-rent", 2936 | "solana-signer", 2937 | "solana-system-interface 3.0.0", 2938 | "solana-sysvar", 2939 | "spl-associated-token-account-interface 2.0.0", 2940 | "spl-token-2022-interface", 2941 | "spl-token-interface", 2942 | ] 2943 | 2944 | [[package]] 2945 | name = "spl-discriminator" 2946 | version = "0.5.1" 2947 | source = "registry+https://github.com/rust-lang/crates.io-index" 2948 | checksum = "d48cc11459e265d5b501534144266620289720b4c44522a47bc6b63cd295d2f3" 2949 | dependencies = [ 2950 | "bytemuck", 2951 | "solana-program-error", 2952 | "solana-sha256-hasher", 2953 | "spl-discriminator-derive", 2954 | ] 2955 | 2956 | [[package]] 2957 | name = "spl-discriminator-derive" 2958 | version = "0.2.0" 2959 | source = "registry+https://github.com/rust-lang/crates.io-index" 2960 | checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" 2961 | dependencies = [ 2962 | "quote", 2963 | "spl-discriminator-syn", 2964 | "syn 2.0.106", 2965 | ] 2966 | 2967 | [[package]] 2968 | name = "spl-discriminator-syn" 2969 | version = "0.2.1" 2970 | source = "registry+https://github.com/rust-lang/crates.io-index" 2971 | checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" 2972 | dependencies = [ 2973 | "proc-macro2", 2974 | "quote", 2975 | "sha2 0.10.9", 2976 | "syn 2.0.106", 2977 | "thiserror 1.0.69", 2978 | ] 2979 | 2980 | [[package]] 2981 | name = "spl-pod" 2982 | version = "0.7.1" 2983 | source = "registry+https://github.com/rust-lang/crates.io-index" 2984 | checksum = "b1233fdecd7461611d69bb87bc2e95af742df47291975d21232a0be8217da9de" 2985 | dependencies = [ 2986 | "borsh", 2987 | "bytemuck", 2988 | "bytemuck_derive", 2989 | "num-derive", 2990 | "num-traits", 2991 | "num_enum", 2992 | "solana-program-error", 2993 | "solana-program-option", 2994 | "solana-pubkey 3.0.0", 2995 | "solana-zk-sdk", 2996 | "thiserror 2.0.17", 2997 | ] 2998 | 2999 | [[package]] 3000 | name = "spl-token-2022-interface" 3001 | version = "2.1.0" 3002 | source = "registry+https://github.com/rust-lang/crates.io-index" 3003 | checksum = "2fcd81188211f4b3c8a5eba7fd534c7142f9dd026123b3472492782cc72f4dc6" 3004 | dependencies = [ 3005 | "arrayref", 3006 | "bytemuck", 3007 | "num-derive", 3008 | "num-traits", 3009 | "num_enum", 3010 | "solana-account-info", 3011 | "solana-instruction", 3012 | "solana-program-error", 3013 | "solana-program-option", 3014 | "solana-program-pack", 3015 | "solana-pubkey 3.0.0", 3016 | "solana-sdk-ids", 3017 | "solana-zk-sdk", 3018 | "spl-pod", 3019 | "spl-token-confidential-transfer-proof-extraction", 3020 | "spl-token-confidential-transfer-proof-generation", 3021 | "spl-token-group-interface", 3022 | "spl-token-metadata-interface", 3023 | "spl-type-length-value", 3024 | "thiserror 2.0.17", 3025 | ] 3026 | 3027 | [[package]] 3028 | name = "spl-token-confidential-transfer-proof-extraction" 3029 | version = "0.5.0" 3030 | source = "registry+https://github.com/rust-lang/crates.io-index" 3031 | checksum = "7a22217af69b7a61ca813f47c018afb0b00b02a74a4c70ff099cd4287740bc3d" 3032 | dependencies = [ 3033 | "bytemuck", 3034 | "solana-account-info", 3035 | "solana-curve25519 2.3.7", 3036 | "solana-instruction", 3037 | "solana-instructions-sysvar", 3038 | "solana-msg", 3039 | "solana-program-error", 3040 | "solana-pubkey 3.0.0", 3041 | "solana-sdk-ids", 3042 | "solana-zk-sdk", 3043 | "spl-pod", 3044 | "thiserror 2.0.17", 3045 | ] 3046 | 3047 | [[package]] 3048 | name = "spl-token-confidential-transfer-proof-generation" 3049 | version = "0.5.0" 3050 | source = "registry+https://github.com/rust-lang/crates.io-index" 3051 | checksum = "f63a2b41095945dc15274b924b21ccae9b3ec9dc2fdd43dbc08de8c33bbcd915" 3052 | dependencies = [ 3053 | "curve25519-dalek", 3054 | "solana-zk-sdk", 3055 | "thiserror 2.0.17", 3056 | ] 3057 | 3058 | [[package]] 3059 | name = "spl-token-group-interface" 3060 | version = "0.7.1" 3061 | source = "registry+https://github.com/rust-lang/crates.io-index" 3062 | checksum = "452d0f758af20caaa10d9a6f7608232e000d4c74462f248540b3d2ddfa419776" 3063 | dependencies = [ 3064 | "bytemuck", 3065 | "num-derive", 3066 | "num-traits", 3067 | "num_enum", 3068 | "solana-instruction", 3069 | "solana-program-error", 3070 | "solana-pubkey 3.0.0", 3071 | "spl-discriminator", 3072 | "spl-pod", 3073 | "thiserror 2.0.17", 3074 | ] 3075 | 3076 | [[package]] 3077 | name = "spl-token-interface" 3078 | version = "2.0.0" 3079 | source = "registry+https://github.com/rust-lang/crates.io-index" 3080 | checksum = "8c564ac05a7c8d8b12e988a37d82695b5ba4db376d07ea98bc4882c81f96c7f3" 3081 | dependencies = [ 3082 | "arrayref", 3083 | "bytemuck", 3084 | "num-derive", 3085 | "num-traits", 3086 | "num_enum", 3087 | "solana-instruction", 3088 | "solana-program-error", 3089 | "solana-program-option", 3090 | "solana-program-pack", 3091 | "solana-pubkey 3.0.0", 3092 | "solana-sdk-ids", 3093 | "thiserror 2.0.17", 3094 | ] 3095 | 3096 | [[package]] 3097 | name = "spl-token-metadata-interface" 3098 | version = "0.8.0" 3099 | source = "registry+https://github.com/rust-lang/crates.io-index" 3100 | checksum = "9c467c7c3bd056f8fe60119e7ec34ddd6f23052c2fa8f1f51999098063b72676" 3101 | dependencies = [ 3102 | "borsh", 3103 | "num-derive", 3104 | "num-traits", 3105 | "solana-borsh", 3106 | "solana-instruction", 3107 | "solana-program-error", 3108 | "solana-pubkey 3.0.0", 3109 | "spl-discriminator", 3110 | "spl-pod", 3111 | "spl-type-length-value", 3112 | "thiserror 2.0.17", 3113 | ] 3114 | 3115 | [[package]] 3116 | name = "spl-type-length-value" 3117 | version = "0.9.0" 3118 | source = "registry+https://github.com/rust-lang/crates.io-index" 3119 | checksum = "ca20a1a19f4507a98ca4b28ff5ed54cac9b9d34ed27863e2bde50a3238f9a6ac" 3120 | dependencies = [ 3121 | "bytemuck", 3122 | "num-derive", 3123 | "num-traits", 3124 | "num_enum", 3125 | "solana-account-info", 3126 | "solana-msg", 3127 | "solana-program-error", 3128 | "spl-discriminator", 3129 | "spl-pod", 3130 | "thiserror 2.0.17", 3131 | ] 3132 | 3133 | [[package]] 3134 | name = "subtle" 3135 | version = "2.6.1" 3136 | source = "registry+https://github.com/rust-lang/crates.io-index" 3137 | checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" 3138 | 3139 | [[package]] 3140 | name = "syn" 3141 | version = "1.0.109" 3142 | source = "registry+https://github.com/rust-lang/crates.io-index" 3143 | checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" 3144 | dependencies = [ 3145 | "proc-macro2", 3146 | "quote", 3147 | "unicode-ident", 3148 | ] 3149 | 3150 | [[package]] 3151 | name = "syn" 3152 | version = "2.0.106" 3153 | source = "registry+https://github.com/rust-lang/crates.io-index" 3154 | checksum = "ede7c438028d4436d71104916910f5bb611972c5cfd7f89b8300a8186e6fada6" 3155 | dependencies = [ 3156 | "proc-macro2", 3157 | "quote", 3158 | "unicode-ident", 3159 | ] 3160 | 3161 | [[package]] 3162 | name = "thiserror" 3163 | version = "1.0.69" 3164 | source = "registry+https://github.com/rust-lang/crates.io-index" 3165 | checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" 3166 | dependencies = [ 3167 | "thiserror-impl 1.0.69", 3168 | ] 3169 | 3170 | [[package]] 3171 | name = "thiserror" 3172 | version = "2.0.17" 3173 | source = "registry+https://github.com/rust-lang/crates.io-index" 3174 | checksum = "f63587ca0f12b72a0600bcba1d40081f830876000bb46dd2337a3051618f4fc8" 3175 | dependencies = [ 3176 | "thiserror-impl 2.0.17", 3177 | ] 3178 | 3179 | [[package]] 3180 | name = "thiserror-impl" 3181 | version = "1.0.69" 3182 | source = "registry+https://github.com/rust-lang/crates.io-index" 3183 | checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" 3184 | dependencies = [ 3185 | "proc-macro2", 3186 | "quote", 3187 | "syn 2.0.106", 3188 | ] 3189 | 3190 | [[package]] 3191 | name = "thiserror-impl" 3192 | version = "2.0.17" 3193 | source = "registry+https://github.com/rust-lang/crates.io-index" 3194 | checksum = "3ff15c8ecd7de3849db632e14d18d2571fa09dfc5ed93479bc4485c7a517c913" 3195 | dependencies = [ 3196 | "proc-macro2", 3197 | "quote", 3198 | "syn 2.0.106", 3199 | ] 3200 | 3201 | [[package]] 3202 | name = "tinyvec" 3203 | version = "1.10.0" 3204 | source = "registry+https://github.com/rust-lang/crates.io-index" 3205 | checksum = "bfa5fdc3bce6191a1dbc8c02d5c8bffcf557bafa17c124c5264a458f1b0613fa" 3206 | dependencies = [ 3207 | "tinyvec_macros", 3208 | ] 3209 | 3210 | [[package]] 3211 | name = "tinyvec_macros" 3212 | version = "0.1.1" 3213 | source = "registry+https://github.com/rust-lang/crates.io-index" 3214 | checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" 3215 | 3216 | [[package]] 3217 | name = "toml_datetime" 3218 | version = "0.6.11" 3219 | source = "registry+https://github.com/rust-lang/crates.io-index" 3220 | checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" 3221 | 3222 | [[package]] 3223 | name = "toml_edit" 3224 | version = "0.22.27" 3225 | source = "registry+https://github.com/rust-lang/crates.io-index" 3226 | checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" 3227 | dependencies = [ 3228 | "indexmap", 3229 | "toml_datetime", 3230 | "winnow", 3231 | ] 3232 | 3233 | [[package]] 3234 | name = "typenum" 3235 | version = "1.18.0" 3236 | source = "registry+https://github.com/rust-lang/crates.io-index" 3237 | checksum = "1dccffe3ce07af9386bfd29e80c0ab1a8205a2fc34e4bcd40364df902cfa8f3f" 3238 | 3239 | [[package]] 3240 | name = "unicode-ident" 3241 | version = "1.0.18" 3242 | source = "registry+https://github.com/rust-lang/crates.io-index" 3243 | checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" 3244 | 3245 | [[package]] 3246 | name = "universal-hash" 3247 | version = "0.5.1" 3248 | source = "registry+https://github.com/rust-lang/crates.io-index" 3249 | checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" 3250 | dependencies = [ 3251 | "crypto-common", 3252 | "subtle", 3253 | ] 3254 | 3255 | [[package]] 3256 | name = "unreachable" 3257 | version = "1.0.0" 3258 | source = "registry+https://github.com/rust-lang/crates.io-index" 3259 | checksum = "382810877fe448991dfc7f0dd6e3ae5d58088fd0ea5e35189655f84e6814fa56" 3260 | dependencies = [ 3261 | "void", 3262 | ] 3263 | 3264 | [[package]] 3265 | name = "uriparse" 3266 | version = "0.6.4" 3267 | source = "registry+https://github.com/rust-lang/crates.io-index" 3268 | checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff" 3269 | dependencies = [ 3270 | "fnv", 3271 | "lazy_static", 3272 | ] 3273 | 3274 | [[package]] 3275 | name = "utf8parse" 3276 | version = "0.2.2" 3277 | source = "registry+https://github.com/rust-lang/crates.io-index" 3278 | checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" 3279 | 3280 | [[package]] 3281 | name = "version_check" 3282 | version = "0.9.5" 3283 | source = "registry+https://github.com/rust-lang/crates.io-index" 3284 | checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" 3285 | 3286 | [[package]] 3287 | name = "void" 3288 | version = "1.0.2" 3289 | source = "registry+https://github.com/rust-lang/crates.io-index" 3290 | checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" 3291 | 3292 | [[package]] 3293 | name = "wasi" 3294 | version = "0.9.0+wasi-snapshot-preview1" 3295 | source = "registry+https://github.com/rust-lang/crates.io-index" 3296 | checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" 3297 | 3298 | [[package]] 3299 | name = "wasi" 3300 | version = "0.11.1+wasi-snapshot-preview1" 3301 | source = "registry+https://github.com/rust-lang/crates.io-index" 3302 | checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" 3303 | 3304 | [[package]] 3305 | name = "wasi" 3306 | version = "0.14.2+wasi-0.2.4" 3307 | source = "registry+https://github.com/rust-lang/crates.io-index" 3308 | checksum = "9683f9a5a998d873c0d21fcbe3c083009670149a8fab228644b8bd36b2c48cb3" 3309 | dependencies = [ 3310 | "wit-bindgen-rt", 3311 | ] 3312 | 3313 | [[package]] 3314 | name = "wasm-bindgen" 3315 | version = "0.2.100" 3316 | source = "registry+https://github.com/rust-lang/crates.io-index" 3317 | checksum = "1edc8929d7499fc4e8f0be2262a241556cfc54a0bea223790e71446f2aab1ef5" 3318 | dependencies = [ 3319 | "cfg-if", 3320 | "once_cell", 3321 | "rustversion", 3322 | "wasm-bindgen-macro", 3323 | ] 3324 | 3325 | [[package]] 3326 | name = "wasm-bindgen-backend" 3327 | version = "0.2.100" 3328 | source = "registry+https://github.com/rust-lang/crates.io-index" 3329 | checksum = "2f0a0651a5c2bc21487bde11ee802ccaf4c51935d0d3d42a6101f98161700bc6" 3330 | dependencies = [ 3331 | "bumpalo", 3332 | "log", 3333 | "proc-macro2", 3334 | "quote", 3335 | "syn 2.0.106", 3336 | "wasm-bindgen-shared", 3337 | ] 3338 | 3339 | [[package]] 3340 | name = "wasm-bindgen-macro" 3341 | version = "0.2.100" 3342 | source = "registry+https://github.com/rust-lang/crates.io-index" 3343 | checksum = "7fe63fc6d09ed3792bd0897b314f53de8e16568c2b3f7982f468c0bf9bd0b407" 3344 | dependencies = [ 3345 | "quote", 3346 | "wasm-bindgen-macro-support", 3347 | ] 3348 | 3349 | [[package]] 3350 | name = "wasm-bindgen-macro-support" 3351 | version = "0.2.100" 3352 | source = "registry+https://github.com/rust-lang/crates.io-index" 3353 | checksum = "8ae87ea40c9f689fc23f209965b6fb8a99ad69aeeb0231408be24920604395de" 3354 | dependencies = [ 3355 | "proc-macro2", 3356 | "quote", 3357 | "syn 2.0.106", 3358 | "wasm-bindgen-backend", 3359 | "wasm-bindgen-shared", 3360 | ] 3361 | 3362 | [[package]] 3363 | name = "wasm-bindgen-shared" 3364 | version = "0.2.100" 3365 | source = "registry+https://github.com/rust-lang/crates.io-index" 3366 | checksum = "1a05d73b933a847d6cccdda8f838a22ff101ad9bf93e33684f39c1f5f0eece3d" 3367 | dependencies = [ 3368 | "unicode-ident", 3369 | ] 3370 | 3371 | [[package]] 3372 | name = "winapi" 3373 | version = "0.3.9" 3374 | source = "registry+https://github.com/rust-lang/crates.io-index" 3375 | checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" 3376 | dependencies = [ 3377 | "winapi-i686-pc-windows-gnu", 3378 | "winapi-x86_64-pc-windows-gnu", 3379 | ] 3380 | 3381 | [[package]] 3382 | name = "winapi-i686-pc-windows-gnu" 3383 | version = "0.4.0" 3384 | source = "registry+https://github.com/rust-lang/crates.io-index" 3385 | checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" 3386 | 3387 | [[package]] 3388 | name = "winapi-x86_64-pc-windows-gnu" 3389 | version = "0.4.0" 3390 | source = "registry+https://github.com/rust-lang/crates.io-index" 3391 | checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" 3392 | 3393 | [[package]] 3394 | name = "windows-link" 3395 | version = "0.1.3" 3396 | source = "registry+https://github.com/rust-lang/crates.io-index" 3397 | checksum = "5e6ad25900d524eaabdbbb96d20b4311e1e7ae1699af4fb28c17ae66c80d798a" 3398 | 3399 | [[package]] 3400 | name = "windows-sys" 3401 | version = "0.60.2" 3402 | source = "registry+https://github.com/rust-lang/crates.io-index" 3403 | checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" 3404 | dependencies = [ 3405 | "windows-targets 0.53.3", 3406 | ] 3407 | 3408 | [[package]] 3409 | name = "windows-targets" 3410 | version = "0.52.6" 3411 | source = "registry+https://github.com/rust-lang/crates.io-index" 3412 | checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" 3413 | dependencies = [ 3414 | "windows_aarch64_gnullvm 0.52.6", 3415 | "windows_aarch64_msvc 0.52.6", 3416 | "windows_i686_gnu 0.52.6", 3417 | "windows_i686_gnullvm 0.52.6", 3418 | "windows_i686_msvc 0.52.6", 3419 | "windows_x86_64_gnu 0.52.6", 3420 | "windows_x86_64_gnullvm 0.52.6", 3421 | "windows_x86_64_msvc 0.52.6", 3422 | ] 3423 | 3424 | [[package]] 3425 | name = "windows-targets" 3426 | version = "0.53.3" 3427 | source = "registry+https://github.com/rust-lang/crates.io-index" 3428 | checksum = "d5fe6031c4041849d7c496a8ded650796e7b6ecc19df1a431c1a363342e5dc91" 3429 | dependencies = [ 3430 | "windows-link", 3431 | "windows_aarch64_gnullvm 0.53.0", 3432 | "windows_aarch64_msvc 0.53.0", 3433 | "windows_i686_gnu 0.53.0", 3434 | "windows_i686_gnullvm 0.53.0", 3435 | "windows_i686_msvc 0.53.0", 3436 | "windows_x86_64_gnu 0.53.0", 3437 | "windows_x86_64_gnullvm 0.53.0", 3438 | "windows_x86_64_msvc 0.53.0", 3439 | ] 3440 | 3441 | [[package]] 3442 | name = "windows_aarch64_gnullvm" 3443 | version = "0.52.6" 3444 | source = "registry+https://github.com/rust-lang/crates.io-index" 3445 | checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" 3446 | 3447 | [[package]] 3448 | name = "windows_aarch64_gnullvm" 3449 | version = "0.53.0" 3450 | source = "registry+https://github.com/rust-lang/crates.io-index" 3451 | checksum = "86b8d5f90ddd19cb4a147a5fa63ca848db3df085e25fee3cc10b39b6eebae764" 3452 | 3453 | [[package]] 3454 | name = "windows_aarch64_msvc" 3455 | version = "0.52.6" 3456 | source = "registry+https://github.com/rust-lang/crates.io-index" 3457 | checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" 3458 | 3459 | [[package]] 3460 | name = "windows_aarch64_msvc" 3461 | version = "0.53.0" 3462 | source = "registry+https://github.com/rust-lang/crates.io-index" 3463 | checksum = "c7651a1f62a11b8cbd5e0d42526e55f2c99886c77e007179efff86c2b137e66c" 3464 | 3465 | [[package]] 3466 | name = "windows_i686_gnu" 3467 | version = "0.52.6" 3468 | source = "registry+https://github.com/rust-lang/crates.io-index" 3469 | checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" 3470 | 3471 | [[package]] 3472 | name = "windows_i686_gnu" 3473 | version = "0.53.0" 3474 | source = "registry+https://github.com/rust-lang/crates.io-index" 3475 | checksum = "c1dc67659d35f387f5f6c479dc4e28f1d4bb90ddd1a5d3da2e5d97b42d6272c3" 3476 | 3477 | [[package]] 3478 | name = "windows_i686_gnullvm" 3479 | version = "0.52.6" 3480 | source = "registry+https://github.com/rust-lang/crates.io-index" 3481 | checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" 3482 | 3483 | [[package]] 3484 | name = "windows_i686_gnullvm" 3485 | version = "0.53.0" 3486 | source = "registry+https://github.com/rust-lang/crates.io-index" 3487 | checksum = "9ce6ccbdedbf6d6354471319e781c0dfef054c81fbc7cf83f338a4296c0cae11" 3488 | 3489 | [[package]] 3490 | name = "windows_i686_msvc" 3491 | version = "0.52.6" 3492 | source = "registry+https://github.com/rust-lang/crates.io-index" 3493 | checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" 3494 | 3495 | [[package]] 3496 | name = "windows_i686_msvc" 3497 | version = "0.53.0" 3498 | source = "registry+https://github.com/rust-lang/crates.io-index" 3499 | checksum = "581fee95406bb13382d2f65cd4a908ca7b1e4c2f1917f143ba16efe98a589b5d" 3500 | 3501 | [[package]] 3502 | name = "windows_x86_64_gnu" 3503 | version = "0.52.6" 3504 | source = "registry+https://github.com/rust-lang/crates.io-index" 3505 | checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" 3506 | 3507 | [[package]] 3508 | name = "windows_x86_64_gnu" 3509 | version = "0.53.0" 3510 | source = "registry+https://github.com/rust-lang/crates.io-index" 3511 | checksum = "2e55b5ac9ea33f2fc1716d1742db15574fd6fc8dadc51caab1c16a3d3b4190ba" 3512 | 3513 | [[package]] 3514 | name = "windows_x86_64_gnullvm" 3515 | version = "0.52.6" 3516 | source = "registry+https://github.com/rust-lang/crates.io-index" 3517 | checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" 3518 | 3519 | [[package]] 3520 | name = "windows_x86_64_gnullvm" 3521 | version = "0.53.0" 3522 | source = "registry+https://github.com/rust-lang/crates.io-index" 3523 | checksum = "0a6e035dd0599267ce1ee132e51c27dd29437f63325753051e71dd9e42406c57" 3524 | 3525 | [[package]] 3526 | name = "windows_x86_64_msvc" 3527 | version = "0.52.6" 3528 | source = "registry+https://github.com/rust-lang/crates.io-index" 3529 | checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" 3530 | 3531 | [[package]] 3532 | name = "windows_x86_64_msvc" 3533 | version = "0.53.0" 3534 | source = "registry+https://github.com/rust-lang/crates.io-index" 3535 | checksum = "271414315aff87387382ec3d271b52d7ae78726f5d44ac98b4f4030c91880486" 3536 | 3537 | [[package]] 3538 | name = "winnow" 3539 | version = "0.7.13" 3540 | source = "registry+https://github.com/rust-lang/crates.io-index" 3541 | checksum = "21a0236b59786fed61e2a80582dd500fe61f18b5dca67a4a067d0bc9039339cf" 3542 | dependencies = [ 3543 | "memchr", 3544 | ] 3545 | 3546 | [[package]] 3547 | name = "wit-bindgen-rt" 3548 | version = "0.39.0" 3549 | source = "registry+https://github.com/rust-lang/crates.io-index" 3550 | checksum = "6f42320e61fe2cfd34354ecb597f86f413484a798ba44a8ca1165c58d42da6c1" 3551 | dependencies = [ 3552 | "bitflags", 3553 | ] 3554 | 3555 | [[package]] 3556 | name = "zerocopy" 3557 | version = "0.8.26" 3558 | source = "registry+https://github.com/rust-lang/crates.io-index" 3559 | checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" 3560 | dependencies = [ 3561 | "zerocopy-derive", 3562 | ] 3563 | 3564 | [[package]] 3565 | name = "zerocopy-derive" 3566 | version = "0.8.26" 3567 | source = "registry+https://github.com/rust-lang/crates.io-index" 3568 | checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" 3569 | dependencies = [ 3570 | "proc-macro2", 3571 | "quote", 3572 | "syn 2.0.106", 3573 | ] 3574 | 3575 | [[package]] 3576 | name = "zeroize" 3577 | version = "1.8.1" 3578 | source = "registry+https://github.com/rust-lang/crates.io-index" 3579 | checksum = "ced3678a2879b30306d323f4542626697a464a97c0a07c9aebf7ebca65cd4dde" 3580 | dependencies = [ 3581 | "zeroize_derive", 3582 | ] 3583 | 3584 | [[package]] 3585 | name = "zeroize_derive" 3586 | version = "1.4.2" 3587 | source = "registry+https://github.com/rust-lang/crates.io-index" 3588 | checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" 3589 | dependencies = [ 3590 | "proc-macro2", 3591 | "quote", 3592 | "syn 2.0.106", 3593 | ] 3594 | --------------------------------------------------------------------------------