diff --git a/.github/actions/setup-ts/action.yaml b/.github/actions/setup-ts/action.yaml index 590f6a68a1..6e058cb788 100644 --- a/.github/actions/setup-ts/action.yaml +++ b/.github/actions/setup-ts/action.yaml @@ -22,6 +22,8 @@ runs: key: solana-${{ runner.os }}-v0000-${{ env.NODE_VERSION }}-${{ hashFiles('./ts/**/*.ts') }} - run: cd ts/packages/borsh && yarn --frozen-lockfile && yarn build && yarn link && cd ../../../ shell: bash + - run: cd ts/packages/anchor-errors && yarn --frozen-lockfile && yarn build && yarn link && cd ../../../ + shell: bash - run: cd ts/packages/anchor && yarn --frozen-lockfile && yarn build:node && yarn link && cd ../../../ shell: bash - run: cd ts/packages/spl-associated-token-account && yarn --frozen-lockfile && yarn build:node && yarn link && cd ../../../ diff --git a/.github/actions/setup/action.yaml b/.github/actions/setup/action.yaml index 1ac983c81f..7a88f31154 100644 --- a/.github/actions/setup/action.yaml +++ b/.github/actions/setup/action.yaml @@ -3,9 +3,9 @@ description: "Setup" runs: using: "composite" steps: - - run: sudo apt-get update && sudo apt-get install -y pkg-config build-essential libudev-dev - shell: bash - - run: echo "ANCHOR_VERSION=$(cat ./VERSION)" >> $GITHUB_ENV - shell: bash - - run: git submodule update --init --recursive --depth 1 - shell: bash + - run: sudo apt-get update && sudo apt-get install -y pkg-config build-essential libudev-dev + shell: bash + - run: echo "ANCHOR_VERSION=$(cat ./VERSION)" >> $GITHUB_ENV + shell: bash + - run: git submodule update --init --recursive --depth 1 + shell: bash diff --git a/.github/workflows/no-caching-tests.yaml b/.github/workflows/no-caching-tests.yaml index e257985bd7..46464fd8ba 100644 --- a/.github/workflows/no-caching-tests.yaml +++ b/.github/workflows/no-caching-tests.yaml @@ -12,7 +12,7 @@ jobs: uses: ./.github/workflows/reusable-tests.yaml with: cache: false - solana_cli_version: 1.17.0 + solana_cli_version: 1.18.17 solang_version: 0.3.2 node_version: 18.18.0 cargo_profile: release diff --git a/.github/workflows/reusable-tests.yaml b/.github/workflows/reusable-tests.yaml index 47fcb067de..3a01ab8a5f 100644 --- a/.github/workflows/reusable-tests.yaml +++ b/.github/workflows/reusable-tests.yaml @@ -61,6 +61,7 @@ jobs: - run: cd avm && cargo fmt -- --check && cargo clippy --all-targets -- -D warnings && cargo test -- --test-threads=1 # Init local borsh package - run: cd ts/packages/borsh && yarn --frozen-lockfile && yarn build + - run: cd ts/packages/anchor-errors && yarn --frozen-lockfile && yarn build - run: cd ts/packages/anchor && yarn --frozen-lockfile - run: cd ts/packages/anchor && yarn test - run: cd ts/packages/anchor && yarn lint @@ -388,6 +389,8 @@ jobs: path: spl/token-wrapper - cmd: cd tests/spl/transfer-hook && anchor test --skip-lint path: spl/transfer-hook + - cmd: cd tests/spl/token-extensions && anchor test --skip-lint + path: spl/token-extensions - cmd: cd tests/multisig && anchor test --skip-lint path: tests/multisig # - cmd: cd tests/lockup && anchor test --skip-lint @@ -412,10 +415,16 @@ jobs: path: tests/cashiers-check - cmd: cd tests/declare-id && anchor test --skip-lint && npx tsc --noEmit path: tests/declare-id + - cmd: cd tests/declare-program && anchor test --skip-lint + path: tests/declare-program - cmd: cd tests/typescript && anchor test --skip-lint && npx tsc --noEmit path: tests/typescript - - cmd: cd tests/zero-copy && anchor test --skip-lint && cd programs/zero-copy && cargo test-sbf - path: tests/zero-copy + # zero-copy tests cause `/usr/bin/ld: final link failed: No space left on device` + # on GitHub runners. It is likely caused by `cargo test-sbf` since all other tests + # don't have this problem. + # TODO: Find a fix. + # - cmd: cd tests/zero-copy && anchor test --skip-lint && cd programs/zero-copy && cargo test-sbf + # path: tests/zero-copy - cmd: cd tests/chat && anchor test --skip-lint path: tests/chat - cmd: cd tests/ido-pool && anchor test --skip-lint @@ -430,6 +439,8 @@ jobs: path: tests/safety-checks - cmd: cd tests/custom-coder && anchor test --skip-lint && npx tsc --noEmit path: tests/custom-coder + - cmd: cd tests/custom-discriminator && anchor test + path: tests/custom-discriminator - cmd: cd tests/validator-clone && anchor test --skip-lint && npx tsc --noEmit path: tests/validator-clone - cmd: cd tests/cpi-returns && anchor test --skip-lint && npx tsc --noEmit @@ -452,8 +463,9 @@ jobs: path: tests/bench - cmd: cd tests/idl && ./test.sh path: tests/idl - - cmd: cd tests/solang && anchor test - path: tests/solang + # TODO: Enable when `solang` becomes compatible with the new IDL spec + # - cmd: cd tests/solang && anchor test + # path: tests/solang steps: - uses: actions/checkout@v3 - uses: ./.github/actions/setup/ diff --git a/.github/workflows/tests.yaml b/.github/workflows/tests.yaml index 409bf9f52f..57476681ac 100644 --- a/.github/workflows/tests.yaml +++ b/.github/workflows/tests.yaml @@ -15,7 +15,7 @@ jobs: uses: ./.github/workflows/reusable-tests.yaml with: cache: true - solana_cli_version: 1.17.0 + solana_cli_version: 1.18.17 solang_version: 0.3.2 node_version: 18.18.0 cargo_profile: debug diff --git a/.gitignore b/.gitignore index d41f3a7251..1867174070 100644 --- a/.gitignore +++ b/.gitignore @@ -10,6 +10,7 @@ target/ test-ledger examples/*/Cargo.lock examples/**/Cargo.lock +*/example/Cargo.lock tests/*/Cargo.lock tests/**/Cargo.lock tests/*/yarn.lock diff --git a/CHANGELOG.md b/CHANGELOG.md index 767c13a384..cf8682e3b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,115 @@ The minor version will be incremented upon a breaking change and the patch versi ### Features +- ts: Add optional `commitment` parameter to `Program.addEventListener` ([#3052](https://github.com/coral-xyz/anchor/pull/3052)). +- cli, idl: Pass `cargo` args to IDL generation when building program or IDL ([#3059](https://github.com/coral-xyz/anchor/pull/3059)). +- cli: Add checks for incorrect usage of `idl-build` feature ([#3061](https://github.com/coral-xyz/anchor/pull/3061)). +- lang: Export `Discriminator` trait from `prelude` ([#3075](https://github.com/coral-xyz/anchor/pull/3075)). +- lang: Add `Account` utility type to get accounts from bytes ([#3091](https://github.com/coral-xyz/anchor/pull/3091)). +- client: Add option to pass in mock rpc client when using anchor_client ([#3053](https://github.com/coral-xyz/anchor/pull/3053)). +- lang: Get discriminator length dynamically ([#3101](https://github.com/coral-xyz/anchor/pull/3101)). +- lang: Add non-8-byte discriminator support in `declare_program!` ([#3103](https://github.com/coral-xyz/anchor/pull/3103)). +- client: Make `ThreadSafeSigner` trait public ([#3107](https://github.com/coral-xyz/anchor/pull/3107)). +- lang: Update `dispatch` function to support dynamic discriminators ([#3104](https://github.com/coral-xyz/anchor/pull/3104)). +- lang: Remove the fallback function shortcut in `try_entry` function ([#3109](https://github.com/coral-xyz/anchor/pull/3109)). +- ts: Get discriminator lengths dynamically ([#3120](https://github.com/coral-xyz/anchor/pull/3120)). +- client: Support non-8-byte discriminators ([#3125](https://github.com/coral-xyz/anchor/pull/3125)). +- spl: Add `withdraw_withheld_tokens_from_accounts` instruction ([#3128]([https://github.com/coral-xyz/anchor/pull/3128)). +- ts: Add optional `wallet` property to the `Provider` interface ([#3130](https://github.com/coral-xyz/anchor/pull/3130)). +- cli: Warn if `anchor-spl/idl-build` is missing ([#3133](https://github.com/coral-xyz/anchor/pull/3133)). +- client: Add `internal_rpc` method for `mock` feature ([#3135](https://github.com/coral-xyz/anchor/pull/3135)). +- lang: Add `#[instruction]` attribute proc-macro to override default instruction discriminators ([#3137](https://github.com/coral-xyz/anchor/pull/3137)). +- lang: Use associated discriminator constants instead of hardcoding in `#[account]` ([#3144](https://github.com/coral-xyz/anchor/pull/3144)). +- lang: Add `discriminator` argument to `#[account]` attribute ([#3149](https://github.com/coral-xyz/anchor/pull/3149)). +- lang: Add `discriminator` argument to `#[event]` attribute ([#3152](https://github.com/coral-xyz/anchor/pull/3152)). +- idl: Check ambiguous discriminators ([#3157](https://github.com/coral-xyz/anchor/pull/3157)). +- idl: Disallow all zero account discriminators ([#3159](https://github.com/coral-xyz/anchor/pull/3159)). +- cli: Support non-8-byte discriminators ([#3165](https://github.com/coral-xyz/anchor/pull/3165)). +- idl: Disallow empty discriminators ([#3166](https://github.com/coral-xyz/anchor/pull/3166)). + +### Fixes + +- idl: Make safety comment checks fail silently when program path env is not set ([#3045](https://github.com/coral-xyz/anchor/pull/3045)). +- idl: Avoid interference from rust tests during IDL generation ([#3058](https://github.com/coral-xyz/anchor/pull/3058)). +- lang: Fix `align` repr support in `declare-program!` ([#3056](https://github.com/coral-xyz/anchor/pull/3056)). +- lang: Make stack frames slimmer on ATA creation ([#3065](https://github.com/coral-xyz/anchor/pull/3065)). +- lang: Remove `getrandom` dependency ([#3072](https://github.com/coral-xyz/anchor/pull/3072)). +- lang: Make `InitSpace` support unnamed & unit structs ([#3084](https://github.com/coral-xyz/anchor/pull/3084)). +- lang: Fix using `owner` constraint with `Box`ed accounts ([#3087](https://github.com/coral-xyz/anchor/pull/3087)). +- lang: Add a sanity check for unimplemented token extensions ([#3090](https://github.com/coral-xyz/anchor/pull/3090)). +- cli: Skip IDL checks if `--no-idl` option is passed ([#3093](https://github.com/coral-xyz/anchor/pull/3093)). +- lang: Remove unnecessary clone in account exit routine ([#3139](https://github.com/coral-xyz/anchor/pull/3139)). +- cli: Fix installation with `--locked` argument using Rust v1.80 due to `time` crate issue ([#3143](https://github.com/coral-xyz/anchor/pull/3143)). + +### Breaking + +- syn: Remove `bpf` target support in `hash` feature ([#3078](https://github.com/coral-xyz/anchor/pull/3078)). +- client: Add `tokio` support to `RequestBuilder` with `async` feature ([#3057](https://github.com/coral-xyz/anchor/pull/3057)). +- lang: Remove `EventData` trait ([#3083](https://github.com/coral-xyz/anchor/pull/3083)). +- client: Remove `async_rpc` method ([#3053](https://github.com/coral-xyz/anchor/pull/3053)). +- lang: Make discriminator type unsized ([#3098](https://github.com/coral-xyz/anchor/pull/3098)). +- lang: Require `Discriminator` trait impl when using the `zero` constraint ([#3118](https://github.com/coral-xyz/anchor/pull/3118)). +- ts: Remove `DISCRIMINATOR_SIZE` constant ([#3120](https://github.com/coral-xyz/anchor/pull/3120)). +- lang: `#[account]` attribute arguments no longer parses identifiers as namespaces ([#3140](https://github.com/coral-xyz/anchor/pull/3140)). +- spl: Rename metadata interface instruction fields from `token_program_id` to `program_id` ([#3076](https://github.com/coral-xyz/anchor/pull/3076)). +- lang, ts: Remove "8 byte" requirement from discriminator error messages ([#3161](https://github.com/coral-xyz/anchor/pull/3161)). +- lang: Remove `discriminator` method from `Discriminator` trait ([#3163](https://github.com/coral-xyz/anchor/pull/3163)). + +## [0.30.1] - 2024-06-20 + +### Features + +- idl: Allow overriding the idl build toolchain with the `RUSTUP_TOOLCHAIN` environment variable ([#2941](https://github.com/coral-xyz/anchor/pull/2941)). +- avm: Support customizing the installation location using `AVM_HOME` environment variable ([#2917](https://github.com/coral-xyz/anchor/pull/2917)). +- avm: Optimize `avm list` when GitHub API rate limits are reached ([#2962](https://github.com/coral-xyz/anchor/pull/2962)) +- idl, ts: Add accounts resolution for associated token accounts ([#2927](https://github.com/coral-xyz/anchor/pull/2927)). +- cli: Add `--no-install` option to the `init` command ([#2945](https://github.com/coral-xyz/anchor/pull/2945)). +- lang: Implement `TryFromIntError` for `Error` to be able to propagate integer conversion errors ([#2950](https://github.com/coral-xyz/anchor/pull/2950)). +- idl: Add ability to convert legacy IDLs ([#2986](https://github.com/coral-xyz/anchor/pull/2986)). +- ts: Extract Anchor error codes into their own package ([#2983](https://github.com/coral-xyz/anchor/pull/2983)). +- cli: Add additional solana arguments to the `upgrade` command ([#2998](https://github.com/coral-xyz/anchor/pull/2998)). +- spl: Export `spl-associated-token-account` crate ([#2999](https://github.com/coral-xyz/anchor/pull/2999)). +- lang: Support legacy IDLs with `declare_program!` ([#2997](https://github.com/coral-xyz/anchor/pull/2997)). +- cli: Add `idl convert` command ([#3009](https://github.com/coral-xyz/anchor/pull/3009)). +- cli: Add `idl type` command ([#3017](https://github.com/coral-xyz/anchor/pull/3017)). +- lang: Add `anchor_lang::pubkey` macro for declaring `Pubkey` const values ([#3021](https://github.com/coral-xyz/anchor/pull/3021)). +- cli: Sync program ids on the initial build ([#3023](https://github.com/coral-xyz/anchor/pull/3023)). +- idl: Remove `anchor-syn` dependency ([#3030](https://github.com/coral-xyz/anchor/pull/3030)). +- lang: Add `const` of program ID to `declare_id!` and `declare_program!` ([#3019](https://github.com/coral-xyz/anchor/pull/3019)). +- idl: Add separate spec crate ([#3036](https://github.com/coral-xyz/anchor/pull/3036)). + +### Fixes + +- lang: Eliminate variable allocations that build up stack space for token extension code generation ([#2913](https://github.com/coral-xyz/anchor/pull/2913)). +- ts: Fix incorrect `maxSupportedTransactionVersion` in `AnchorProvider.send*()` methods ([#2922](https://github.com/coral-xyz/anchor/pull/2922)). +- cli: Use npm's configured default license for new projects made with `anchor init` ([#2929](https://github.com/coral-xyz/anchor/pull/2929)). +- cli: add filename to 'Unable to read keypair file' errors ([#2932](https://github.com/coral-xyz/anchor/pull/2932)). +- idl: Fix path resolution of the `Cargo.lock` of the project when generating idls for external types ([#2946](https://github.com/coral-xyz/anchor/pull/2946)). +- idl: Fix potential panic on external type resolution ([#2954](https://github.com/coral-xyz/anchor/pull/2954)). +- lang: Fix using defined types in instruction parameters with `declare_program!` ([#2959](https://github.com/coral-xyz/anchor/pull/2959)). +- lang: Fix using const generics with `declare_program!` ([#2965](https://github.com/coral-xyz/anchor/pull/2965)). +- lang: Fix using `Vec` type with `declare_program!` ([#2966](https://github.com/coral-xyz/anchor/pull/2966)). +- lang: Fix `ProgramError::ArithmeticOverflow` not found error ([#2975](https://github.com/coral-xyz/anchor/pull/2975)). +- lang: Fix using optional accounts with `declare_program!` ([#2967](https://github.com/coral-xyz/anchor/pull/2967)). +- lang: Fix instruction return type generation with `declare_program!` ([#2977](https://github.com/coral-xyz/anchor/pull/2977)). +- cli: Fix IDL write getting corrupted from retries ([#2964](https://github.com/coral-xyz/anchor/pull/2964)). +- idl: Fix `unexpected_cfgs` build warning ([#2992](https://github.com/coral-xyz/anchor/pull/2992)). +- lang: Make tuple struct fields public in `declare_program!` ([#2994](https://github.com/coral-xyz/anchor/pull/2994)). +- Remove `rust-version` from crate manifests ([#3000](https://github.com/coral-xyz/anchor/pull/3000)). +- cli: Fix upgradeable program clones ([#3010](https://github.com/coral-xyz/anchor/pull/3010)). +- ts: Fix using IDLs that have defined types as generic arguments ([#3016](https://github.com/coral-xyz/anchor/pull/3016)). +- idl: Fix generation with unsupported expressions ([#3033](https://github.com/coral-xyz/anchor/pull/3033)). +- idl: Fix using `address` constraint with field expressions ([#3034](https://github.com/coral-xyz/anchor/pull/3034)). +- lang: Fix using `bytemuckunsafe` account serialization with `declare_program!` ([#3037](https://github.com/coral-xyz/anchor/pull/3037)). + +### Breaking + +## [0.30.0] - 2024-04-15 + +See the [Anchor 0.30 release notes](https://www.anchor-lang.com/release-notes/0.30.0) for a high-level overview of how to update. + +### Features + - cli: Allow force `init` and `new` ([#2698](https://github.com/coral-xyz/anchor/pull/2698)). - cli: Add verifiable option when `deploy` ([#2705](https://github.com/coral-xyz/anchor/pull/2705)). - cli: Add support for passing arguments to the underlying `solana program deploy` command with `anchor deploy` ([#2709](https://github.com/coral-xyz/anchor/pull/2709)). @@ -19,10 +128,32 @@ The minor version will be incremented upon a breaking change and the patch versi - lang: Add `#[interface(..)]` attribute for instruction discriminator overrides ([#2728](https://github.com/coral-xyz/anchor/pull/2728)). - ts: Add `.interface(..)` method for instruction discriminator overrides ([#2728](https://github.com/coral-xyz/anchor/pull/2728)). - cli: Check `anchor-lang` and CLI version compatibility ([#2753](https://github.com/coral-xyz/anchor/pull/2753)). -- ts: Add IdlSeed Type for IDL PDA seeds ([#2752](https://github.com/coral-xyz/anchor/pull/2752)). +- ts: Add missing IDL PDA seed types ([#2752](https://github.com/coral-xyz/anchor/pull/2752)). - cli: `idl close` accepts optional `--idl-address` parameter ([#2760](https://github.com/coral-xyz/anchor/pull/2760)). - cli: Add support for simple wildcard patterns in Anchor.toml's `workspace.members` and `workspace.exclude`. ([#2785](https://github.com/coral-xyz/anchor/pull/2785)). +- cli: Add `--test-template` option for `init` command ([#2805](https://github.com/coral-xyz/anchor/pull/2805)). - cli: `anchor test` is able to run multiple commands ([#2799](https://github.com/coral-xyz/anchor/pull/2799)). +- cli: Check `@coral-xyz/anchor` package and CLI version compatibility ([#2813](https://github.com/coral-xyz/anchor/pull/2813)). +- cli: Accept package name as program name ([#2816](https://github.com/coral-xyz/anchor/pull/2816)). +- cli: Add ability to build and test only a specified program ([#2823](https://github.com/coral-xyz/anchor/pull/2823)). +- idl: Add new IDL spec ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Add support for `repr`s ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Add support for expression evaluation ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Add support for using external types when generating the IDL ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl, ts: Add unit and tuple struct support ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl, ts: Add generics support ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Add `accountsPartial` method to keep the old `accounts` method behavior ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Make `opts` parameter of `AnchorProvider` constructor optional ([#2843](https://github.com/coral-xyz/anchor/pull/2843)). +- cli: Add `--no-idl` flag to the `build` command ([#2847](https://github.com/coral-xyz/anchor/pull/2847)). +- cli: Add priority fees to idl commands ([#2845](https://github.com/coral-xyz/anchor/pull/2845)). +- ts: Add `prepend` option to MethodBuilder `preInstructions` method ([#2863](https://github.com/coral-xyz/anchor/pull/2863)). +- lang: Add `declare_program!` macro ([#2857](https://github.com/coral-xyz/anchor/pull/2857)). +- cli: Add `deactivate_feature` flag to `solana-test-validator` config in Anchor.toml ([#2872](https://github.com/coral-xyz/anchor/pull/2872)). +- idl: Add `docs` field for constants ([#2887](https://github.com/coral-xyz/anchor/pull/2887)). +- idl: Store deployment addresses for other clusters ([#2892](https://github.com/coral-xyz/anchor/pull/2892)). +- lang: Add `Event` utility type to get events from bytes ([#2897](https://github.com/coral-xyz/anchor/pull/2897)). +- lang, spl: Add support for [token extensions](https://solana.com/solutions/token-extensions) ([#2789](https://github.com/coral-xyz/anchor/pull/2789)). +- lang: Return overflow error from `Lamports` trait operations ([#2907](https://github.com/coral-xyz/anchor/pull/2907)). ### Fixes @@ -41,6 +172,17 @@ The minor version will be incremented upon a breaking change and the patch versi - ts: Fix formatting enums ([#2763](https://github.com/coral-xyz/anchor/pull/2763)). - cli: Fix `migrate` command not working without global `ts-node` installation ([#2767](https://github.com/coral-xyz/anchor/pull/2767)). - client, lang, spl, syn: Enable all features for docs.rs build ([#2774](https://github.com/coral-xyz/anchor/pull/2774)). +- ts: Fix construction of field layouts for type aliased instruction arguments ([#2821](https://github.com/coral-xyz/anchor/pull/2821)) +- idl: Fix IDL ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl, ts: Make casing consistent ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Fix not being able to use numbers in instruction, account, or event names in some cases due to case conversion ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- cli: Fix excessive test validator requests ([#2828](https://github.com/coral-xyz/anchor/pull/2828)). +- client: Fix `parse_logs_response` to prevent panics when more than 1 outer instruction exists in logs ([#2856](https://github.com/coral-xyz/anchor/pull/2856)). +- avm, cli: Fix `stdsimd` feature compilation error from `ahash` when installing the CLI using newer Rust versions ([#2867](https://github.com/coral-xyz/anchor/pull/2867)). +- spl: Fix not being able to deserialize newer token 2022 extensions ([#2876](https://github.com/coral-xyz/anchor/pull/2876)). +- spl: Remove `solana-program` dependency ([#2900](https://github.com/coral-xyz/anchor/pull/2900)). +- spl: Make `TokenAccount` and ` Mint` `Copy` ([#2904](https://github.com/coral-xyz/anchor/pull/2904)). +- ts: Add missing errors ([#2906](https://github.com/coral-xyz/anchor/pull/2906)). ### Breaking @@ -52,9 +194,23 @@ The minor version will be incremented upon a breaking change and the patch versi - spl: Remove `shared-memory` program ([#2747](https://github.com/coral-xyz/anchor/pull/2747)). - ts: Remove `associated`, `account.associated` and `account.associatedAddress` methods ([#2749](https://github.com/coral-xyz/anchor/pull/2749)). - cli: `idl upgrade` command closes the IDL buffer account ([#2760](https://github.com/coral-xyz/anchor/pull/2760)). +- cli: Remove `--jest` option from the `init` command ([#2805](https://github.com/coral-xyz/anchor/pull/2805)). +- cli: Require `idl-build` feature in program `Cargo.toml` ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- cli: Rename `seeds` feature to `resolution` and make it enabled by default ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- cli: Remove `idl parse` command ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Change IDL spec ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- syn: Remove `idl-parse` and `seeds` features ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Change `accounts` method to no longer accept resolvable accounts ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: `Program` instances use camelCase for everything ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Remove discriminator functions ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Remove `programId` parameter of the `Program` constructor ([#2864](https://github.com/coral-xyz/anchor/pull/2864)). +- idl, syn: Move IDL types from the `anchor-syn` crate to the new IDL crate ([#2882](https://github.com/coral-xyz/anchor/pull/2882)). +- idl: Add `#[non_exhaustive]` to IDL enums ([#2890](https://github.com/coral-xyz/anchor/pull/2890)). ## [0.29.0] - 2023-10-16 +See the [Anchor 0.29 release notes](https://www.anchor-lang.com/release-notes/0.29.0) for a high-level overview of how to update. + ### Features - lang: Change all accounts to have a reference to `AccountInfo` ([#2656](https://github.com/coral-xyz/anchor/pull/2656)). diff --git a/Cargo.lock b/Cargo.lock index 1b49a4f819..7587041401 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" dependencies = [ "cfg-if", "getrandom 0.2.10", @@ -119,7 +119,7 @@ checksum = "6b2d54853319fd101b8dd81de382bcbf3e03410a64d8928bbee85a3e7dcde483" [[package]] name = "anchor-attribute-access-control" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-syn", "proc-macro2", @@ -129,7 +129,7 @@ dependencies = [ [[package]] name = "anchor-attribute-account" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-syn", "bs58 0.5.0", @@ -140,7 +140,7 @@ dependencies = [ [[package]] name = "anchor-attribute-constant" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-syn", "quote", @@ -149,7 +149,7 @@ dependencies = [ [[package]] name = "anchor-attribute-error" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-syn", "quote", @@ -158,7 +158,7 @@ dependencies = [ [[package]] name = "anchor-attribute-event" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-syn", "proc-macro2", @@ -168,22 +168,28 @@ dependencies = [ [[package]] name = "anchor-attribute-program" -version = "0.29.0" +version = "0.30.1" dependencies = [ + "anchor-lang-idl", "anchor-syn", + "anyhow", + "bs58 0.5.0", + "heck 0.3.3", + "proc-macro2", "quote", + "serde_json", "syn 1.0.109", ] [[package]] name = "anchor-cli" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-client", "anchor-lang", - "anchor-syn", + "anchor-lang-idl", "anyhow", - "base64 0.21.4", + "base64 0.21.7", "bincode", "cargo_toml", "chrono", @@ -213,7 +219,7 @@ dependencies = [ [[package]] name = "anchor-client" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-lang", "anyhow", @@ -230,7 +236,7 @@ dependencies = [ [[package]] name = "anchor-derive-accounts" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-syn", "quote", @@ -239,7 +245,7 @@ dependencies = [ [[package]] name = "anchor-derive-serde" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-syn", "borsh-derive-internal 0.10.3", @@ -250,7 +256,7 @@ dependencies = [ [[package]] name = "anchor-derive-space" -version = "0.29.0" +version = "0.30.1" dependencies = [ "proc-macro2", "quote", @@ -259,9 +265,8 @@ dependencies = [ [[package]] name = "anchor-lang" -version = "0.29.0" +version = "0.30.1" dependencies = [ - "ahash 0.8.6", "anchor-attribute-access-control", "anchor-attribute-account", "anchor-attribute-constant", @@ -271,39 +276,61 @@ dependencies = [ "anchor-derive-accounts", "anchor-derive-serde", "anchor-derive-space", - "anchor-syn", + "anchor-lang-idl", "arrayref", - "base64 0.21.4", + "base64 0.21.7", "bincode", "borsh 0.10.3", "bytemuck", - "getrandom 0.2.10", "solana-program", "thiserror", ] +[[package]] +name = "anchor-lang-idl" +version = "0.1.1" +dependencies = [ + "anchor-lang-idl-spec", + "anyhow", + "heck 0.3.3", + "regex", + "serde", + "serde_json", + "sha2 0.10.8", +] + +[[package]] +name = "anchor-lang-idl-spec" +version = "0.1.0" +dependencies = [ + "anyhow", + "serde", +] + [[package]] name = "anchor-spl" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anchor-lang", "borsh 0.10.3", "mpl-token-metadata", "serum_dex", - "solana-program", - "spl-associated-token-account", + "spl-associated-token-account 3.0.2", "spl-memo", + "spl-pod 0.2.2", "spl-token 4.0.0", - "spl-token-2022", - "toml_edit 0.21.0", + "spl-token-2022 3.0.2", + "spl-token-group-interface 0.2.3", + "spl-token-metadata-interface 0.3.3", ] [[package]] name = "anchor-syn" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anyhow", "bs58 0.5.0", + "cargo_toml", "heck 0.3.3", "proc-macro2", "quote", @@ -617,13 +644,13 @@ dependencies = [ [[package]] name = "async-trait" -version = "0.1.73" +version = "0.1.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc00ceb34980c03614e35a3a4e218276a0a824e911d07651cd0d858a51e8c0f0" +checksum = "a507401cad91ec6a857ed5513a2073c82a9b9048762b885bb98655b306964681" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -645,11 +672,12 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "avm" -version = "0.29.0" +version = "0.30.1" dependencies = [ "anyhow", "cargo_toml", "cfg-if", + "chrono", "clap 4.4.6", "dirs", "once_cell", @@ -688,9 +716,9 @@ checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" [[package]] name = "base64" -version = "0.21.4" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ba43ea6f343b788c8764558649e08df62f86c6ef251fdaeb1ffd010a9ae50a2" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64ct" @@ -730,9 +758,9 @@ checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" [[package]] name = "bitflags" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" +checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" dependencies = [ "serde", ] @@ -805,6 +833,16 @@ dependencies = [ "hashbrown 0.13.2", ] +[[package]] +name = "borsh" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f58b559fd6448c6e2fd0adb5720cd98a2506594cafa4737ff98c396f3e82f667" +dependencies = [ + "borsh-derive 1.3.1", + "cfg_aliases", +] + [[package]] name = "borsh-derive" version = "0.9.3" @@ -831,6 +869,20 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "borsh-derive" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aadb5b6ccbd078890f6d7003694e33816e6b784358f18e15e7e6d9f065a57cd" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", + "proc-macro2", + "quote", + "syn 2.0.55", + "syn_derive", +] + [[package]] name = "borsh-derive-internal" version = "0.9.3" @@ -929,9 +981,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.14.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "374d28ec25809ee0e23827c2ab573d729e293f281dfe393500e7ad618baa61c6" +checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15" dependencies = [ "bytemuck_derive", ] @@ -944,14 +996,14 @@ checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" @@ -971,12 +1023,12 @@ dependencies = [ [[package]] name = "cargo_toml" -version = "0.15.3" +version = "0.19.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "599aa35200ffff8f04c1925aa1acc92fa2e08874379ef42e210a80e527e60838" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" dependencies = [ "serde", - "toml 0.7.8", + "toml 0.8.2", ] [[package]] @@ -995,6 +1047,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + [[package]] name = "chrono" version = "0.4.31" @@ -1081,7 +1139,7 @@ dependencies = [ "heck 0.4.1", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -1129,15 +1187,15 @@ dependencies = [ [[package]] name = "console" -version = "0.15.7" +version = "0.15.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c926e00cc70edefdc64d3a5ff31cc65bb97a3460097762bd23afb4d8145fccf8" +checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" dependencies = [ "encode_unicode", "lazy_static", "libc", "unicode-width", - "windows-sys 0.45.0", + "windows-sys 0.52.0", ] [[package]] @@ -1208,11 +1266,10 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.8" +version = "0.5.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a33c2bf77f2df06183c3aa30d1e96c0695a313d4f9c453cc3762a6db39f99200" +checksum = "ab3db02a9c5b5121e1e42fbdb1aeb65f5e02624cc58c43f2884c6ccac0b82f95" dependencies = [ - "cfg-if", "crossbeam-utils", ] @@ -1242,12 +1299,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.16" +version = "0.8.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a22b2d63d4d1dc0b7f1b6b2747dd0088008a9be28b6ddf0b1e7d335e3037294" -dependencies = [ - "cfg-if", -] +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" [[package]] name = "crunchy" @@ -1319,7 +1373,7 @@ dependencies = [ "proc-macro2", "quote", "strsim 0.10.0", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -1330,17 +1384,20 @@ checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" dependencies = [ "darling_core", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "dashmap" -version = "4.0.2" +version = "5.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" dependencies = [ "cfg-if", - "num_cpus", + "hashbrown 0.14.1", + "lock_api", + "once_cell", + "parking_lot_core", ] [[package]] @@ -1374,9 +1431,12 @@ dependencies = [ [[package]] name = "deranged" -version = "0.3.8" +version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2696e8a945f658fd14dc3b87242e6b80cd0f36ff04ea560fa39082368847946" +checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +dependencies = [ + "powerfmt", +] [[package]] name = "derivation-path" @@ -1482,7 +1542,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -1505,7 +1565,7 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -1581,22 +1641,22 @@ dependencies = [ [[package]] name = "enum-iterator" -version = "1.4.1" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7add3873b5dd076766ee79c8e406ad1a472c385476b9e38849f8eec24f1be689" +checksum = "9fd242f399be1da0a5354aa462d57b4ab2b4ee0683cc552f7c007d2d12d36e94" dependencies = [ "enum-iterator-derive", ] [[package]] name = "enum-iterator-derive" -version = "1.2.1" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eecf8589574ce9b895052fa12d69af7a233f99e6107f5cb8dd1044f2a17bfdcb" +checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -1723,18 +1783,18 @@ checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" [[package]] name = "form_urlencoded" -version = "1.2.0" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a62bc1cf6f830c2ec14a513a9fb124d0a213a629668a4186f329db21fe045652" +checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" dependencies = [ "percent-encoding", ] [[package]] name = "futures" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" dependencies = [ "futures-channel", "futures-core", @@ -1747,9 +1807,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" dependencies = [ "futures-core", "futures-sink", @@ -1757,15 +1817,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" [[package]] name = "futures-executor" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" dependencies = [ "futures-core", "futures-task", @@ -1774,38 +1834,38 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" [[package]] name = "futures-macro" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "89ca545a94061b6365f2c7355b4b32bd20df3ff95f02da9329b34ccc3bd6ee72" +checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "futures-sink" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" +checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" [[package]] name = "futures-task" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" +checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-util" -version = "0.3.28" +version = "0.3.30" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" dependencies = [ "futures-channel", "futures-core", @@ -1932,7 +1992,7 @@ version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", ] [[package]] @@ -2116,9 +2176,9 @@ checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" [[package]] name = "idna" -version = "0.4.0" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d20d6b07bfbc108882d88ed8e37d39636dcc260e15e30c45e6ba089610b917c" +checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" dependencies = [ "unicode-bidi", "unicode-normalization", @@ -2152,9 +2212,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "2.0.2" +version = "2.2.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8adf3ddd720272c6ea8bf59463c04e0f93d0bbf7c5439b691bca2987e0270897" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" dependencies = [ "equivalent", "hashbrown 0.14.1", @@ -2243,9 +2303,9 @@ dependencies = [ [[package]] name = "js-sys" -version = "0.3.64" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5f195fe497f702db0f318b07fdd68edb16955aed830df8363d837542f8f935a" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] @@ -2310,9 +2370,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" [[package]] name = "libc" -version = "0.2.148" +version = "0.2.153" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" +checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd" [[package]] name = "libsecp256k1" @@ -2364,12 +2424,13 @@ dependencies = [ [[package]] name = "light-poseidon" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "949bdd22e4ed93481d45e9a6badb34b99132bcad0c8a8d4f05c42f7dcc7b90bc" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ "ark-bn254", "ark-ff", + "num-bigint 0.4.4", "thiserror", ] @@ -2484,9 +2545,9 @@ dependencies = [ [[package]] name = "mpl-token-metadata" -version = "3.1.0" +version = "4.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177204bbe7486b22ac35af2c91a82630f830a6ddd3392651aefde1ef346aba3d" +checksum = "caf0f61b553e424a6234af1268456972ee66c2222e1da89079242251fa7479e5" dependencies = [ "borsh 0.10.3", "num-derive 0.3.3", @@ -2570,6 +2631,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51d515d32fb182ee37cda2ccdcb92950d6a3c2893aa280e540671c2cd0f3b1d9" + [[package]] name = "num-derive" version = "0.3.3" @@ -2589,7 +2656,7 @@ checksum = "9e6a0fd4f737c707bd9086cc16c925f294943eb62eb71499e9fd4cf71f8b9f4e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -2664,11 +2731,11 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70bf6736f74634d299d00086f02986875b3c2d924781a6a2cb6c201e73da0ceb" +checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" dependencies = [ - "num_enum_derive 0.7.0", + "num_enum_derive 0.7.2", ] [[package]] @@ -2692,19 +2759,19 @@ dependencies = [ "proc-macro-crate 1.3.1", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "num_enum_derive" -version = "0.7.0" +version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ea360eafe1022f7cc56cd7b869ed57330fb2453d0c7831d99b74c65d2f5597" +checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b" dependencies = [ - "proc-macro-crate 1.3.1", + "proc-macro-crate 3.1.0", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -2819,9 +2886,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.0" +version = "2.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b2a4787296e9989611394c33f193f676704af1686e70b8f8033ab5ba9a35a94" +checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" [[package]] name = "percentage" @@ -2839,7 +2906,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e1d3afd2628e69da2be385eb6f2fd57c8ac7977ceeff6dc166ff1657b0e386a9" dependencies = [ "fixedbitset", - "indexmap 2.0.2", + "indexmap 2.2.6", ] [[package]] @@ -2872,7 +2939,7 @@ dependencies = [ "phf_shared 0.11.2", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -2955,6 +3022,12 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "powerfmt" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" + [[package]] name = "ppv-lite86" version = "0.2.17" @@ -2986,11 +3059,43 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "proc-macro-crate" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +dependencies = [ + "toml_edit 0.21.0", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +dependencies = [ + "proc-macro-error-attr", + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + [[package]] name = "proc-macro2" -version = "1.0.67" +version = "1.0.79" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e" dependencies = [ "unicode-ident", ] @@ -3012,7 +3117,7 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -3034,13 +3139,13 @@ dependencies = [ [[package]] name = "quinn-proto" -version = "0.10.5" +version = "0.10.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c78e758510582acc40acb90458401172d41f1016f8c9dde89e49677afb7eec1" +checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" dependencies = [ "bytes", "rand 0.8.5", - "ring", + "ring 0.16.20", "rustc-hash", "rustls", "rustls-native-certs", @@ -3058,16 +3163,16 @@ checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" dependencies = [ "bytes", "libc", - "socket2 0.5.4", + "socket2 0.5.6", "tracing", "windows-sys 0.48.0", ] [[package]] name = "quote" -version = "1.0.33" +version = "1.0.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" dependencies = [ "proc-macro2", ] @@ -3154,9 +3259,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -3164,9 +3269,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", @@ -3179,7 +3284,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" dependencies = [ "pem", - "ring", + "ring 0.16.20", "time", "yasna", ] @@ -3244,12 +3349,12 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da" [[package]] name = "reqwest" -version = "0.11.21" +version = "0.11.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78fdbab6a7e1d7b13cc8ff10197f47986b41c639300cc3c8158cac7847c9bbef" +checksum = "dd67538700a17451e7cba03ac727fb961abb7607553461627b97de0b89cf4a62" dependencies = [ "async-compression", - "base64 0.21.4", + "base64 0.21.7", "bytes", "encoding_rs", "futures-core", @@ -3272,6 +3377,7 @@ dependencies = [ "serde", "serde_json", "serde_urlencoded", + "sync_wrapper", "system-configuration", "tokio", "tokio-rustls", @@ -3294,21 +3400,36 @@ dependencies = [ "cc", "libc", "once_cell", - "spin", - "untrusted", + "spin 0.5.2", + "untrusted 0.7.1", "web-sys", "winapi", ] +[[package]] +name = "ring" +version = "0.17.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c17fa4cb658e3583423e915b9f3acc01cceaee1860e33d59ebae66adc3a2dc0d" +dependencies = [ + "cc", + "cfg-if", + "getrandom 0.2.10", + "libc", + "spin 0.9.8", + "untrusted 0.9.0", + "windows-sys 0.52.0", +] + [[package]] name = "rpassword" -version = "7.2.0" +version = "7.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6678cf63ab3491898c0d021b493c94c9b221d91295294a2a5746eacbe5928322" +checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" dependencies = [ "libc", "rtoolbox", - "winapi", + "windows-sys 0.48.0", ] [[package]] @@ -3357,7 +3478,7 @@ version = "0.38.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d2f9da0cbd88f9f09e7814e388301c8414c51c62aa6ce1e4b5c551d49d96e531" dependencies = [ - "bitflags 2.4.0", + "bitflags 2.5.0", "errno", "libc", "linux-raw-sys", @@ -3366,12 +3487,12 @@ dependencies = [ [[package]] name = "rustls" -version = "0.21.7" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cd8d6c9f025a446bc4d18ad9632e69aec8f287aa84499ee335599fabd20c3fd8" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring", + "ring 0.17.8", "rustls-webpki", "sct", ] @@ -3394,17 +3515,17 @@ version = "1.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2d3987094b1d07b653b7dfdc3f70ce9a1da9c51ac18c1b06b662e4f9a0e9f4b2" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", ] [[package]] name = "rustls-webpki" -version = "0.101.6" +version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c7d5dece342910d9ba34d259310cae3e0154b873b35408b787b59bce53d34fe" +checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring", - "untrusted", + "ring 0.17.8", + "untrusted 0.9.0", ] [[package]] @@ -3466,7 +3587,7 @@ checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -3475,8 +3596,8 @@ version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d53dcdb7c9f8158937a7981b48accfd39a43af418591a5d008c7b22b5e1b7ca4" dependencies = [ - "ring", - "untrusted", + "ring 0.16.20", + "untrusted 0.7.1", ] [[package]] @@ -3504,44 +3625,44 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.19" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad977052201c6de01a8ef2aa3378c4bd23217a056337d1d6da40468d267a4fb0" +checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.12" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.188" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "serde_json" -version = "1.0.107" +version = "1.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b420ce6e3d8bd882e9b243c6eed35dbc9a6110c9769e74b584e0d68d1f20c65" +checksum = "c5f09b1bd632ef549eaa9f60a1f8de742bdbc698e6cee2095fc84dde5f549ae0" dependencies = [ "itoa", "ryu", @@ -3588,16 +3709,16 @@ dependencies = [ "darling", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "serde_yaml" -version = "0.9.25" +version = "0.9.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a49e178e4452f45cb61d0cd8cebc1b0fafd3e41929e996cef79aa3aca91f574" +checksum = "a0623d197252096520c6f2a5e1171ee436e5af99a5d7caa2891e55e61950e6d9" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.2.6", "itoa", "ryu", "serde", @@ -3741,9 +3862,9 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.11.1" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "socket2" @@ -3757,22 +3878,22 @@ dependencies = [ [[package]] name = "socket2" -version = "0.5.4" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4031e820eb552adee9295814c0ced9e5cf38ddf1e8b7d566d6de8e2538ea989e" +checksum = "05ffd9c0a93b7543e062e759284fcf5f5e3b098501104bfbdde4d404db792871" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.52.0", ] [[package]] name = "solana-account-decoder" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d67ecc499b9cc79c9f34c1bbae2ba3f102d9bfaa78f48ad49d11f433bc4c7b4" +checksum = "4973213a11c2e1b924b36e0c6688682b5aa4623f8d4eeaa1204c32cee524e6d6" dependencies = [ "Inflector", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bs58 0.4.0", "bv", @@ -3783,17 +3904,18 @@ dependencies = [ "solana-config-program", "solana-sdk", "spl-token 4.0.0", - "spl-token-2022", - "spl-token-metadata-interface", + "spl-token-2022 1.0.0", + "spl-token-group-interface 0.1.0", + "spl-token-metadata-interface 0.2.0", "thiserror", "zstd", ] [[package]] name = "solana-clap-utils" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26cf9322dc6cad9902a6a5ef77ad9cd9149b64c757c1ffa536c4243bd7136159" +checksum = "909f4553d0b31bb5b97533a6b64cc321a4eace9112d6efbabcf4408ea1b3f1db" dependencies = [ "chrono", "clap 2.34.0", @@ -3808,9 +3930,9 @@ dependencies = [ [[package]] name = "solana-cli-config" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7e3476dc3b63bb2e0da304f10df299b20942ae57054eaed2cc411a5449876bd" +checksum = "2242c4a0776cdaec1358d0ffc61b32131985a7b2210c491fa465d28c313eb880" dependencies = [ "dirs-next", "lazy_static", @@ -3824,16 +3946,16 @@ dependencies = [ [[package]] name = "solana-client" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df5d23b030f09ea0a3e0d89d22b453849e33f45a89ef0eeae152a21c58752985" +checksum = "c5cc431df6cc1dd964134fa4ec7df765d3af3fae9c2148f96a3c4fb500290633" dependencies = [ "async-trait", "bincode", "dashmap", "futures", "futures-util", - "indexmap 2.0.2", + "indexmap 2.2.6", "indicatif", "log", "quinn", @@ -3857,9 +3979,9 @@ dependencies = [ [[package]] name = "solana-config-program" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "117a5204fb9e7982f2058373d3f21b7997846aed4ca562cf6e84aef4c729c75b" +checksum = "e38b040d3a42e8f7d80c4a86bb0d49d7aed663b56b0fe0ae135d2d145fb7ae3a" dependencies = [ "bincode", "chrono", @@ -3871,15 +3993,15 @@ dependencies = [ [[package]] name = "solana-connection-cache" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08c2f6c76632ec5d6e59aae8fe13095d27c3ae2af143f6973684856babdcd2da" +checksum = "ae02622c63943485f0af3d0896626eaf6478e734f0b6bc61c7cc5320963c6e75" dependencies = [ "async-trait", "bincode", "crossbeam-channel", "futures-util", - "indexmap 2.0.2", + "indexmap 2.2.6", "log", "rand 0.8.5", "rayon", @@ -3893,9 +4015,9 @@ dependencies = [ [[package]] name = "solana-faucet" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cd45403c75e5104c79f6875b2326196af76572534c80cfadaed3145ed087aa" +checksum = "6fb2e8702fea7c9549d4e946c9b30894f99c94778d80cc8a669d8fdccb131ce3" dependencies = [ "bincode", "byteorder", @@ -3917,17 +4039,13 @@ dependencies = [ [[package]] name = "solana-frozen-abi" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7fdc9268b1abba206e1a8a234473eb5f7f7af660a86e4d468e7e79b3e5667aa9" +checksum = "4867f66e9527fa44451c861c1dc6d9b2a7c7a668d7c6a297cdefbe39f4395b33" dependencies = [ - "ahash 0.8.6", - "blake3", "block-buffer 0.10.4", "bs58 0.4.0", "bv", - "byteorder", - "cc", "either", "generic-array", "im", @@ -3938,7 +4056,6 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "serde_json", "sha2 0.10.8", "solana-frozen-abi-macro", "subtle", @@ -3947,21 +4064,21 @@ dependencies = [ [[package]] name = "solana-frozen-abi-macro" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86118cc8437c60d1a474501f6095df880aaac422ab04523a984015c5b7334428" +checksum = "168f24d97347b85f05192df58d6be3e3047a4aadc4001bc1b9e711a5ec878eea" dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "solana-logger" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "060dcc6a1ee83aa2df01126e0319b17a84d13251b7660fa1e69241e110252779" +checksum = "a0511082fc62f2d086520fff5aa1917c389d8c840930c08ad255ae05952c08a2" dependencies = [ "env_logger", "lazy_static", @@ -3970,9 +4087,9 @@ dependencies = [ [[package]] name = "solana-measure" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a23bcca30fdb20efb5f2d81d61ad9cf1ec0f0141b3bbc095835140db72930f" +checksum = "be55a3df105431d25f86f2a7da0cbbde5f54c1f0782ca59367ea4a8037bc6797" dependencies = [ "log", "solana-sdk", @@ -3980,9 +4097,9 @@ dependencies = [ [[package]] name = "solana-metrics" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa2d29f683e800cbfb836ceec63fdbf5f42388c21fdacb2e16160b10be3b08cd" +checksum = "ddec097ed7572804389195128dbd57958b427829153c6cd8ec3343c86fe3cd22" dependencies = [ "crossbeam-channel", "gethostname", @@ -3995,9 +4112,9 @@ dependencies = [ [[package]] name = "solana-net-utils" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "687c740f5b45166666e016ac43cc1001fa5bf9e8f7b9e24cb0a554c6ce35bfd6" +checksum = "258fa7c29fb7605b8d2ed89aa0d43c640d14f4147ad1f5b3fdad19a1ac145ca5" dependencies = [ "bincode", "clap 3.2.25", @@ -4007,7 +4124,7 @@ dependencies = [ "rand 0.8.5", "serde", "serde_derive", - "socket2 0.5.4", + "socket2 0.5.6", "solana-logger", "solana-sdk", "solana-version", @@ -4017,11 +4134,11 @@ dependencies = [ [[package]] name = "solana-perf" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d0b706a083218777c52adbb6138b96c143e06031d41ec9c32cf1da9c352c7c" +checksum = "ca422edcf16a6e64003ca118575ea641f7b750f14a0ad28c71dd84f33dcb912a" dependencies = [ - "ahash 0.8.6", + "ahash 0.8.11", "bincode", "bv", "caps", @@ -4034,7 +4151,10 @@ dependencies = [ "nix", "rand 0.8.5", "rayon", + "rustc_version", "serde", + "solana-frozen-abi", + "solana-frozen-abi-macro", "solana-metrics", "solana-rayon-threadlimit", "solana-sdk", @@ -4043,20 +4163,21 @@ dependencies = [ [[package]] name = "solana-program" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05c940ad70659c2366331fd136d67cc968acadbc1f6ad13cff9ffe7e392aa831" +checksum = "2bc5a636dc75e5c25651e34f7a36afc9ae60d38166687c5b0375abb580ac81a2" dependencies = [ "ark-bn254", "ark-ec", "ark-ff", "ark-serialize", - "base64 0.21.4", + "base64 0.21.7", "bincode", - "bitflags 2.4.0", + "bitflags 2.5.0", "blake3", "borsh 0.10.3", "borsh 0.9.3", + "borsh 1.3.1", "bs58 0.4.0", "bv", "bytemuck", @@ -4074,7 +4195,7 @@ dependencies = [ "log", "memoffset 0.9.0", "num-bigint 0.4.4", - "num-derive 0.3.3", + "num-derive 0.4.0", "num-traits", "parking_lot", "rand 0.8.5", @@ -4097,18 +4218,18 @@ dependencies = [ [[package]] name = "solana-program-runtime" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ffcc34819f5b9da3c5ba4045d572e97a60544b8ed49d604ab0a9cc990f875e2" +checksum = "bf373c3da0387f47fee4c5ed2465a9628b9db026a62211a692a9285aa9251544" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bincode", "eager", "enum-iterator", "itertools 0.10.5", "libc", "log", - "num-derive 0.3.3", + "num-derive 0.4.0", "num-traits", "percentage", "rand 0.8.5", @@ -4125,9 +4246,9 @@ dependencies = [ [[package]] name = "solana-pubsub-client" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "076dbe759e2c86aa5c8b57575d2bd593980bde82b59cb6192261b5d6111dfcd1" +checksum = "97b9abc76168d19927561db6a3685b98752bd0961b4ce4f8b7f85ee12238c017" dependencies = [ "crossbeam-channel", "futures-util", @@ -4150,9 +4271,9 @@ dependencies = [ [[package]] name = "solana-quic-client" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a5bbf483ec8e440a80b02ef4aa37d0cb6dc77403dc8dfd1a72bdba90429539a" +checksum = "7952c5306a0be5f5276448cd20246b31265bfa884f29a077a24303c6a16aeb34" dependencies = [ "async-mutex", "async-trait", @@ -4177,9 +4298,9 @@ dependencies = [ [[package]] name = "solana-rayon-threadlimit" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f23c92c4fb6a1036b7910fb86fbfbf213fabcb3f0d143e6472511d312e0091e" +checksum = "a4fa0cc66f8e73d769bca2ede3012ba2ef8ab67963e832808665369f2cf81743" dependencies = [ "lazy_static", "num_cpus", @@ -4187,14 +4308,14 @@ dependencies = [ [[package]] name = "solana-remote-wallet" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3b7545aa3e2201494e3a1379bb487caa1081786ddf17959ffb819eef9c9202db" +checksum = "289803796d4ff7b4699504d3ab9e9d9c5205ea3892b2ebe397b377494dbd75d4" dependencies = [ "console", "dialoguer", "log", - "num-derive 0.3.3", + "num-derive 0.4.0", "num-traits", "parking_lot", "qstring", @@ -4206,12 +4327,12 @@ dependencies = [ [[package]] name = "solana-rpc-client" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e24f3f022731f854f97fa88190a4bdf4a6a2e11704999ef4882320d7edc4eb" +checksum = "6cb55a08018776a62ecff52139fbcdab1a7baa4e8f077202be58156e8dde4d5f" dependencies = [ "async-trait", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bs58 0.4.0", "indicatif", @@ -4232,11 +4353,11 @@ dependencies = [ [[package]] name = "solana-rpc-client-api" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ae82221d8d5d447cdc27355caa54f96f52af195a984f70c7e8fa0d8e4a4b0f3" +checksum = "72a8403038f4d6ab65bc7e7afb3afe8d9824c592232553c5cef55cf3de36025d" dependencies = [ - "base64 0.21.4", + "base64 0.21.7", "bs58 0.4.0", "jsonrpc-core", "reqwest", @@ -4248,15 +4369,15 @@ dependencies = [ "solana-sdk", "solana-transaction-status", "solana-version", - "spl-token-2022", + "spl-token-2022 1.0.0", "thiserror", ] [[package]] name = "solana-rpc-client-nonce-utils" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0795902effc5404f43a0a54a489f9d84a5c7eb62164234288690a608582ee4a" +checksum = "4caca735caf76d51c074c3bacbfe38094bf7f92cfbe7b5b13f3bc4946e64f889" dependencies = [ "clap 2.34.0", "solana-clap-utils", @@ -4267,15 +4388,15 @@ dependencies = [ [[package]] name = "solana-sdk" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3db7ae7c80ba537e4b8c1b4655fda680aa1452c8c955113f985b74b235fc3102" +checksum = "df43d3a1e1637397ab43cbc216a5a8f977ec8a3cc3f3ae8c3851c83a3255dbcf" dependencies = [ "assert_matches", - "base64 0.21.4", + "base64 0.21.7", "bincode", - "bitflags 2.4.0", - "borsh 0.10.3", + "bitflags 2.5.0", + "borsh 1.3.1", "bs58 0.4.0", "bytemuck", "byteorder", @@ -4292,9 +4413,9 @@ dependencies = [ "libsecp256k1", "log", "memmap2", - "num-derive 0.3.3", + "num-derive 0.4.0", "num-traits", - "num_enum 0.6.1", + "num_enum 0.7.2", "pbkdf2 0.11.0", "qstring", "qualifier_attr", @@ -4309,6 +4430,7 @@ dependencies = [ "serde_with", "sha2 0.10.8", "sha3 0.10.8", + "siphasher", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-logger", @@ -4321,29 +4443,35 @@ dependencies = [ [[package]] name = "solana-sdk-macro" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1da4a7421c09ee4dbf81df06407933d4f68f8990ae87a2feaee6e1b03c97d1d" +checksum = "86c76414183a325038ff020b22c07d1e9d2da0703ddc0244acfed37ee2921d96" dependencies = [ "bs58 0.4.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.37", + "syn 2.0.55", ] +[[package]] +name = "solana-security-txt" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" + [[package]] name = "solana-streamer" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28b4f623d32af2793e7ebdd24bd04f704a77f6a7975cf8204275ebc918d4685" +checksum = "fad1bdb955ec6d23a1dbf87e403ff3e610d68616275693125a893d7ed4b2d323" dependencies = [ "async-channel", "bytes", "crossbeam-channel", "futures-util", "histogram", - "indexmap 2.0.2", + "indexmap 2.2.6", "itertools 0.10.5", "libc", "log", @@ -4356,6 +4484,7 @@ dependencies = [ "rand 0.8.5", "rcgen", "rustls", + "smallvec", "solana-metrics", "solana-perf", "solana-sdk", @@ -4366,9 +4495,9 @@ dependencies = [ [[package]] name = "solana-thin-client" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05ec81c9b19cc3a02e423782758305c63460b664912217e61e273e0105f7dc0b" +checksum = "bc301310ba0755c449a8800136f67f8ad14419b366404629894cd10021495360" dependencies = [ "bincode", "log", @@ -4381,14 +4510,14 @@ dependencies = [ [[package]] name = "solana-tpu-client" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf9e6a85761ebc7be477e95b5787f206e6f64d09d297006881edbe30c99106d0" +checksum = "fb887bd5078ff015e103e9ee54a6713380590efa8ff1804b3a653f07188928c6" dependencies = [ "async-trait", "bincode", "futures-util", - "indexmap 2.0.2", + "indexmap 2.2.6", "indicatif", "log", "rayon", @@ -4405,12 +4534,12 @@ dependencies = [ [[package]] name = "solana-transaction-status" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2eaba311b1be47ae8a1ed8d082d2c35cd89a39c5daf73514668c735574d4ecd" +checksum = "4a0cdfdf63192fb60de094fae8e81159e4e3e9aac9659fe3f9ef0e707023fb32" dependencies = [ "Inflector", - "base64 0.21.4", + "base64 0.21.7", "bincode", "borsh 0.10.3", "bs58 0.4.0", @@ -4421,18 +4550,18 @@ dependencies = [ "serde_json", "solana-account-decoder", "solana-sdk", - "spl-associated-token-account", + "spl-associated-token-account 2.3.0", "spl-memo", "spl-token 4.0.0", - "spl-token-2022", + "spl-token-2022 1.0.0", "thiserror", ] [[package]] name = "solana-udp-client" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6f3750d7c9218e2a0e5ad73b62e293a71489c6425e64e98d5315dc64939eee6" +checksum = "3ea0d6d8d66e36371577f51c4d1d6192a66f1fa4efe7161a36d94677640dcadb" dependencies = [ "async-trait", "solana-connection-cache", @@ -4445,9 +4574,9 @@ dependencies = [ [[package]] name = "solana-version" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19dc9876647351f50ac415afcd9bc8ea3892883a077cd240f84490a0670ab021" +checksum = "6f4c2f531c22ce806b211118be8928a791425f97de4592371fb57b246ed33e34" dependencies = [ "log", "rustc_version", @@ -4461,13 +4590,13 @@ dependencies = [ [[package]] name = "solana-vote-program" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "480b27798516d7065b358f3ec056b2ede79e0dc8406a9697c6028f289a09398d" +checksum = "6d8a6486017e71a3714a8e1a635e17209135cc20535ba9808ccf106d80ff6e8b" dependencies = [ "bincode", "log", - "num-derive 0.3.3", + "num-derive 0.4.0", "num-traits", "rustc_version", "serde", @@ -4483,12 +4612,12 @@ dependencies = [ [[package]] name = "solana-zk-token-sdk" -version = "1.17.0" +version = "1.18.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8690fff97c3cb2acfdb49d126f8b958736884f58bd1c7fd2230984f132095f05" +checksum = "513407f88394e437b4ff5aad892bc5bf51a655ae2401e6e63549734d3695c46f" dependencies = [ "aes-gcm-siv", - "base64 0.21.4", + "base64 0.21.7", "bincode", "bytemuck", "byteorder", @@ -4497,7 +4626,7 @@ dependencies = [ "itertools 0.10.5", "lazy_static", "merlin", - "num-derive 0.3.3", + "num-derive 0.4.0", "num-traits", "rand 0.7.3", "serde", @@ -4512,9 +4641,9 @@ dependencies = [ [[package]] name = "solana_rbpf" -version = "0.7.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "103318aa365ff7caa8cf534f2246b5eb7e5b34668736d52b1266b143f7a21196" +checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" dependencies = [ "byteorder", "combine", @@ -4549,6 +4678,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + [[package]] name = "spki" version = "0.5.4" @@ -4561,9 +4696,9 @@ dependencies = [ [[package]] name = "spl-associated-token-account" -version = "2.2.0" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "385e31c29981488f2820b2022d8e731aae3b02e6e18e2fd854e4c9a94dc44fc3" +checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" dependencies = [ "assert_matches", "borsh 0.10.3", @@ -4571,7 +4706,23 @@ dependencies = [ "num-traits", "solana-program", "spl-token 4.0.0", - "spl-token-2022", + "spl-token-2022 1.0.0", + "thiserror", +] + +[[package]] +name = "spl-associated-token-account" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2e688554bac5838217ffd1fab7845c573ff106b6336bf7d290db7c98d5a8efd" +dependencies = [ + "assert_matches", + "borsh 1.3.1", + "num-derive 0.4.0", + "num-traits", + "solana-program", + "spl-token 4.0.0", + "spl-token-2022 3.0.2", "thiserror", ] @@ -4583,7 +4734,18 @@ checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f" dependencies = [ "bytemuck", "solana-program", - "spl-discriminator-derive", + "spl-discriminator-derive 0.1.1", +] + +[[package]] +name = "spl-discriminator" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34d1814406e98b08c5cd02c1126f83fd407ad084adce0b05fda5730677822eac" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator-derive 0.2.0", ] [[package]] @@ -4593,8 +4755,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" dependencies = [ "quote", - "spl-discriminator-syn", - "syn 2.0.37", + "spl-discriminator-syn 0.1.1", + "syn 2.0.55", +] + +[[package]] +name = "spl-discriminator-derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" +dependencies = [ + "quote", + "spl-discriminator-syn 0.2.0", + "syn 2.0.55", ] [[package]] @@ -4606,7 +4779,20 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.37", + "syn 2.0.55", + "thiserror", +] + +[[package]] +name = "spl-discriminator-syn" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.55", "thiserror", ] @@ -4621,15 +4807,28 @@ dependencies = [ [[package]] name = "spl-pod" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079" +checksum = "85a5db7e4efb1107b0b8e52a13f035437cdcb36ef99c58f6d467f089d9b2915a" dependencies = [ "borsh 0.10.3", "bytemuck", "solana-program", "solana-zk-token-sdk", - "spl-program-error", + "spl-program-error 0.3.0", +] + +[[package]] +name = "spl-pod" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "046ce669f48cf2eca1ec518916d8725596bfb655beb1c74374cf71dc6cb773c9" +dependencies = [ + "borsh 1.3.1", + "bytemuck", + "solana-program", + "solana-zk-token-sdk", + "spl-program-error 0.4.0", ] [[package]] @@ -4641,7 +4840,20 @@ dependencies = [ "num-derive 0.4.0", "num-traits", "solana-program", - "spl-program-error-derive", + "spl-program-error-derive 0.3.1", + "thiserror", +] + +[[package]] +name = "spl-program-error" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5528f4dfa2a905012007999526955c79162c09668c69ad3c3f2ddfbd0b2984a4" +dependencies = [ + "num-derive 0.4.0", + "num-traits", + "solana-program", + "spl-program-error-derive 0.4.0", "thiserror", ] @@ -4654,21 +4866,47 @@ dependencies = [ "proc-macro2", "quote", "sha2 0.10.8", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] -name = "spl-tlv-account-resolution" +name = "spl-program-error-derive" version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062e148d3eab7b165582757453632ffeef490c02c86a48bfdb4988f63eefb3b9" +checksum = "641aa3116b1d58481e921b5d41dafc26a67bd488cb288330dbde004641764dd4" +dependencies = [ + "proc-macro2", + "quote", + "sha2 0.10.8", + "syn 2.0.55", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "615d381f48ddd2bb3c57c7f7fb207591a2a05054639b18a62e785117dd7a8683" dependencies = [ "bytemuck", "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", - "spl-type-length-value", + "spl-discriminator 0.1.0", + "spl-pod 0.1.1", + "spl-program-error 0.3.0", + "spl-type-length-value 0.3.0", +] + +[[package]] +name = "spl-tlv-account-resolution" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cace91ba08984a41556efe49cbf2edca4db2f577b649da7827d3621161784bf8" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", + "spl-program-error 0.4.0", + "spl-type-length-value 0.4.3", ] [[package]] @@ -4703,26 +4941,78 @@ dependencies = [ [[package]] name = "spl-token-2022" -version = "0.9.0" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" +dependencies = [ + "arrayref", + "bytemuck", + "num-derive 0.4.0", + "num-traits", + "num_enum 0.7.2", + "solana-program", + "solana-security-txt", + "solana-zk-token-sdk", + "spl-memo", + "spl-pod 0.1.1", + "spl-token 4.0.0", + "spl-token-group-interface 0.1.0", + "spl-token-metadata-interface 0.2.0", + "spl-transfer-hook-interface 0.4.1", + "spl-type-length-value 0.3.0", + "thiserror", +] + +[[package]] +name = "spl-token-2022" +version = "3.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4abf34a65ba420584a0c35f3903f8d727d1f13ababbdc3f714c6b065a686e86" +checksum = "e5412f99ae7ee6e0afde00defaa354e6228e47e30c0e3adf553e2e01e6abb584" dependencies = [ "arrayref", "bytemuck", "num-derive 0.4.0", "num-traits", - "num_enum 0.7.0", + "num_enum 0.7.2", "solana-program", + "solana-security-txt", "solana-zk-token-sdk", "spl-memo", - "spl-pod", + "spl-pod 0.2.2", "spl-token 4.0.0", - "spl-token-metadata-interface", - "spl-transfer-hook-interface", - "spl-type-length-value", + "spl-token-group-interface 0.2.3", + "spl-token-metadata-interface 0.3.3", + "spl-transfer-hook-interface 0.6.3", + "spl-type-length-value 0.4.3", "thiserror", ] +[[package]] +name = "spl-token-group-interface" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.1.0", + "spl-pod 0.1.1", + "spl-program-error 0.3.0", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d419b5cfa3ee8e0f2386fd7e02a33b3ec8a7db4a9c7064a2ea24849dc4a273b6" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", + "spl-program-error 0.4.0", +] + [[package]] name = "spl-token-metadata-interface" version = "0.2.0" @@ -4731,26 +5021,56 @@ checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" dependencies = [ "borsh 0.10.3", "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", - "spl-type-length-value", + "spl-discriminator 0.1.0", + "spl-pod 0.1.1", + "spl-program-error 0.3.0", + "spl-type-length-value 0.3.0", +] + +[[package]] +name = "spl-token-metadata-interface" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30179c47e93625680dabb620c6e7931bd12d62af390f447bc7beb4a3a9b5feee" +dependencies = [ + "borsh 1.3.1", + "solana-program", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", + "spl-program-error 0.4.0", + "spl-type-length-value 0.4.3", ] [[package]] name = "spl-transfer-hook-interface" -version = "0.3.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "051d31803f873cabe71aec3c1b849f35248beae5d19a347d93a5c9cccc5d5a9b" +checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" dependencies = [ "arrayref", "bytemuck", "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", - "spl-tlv-account-resolution", - "spl-type-length-value", + "spl-discriminator 0.1.0", + "spl-pod 0.1.1", + "spl-program-error 0.3.0", + "spl-tlv-account-resolution 0.5.1", + "spl-type-length-value 0.3.0", +] + +[[package]] +name = "spl-transfer-hook-interface" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66a98359769cd988f7b35c02558daa56d496a7e3bd8626e61f90a7c757eedb9b" +dependencies = [ + "arrayref", + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", + "spl-program-error 0.4.0", + "spl-tlv-account-resolution 0.6.3", + "spl-type-length-value 0.4.3", ] [[package]] @@ -4761,9 +5081,22 @@ checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac" dependencies = [ "bytemuck", "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", + "spl-discriminator 0.1.0", + "spl-pod 0.1.1", + "spl-program-error 0.3.0", +] + +[[package]] +name = "spl-type-length-value" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "422ce13429dbd41d2cee8a73931c05fda0b0c8ca156a8b0c19445642550bb61a" +dependencies = [ + "bytemuck", + "solana-program", + "spl-discriminator 0.2.2", + "spl-pod 0.2.2", + "spl-program-error 0.4.0", ] [[package]] @@ -4816,15 +5149,33 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.37" +version = "2.0.55" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.55", +] + +[[package]] +name = "sync_wrapper" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2047c6ded9c721764247e62cd3b03c09ffc529b2ba5b10ec482ae507a4a70160" + [[package]] name = "synstructure" version = "0.12.6" @@ -4919,32 +5270,34 @@ checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" [[package]] name = "thiserror" -version = "1.0.49" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.49" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] name = "time" -version = "0.3.29" +version = "0.3.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "426f806f4089c493dcac0d24c29c01e2c38baf8e30f1b716ee37e83d200b18fe" +checksum = "5dfd88e563464686c916c7e46e623e520ddc6d79fa6641390f2e3fa86e83e885" dependencies = [ "deranged", "itoa", + "num-conv", + "powerfmt", "serde", "time-core", "time-macros", @@ -4958,10 +5311,11 @@ checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" [[package]] name = "time-macros" -version = "0.2.15" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ad70d68dba9e1f8aceda7aa6711965dfec1cac869f311a51bd08b3a2ccbce20" +checksum = "3f252a68540fde3a3877aeea552b832b40ab9a69e318efd078774a01ddee1ccf" dependencies = [ + "num-conv", "time-core", ] @@ -5022,7 +5376,7 @@ dependencies = [ "parking_lot", "pin-project-lite", "signal-hook-registry", - "socket2 0.5.4", + "socket2 0.5.6", "tokio-macros", "windows-sys 0.48.0", ] @@ -5035,7 +5389,7 @@ checksum = "630bdcf245f78637c13ec01ffae6187cca34625e8c63150d424b59e55af2675e" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -5109,6 +5463,18 @@ dependencies = [ "toml_edit 0.19.15", ] +[[package]] +name = "toml" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "185d8ab0dfbb35cf1399a6344d8484209c088f75f8f68230da55d48d95d43e3d" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.20.2", +] + [[package]] name = "toml_datetime" version = "0.6.5" @@ -5124,7 +5490,20 @@ version = "0.19.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.2.6", + "serde", + "serde_spanned", + "toml_datetime", + "winnow", +] + +[[package]] +name = "toml_edit" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "396e4d48bbb2b7554c944bde63101b5ae446cff6ec4a24227428f15eb72ef338" +dependencies = [ + "indexmap 2.2.6", "serde", "serde_spanned", "toml_datetime", @@ -5137,7 +5516,7 @@ version = "0.21.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" dependencies = [ - "indexmap 2.0.2", + "indexmap 2.2.6", "toml_datetime", "winnow", ] @@ -5169,7 +5548,7 @@ checksum = "5f4f31f56159e98206da9efd823404b79b6ef3143b4a7ab76e67b1751b25a4ab" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -5283,9 +5662,9 @@ dependencies = [ [[package]] name = "unsafe-libyaml" -version = "0.2.9" +version = "0.2.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f28467d3e1d3c6586d8f25fa243f544f5800fec42d97032474e17222c2b75cfa" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" [[package]] name = "unsize" @@ -5302,6 +5681,12 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +[[package]] +name = "untrusted" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" + [[package]] name = "uriparse" version = "0.6.4" @@ -5314,9 +5699,9 @@ dependencies = [ [[package]] name = "url" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "143b538f18257fac9cad154828a57c6bf5157e1aa604d4816b5995bf6de87ae5" +checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" dependencies = [ "form_urlencoded", "idna", @@ -5386,9 +5771,9 @@ checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7706a72ab36d8cb1f80ffbf0e071533974a60d0a308d01a5d0375bf60499a342" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -5396,16 +5781,16 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ef2b6d3c510e9625e5fe6f509ab07d66a760f0885d858736483c32ed7809abd" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", "log", "once_cell", "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", "wasm-bindgen-shared", ] @@ -5423,9 +5808,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dee495e55982a3bd48105a7b947fd2a9b4a8ae3010041b9e0faab3f9cd028f1d" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5433,22 +5818,22 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54681b18a46765f095758388f2d0cf16eb8d4169b639ab575a8f5693af210c7b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.87" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ca6ad05a4870b2bf5fe995117d3728437bd27d7cd5f06f13c17443ef369775a1" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" @@ -5515,15 +5900,6 @@ dependencies = [ "windows-targets 0.48.5", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets 0.42.2", -] - [[package]] name = "windows-sys" version = "0.48.0" @@ -5534,18 +5910,12 @@ dependencies = [ ] [[package]] -name = "windows-targets" -version = "0.42.2" +name = "windows-sys" +version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows_aarch64_gnullvm 0.42.2", - "windows_aarch64_msvc 0.42.2", - "windows_i686_gnu 0.42.2", - "windows_i686_msvc 0.42.2", - "windows_x86_64_gnu 0.42.2", - "windows_x86_64_gnullvm 0.42.2", - "windows_x86_64_msvc 0.42.2", + "windows-targets 0.52.4", ] [[package]] @@ -5564,10 +5934,19 @@ dependencies = [ ] [[package]] -name = "windows_aarch64_gnullvm" -version = "0.42.2" +name = "windows-targets" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" +checksum = "7dd37b7e5ab9018759f893a1952c9420d060016fc19a472b4bb20d1bdd694d1b" +dependencies = [ + "windows_aarch64_gnullvm 0.52.4", + "windows_aarch64_msvc 0.52.4", + "windows_i686_gnu 0.52.4", + "windows_i686_msvc 0.52.4", + "windows_x86_64_gnu 0.52.4", + "windows_x86_64_gnullvm 0.52.4", + "windows_x86_64_msvc 0.52.4", +] [[package]] name = "windows_aarch64_gnullvm" @@ -5576,10 +5955,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" [[package]] -name = "windows_aarch64_msvc" -version = "0.42.2" +name = "windows_aarch64_gnullvm" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" +checksum = "bcf46cf4c365c6f2d1cc93ce535f2c8b244591df96ceee75d8e83deb70a9cac9" [[package]] name = "windows_aarch64_msvc" @@ -5588,10 +5967,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" [[package]] -name = "windows_i686_gnu" -version = "0.42.2" +name = "windows_aarch64_msvc" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" +checksum = "da9f259dd3bcf6990b55bffd094c4f7235817ba4ceebde8e6d11cd0c5633b675" [[package]] name = "windows_i686_gnu" @@ -5600,10 +5979,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" [[package]] -name = "windows_i686_msvc" -version = "0.42.2" +name = "windows_i686_gnu" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" +checksum = "b474d8268f99e0995f25b9f095bc7434632601028cf86590aea5c8a5cb7801d3" [[package]] name = "windows_i686_msvc" @@ -5612,10 +5991,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" [[package]] -name = "windows_x86_64_gnu" -version = "0.42.2" +name = "windows_i686_msvc" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" +checksum = "1515e9a29e5bed743cb4415a9ecf5dfca648ce85ee42e15873c3cd8610ff8e02" [[package]] name = "windows_x86_64_gnu" @@ -5624,10 +6003,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" [[package]] -name = "windows_x86_64_gnullvm" -version = "0.42.2" +name = "windows_x86_64_gnu" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" +checksum = "5eee091590e89cc02ad514ffe3ead9eb6b660aedca2183455434b93546371a03" [[package]] name = "windows_x86_64_gnullvm" @@ -5636,10 +6015,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" [[package]] -name = "windows_x86_64_msvc" -version = "0.42.2" +name = "windows_x86_64_gnullvm" +version = "0.52.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" +checksum = "77ca79f2451b49fa9e2af39f0747fe999fcda4f5e241b2898624dca97a1f2177" [[package]] name = "windows_x86_64_msvc" @@ -5647,6 +6026,12 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32b752e52a2da0ddfbdbcc6fceadfeede4c939ed16d13e648833a61dfb611ed8" + [[package]] name = "winnow" version = "0.5.15" @@ -5729,7 +6114,7 @@ checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] @@ -5749,7 +6134,7 @@ checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" dependencies = [ "proc-macro2", "quote", - "syn 2.0.37", + "syn 2.0.55", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index 78a2c739fd..a6abc075cc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -9,6 +9,7 @@ members = [ "avm", "cli", "client", + "idl", "lang", "lang/attribute/*", "lang/derive/*", diff --git a/Makefile b/Makefile index 8d3c6d4e5f..9ab0f04274 100644 --- a/Makefile +++ b/Makefile @@ -15,6 +15,8 @@ publish: sleep 25 cd lang/derive/accounts/ && cargo publish && cd ../../../ sleep 25 + cd lang/derive/serde/ && cargo publish && cd ../../../ + sleep 25 cd lang/derive/space/ && cargo publish && cd ../../../ sleep 25 cd lang/attribute/access-control/ && cargo publish && cd ../../../ diff --git a/VERSION b/VERSION index ae6dd4e203..1a44cad74d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -0.29.0 +0.30.1 diff --git a/avm/Cargo.toml b/avm/Cargo.toml index d13060b7c3..0571015a55 100644 --- a/avm/Cargo.toml +++ b/avm/Cargo.toml @@ -1,7 +1,6 @@ [package] name = "avm" -version = "0.29.0" -rust-version = "1.60" +version = "0.30.1" edition = "2021" [[bin]] @@ -15,7 +14,7 @@ path = "src/anchor/main.rs" [dependencies] anyhow = "1.0.32" cfg-if = "1.0.0" -cargo_toml = "0.15.3" +cargo_toml = "0.19.2" clap = { version = "4.2.4", features = ["derive"] } dirs = "4.0.0" once_cell = "1.8.0" @@ -23,3 +22,4 @@ reqwest = { version = "0.11.9", default-features = false, features = ["blocking" semver = "1.0.4" serde = { version = "1.0.136", features = ["derive"] } tempfile = "3.3.0" +chrono = "0.4" diff --git a/avm/src/lib.rs b/avm/src/lib.rs index 32881f9c81..bbc6b4223d 100644 --- a/avm/src/lib.rs +++ b/avm/src/lib.rs @@ -1,5 +1,6 @@ -use anyhow::{anyhow, Result}; +use anyhow::{anyhow, Error, Result}; use cargo_toml::Manifest; +use chrono::{TimeZone, Utc}; use once_cell::sync::Lazy; use reqwest::header::USER_AGENT; use reqwest::StatusCode; @@ -10,26 +11,30 @@ use std::io::Write; use std::path::PathBuf; use std::process::Stdio; -/// Storage directory for AVM, ~/.avm +/// Storage directory for AVM, customizable by setting the $AVM_HOME, defaults to ~/.avm pub static AVM_HOME: Lazy = Lazy::new(|| { cfg_if::cfg_if! { if #[cfg(test)] { let dir = tempfile::tempdir().expect("Could not create temporary directory"); dir.path().join(".avm") } else { - let mut user_home = dirs::home_dir().expect("Could not find home directory"); - user_home.push(".avm"); - user_home + if let Ok(avm_home) = std::env::var("AVM_HOME") { + PathBuf::from(avm_home) + } else { + let mut user_home = dirs::home_dir().expect("Could not find home directory"); + user_home.push(".avm"); + user_home + } } } }); -/// Path to the current version file ~/.avm/.version +/// Path to the current version file $AVM_HOME/.version fn current_version_file_path() -> PathBuf { AVM_HOME.join(".version") } -/// Path to the current version file ~/.avm/bin +/// Path to the current version file $AVM_HOME/bin fn get_bin_dir_path() -> PathBuf { AVM_HOME.join("bin") } @@ -240,7 +245,7 @@ pub fn read_anchorversion_file() -> Result { /// Retrieve a list of installable versions of anchor-cli using the GitHub API and tags on the Anchor /// repository. -pub fn fetch_versions() -> Result> { +pub fn fetch_versions() -> Result, Error> { #[derive(Deserialize)] struct Release { #[serde(rename = "name", deserialize_with = "version_deserializer")] @@ -255,16 +260,30 @@ pub fn fetch_versions() -> Result> { Version::parse(s.trim_start_matches('v')).map_err(de::Error::custom) } - let versions = reqwest::blocking::Client::new() + let response = reqwest::blocking::Client::new() .get("https://api.github.com/repos/coral-xyz/anchor/tags") .header(USER_AGENT, "avm https://github.com/coral-xyz/anchor") - .send()? - .json::>()? - .into_iter() - .map(|release| release.version) - .collect(); + .send()?; - Ok(versions) + if response.status().is_success() { + let releases: Vec = response.json()?; + let versions = releases.into_iter().map(|r| r.version).collect(); + Ok(versions) + } else { + let reset_time_header = response + .headers() + .get("X-RateLimit-Reset") + .map_or("unknown", |v| v.to_str().unwrap()); + let t = Utc.timestamp_opt(reset_time_header.parse::().unwrap(), 0); + let reset_time = t + .single() + .map(|t| t.format("%Y-%m-%d %H:%M:%S").to_string()) + .unwrap_or_else(|| "unknown".to_string()); + Err(anyhow!( + "GitHub API rate limit exceeded. Try again after {} UTC.", + reset_time + )) + } } /// Print available versions and flags indicating installed, current and latest diff --git a/bench/BINARY_SIZE.md b/bench/BINARY_SIZE.md index ef36554168..8c2718d54e 100644 --- a/bench/BINARY_SIZE.md +++ b/bench/BINARY_SIZE.md @@ -14,14 +14,40 @@ The programs and their tests are located in [/tests/bench](https://github.com/co ## [Unreleased] -Solana version: 1.17.0 +Solana version: 1.18.17 + +| Program | Binary Size | - | +| ------- | ----------- | --------------------- | +| bench | 787,968 | 🟢 **-3,040 (0.38%)** | + +### Notable changes + +--- + +## [0.30.1] + +Solana version: 1.18.17 + +| Program | Binary Size | - | +| ------- | ----------- | --- | +| bench | 791,008 | - | + +### Notable changes + +--- -| Program | Binary Size | - | -| ------- | ----------- | ------------------- | -| bench | 743,208 | 🔴 **+152 (0.02%)** | +## [0.30.0] + +Solana version: 1.18.8 + +| Program | Binary Size | - | +| ------- | ----------- | ---------------------- | +| bench | 791,008 | 🔴 **+47,952 (6.45%)** | ### Notable changes +- Upgrade Solana to `1.18.8` ([#2867](https://github.com/coral-xyz/anchor/pull/2867)). + --- ## [0.29.0] diff --git a/bench/COMPUTE_UNITS.md b/bench/COMPUTE_UNITS.md index 9c969678b4..8df52c30a2 100644 --- a/bench/COMPUTE_UNITS.md +++ b/bench/COMPUTE_UNITS.md @@ -14,102 +14,303 @@ The programs and their tests are located in [/tests/bench](https://github.com/co ## [Unreleased] -Solana version: 1.17.0 +Solana version: 1.18.17 + +| Instruction | Compute Units | - | +| --------------------------- | ------------- | -------------------- | +| accountInfo1 | 573 | 🟢 **-28 (4.66%)** | +| accountInfo2 | 899 | 🟢 **-24 (2.60%)** | +| accountInfo4 | 1,561 | 🟢 **-22 (1.39%)** | +| accountInfo8 | 2,957 | 🟢 **-18 (0.61%)** | +| accountEmptyInit1 | 4,976 | 🟢 **-58 (1.15%)** | +| accountEmpty1 | 649 | 🟢 **-3 (0.46%)** | +| accountEmptyInit2 | 9,590 | 🟢 **-97 (1.00%)** | +| accountEmpty2 | 1,015 | 🟢 **-1 (0.10%)** | +| accountEmptyInit4 | 18,323 | 🟢 **-178 (0.96%)** | +| accountEmpty4 | 1,740 | 🔴 **+3 (0.17%)** | +| accountEmptyInit8 | 35,827 | 🟢 **-342 (0.95%)** | +| accountEmpty8 | 3,193 | 🔴 **+7 (0.22%)** | +| accountSizedInit1 | 5,070 | 🟢 **-36 (0.71%)** | +| accountSized1 | 690 | 🔴 **+22 (3.29%)** | +| accountSizedInit2 | 9,750 | 🟢 **-78 (0.79%)** | +| accountSized2 | 1,069 | 🔴 **+23 (2.20%)** | +| accountSizedInit4 | 18,677 | 🟢 **-160 (0.85%)** | +| accountSized4 | 1,834 | 🔴 **+27 (1.49%)** | +| accountSizedInit8 | 36,426 | 🟢 **-335 (0.91%)** | +| accountSized8 | 3,357 | 🔴 **+31 (0.93%)** | +| accountUnsizedInit1 | 5,190 | 🟢 **-9 (0.17%)** | +| accountUnsized1 | 747 | 🔴 **+45 (6.41%)** | +| accountUnsizedInit2 | 10,033 | 🟢 **-45 (0.45%)** | +| accountUnsized2 | 1,165 | 🔴 **+49 (4.39%)** | +| accountUnsizedInit4 | 19,134 | 🟢 **-125 (0.65%)** | +| accountUnsized4 | 2,004 | 🔴 **+51 (2.61%)** | +| accountUnsizedInit8 | 37,046 | 🟢 **-285 (0.76%)** | +| accountUnsized8 | 3,679 | 🔴 **+53 (1.46%)** | +| boxedAccountEmptyInit1 | 5,078 | 🔴 **+14 (0.28%)** | +| boxedAccountEmpty1 | 740 | 🔴 **+69 (10.28%)** | +| boxedAccountEmptyInit2 | 9,697 | 🟢 **-24 (0.25%)** | +| boxedAccountEmpty2 | 1,125 | 🔴 **+73 (6.94%)** | +| boxedAccountEmptyInit4 | 18,477 | 🟢 **-105 (0.57%)** | +| boxedAccountEmpty4 | 1,886 | 🔴 **+75 (4.14%)** | +| boxedAccountEmptyInit8 | 36,059 | 🟢 **-270 (0.74%)** | +| boxedAccountEmpty8 | 3,435 | 🔴 **+78 (2.32%)** | +| boxedAccountSizedInit1 | 5,157 | 🔴 **+38 (0.74%)** | +| boxedAccountSized1 | 780 | 🔴 **+94 (13.70%)** | +| boxedAccountSizedInit2 | 9,842 | 🟢 **-3 (0.03%)** | +| boxedAccountSized2 | 1,180 | 🔴 **+95 (8.76%)** | +| boxedAccountSizedInit4 | 18,736 | 🟢 **-89 (0.47%)** | +| boxedAccountSized4 | 1,974 | 🔴 **+100 (5.34%)** | +| boxedAccountSizedInit8 | 36,563 | 🟢 **-261 (0.71%)** | +| boxedAccountSized8 | 3,593 | 🔴 **+103 (2.95%)** | +| boxedAccountUnsizedInit1 | 5,271 | 🔴 **+64 (1.23%)** | +| boxedAccountUnsized1 | 839 | 🔴 **+118 (16.37%)** | +| boxedAccountUnsizedInit2 | 10,040 | 🔴 **+25 (0.25%)** | +| boxedAccountUnsized2 | 1,277 | 🔴 **+120 (10.37%)** | +| boxedAccountUnsizedInit4 | 19,108 | 🟢 **-52 (0.27%)** | +| boxedAccountUnsized4 | 2,142 | 🔴 **+123 (6.09%)** | +| boxedAccountUnsizedInit8 | 37,283 | 🟢 **-213 (0.57%)** | +| boxedAccountUnsized8 | 3,903 | 🔴 **+127 (3.36%)** | +| boxedInterfaceAccountMint1 | 1,502 | 🔴 **+130 (9.48%)** | +| boxedInterfaceAccountMint2 | 2,423 | 🔴 **+130 (5.67%)** | +| boxedInterfaceAccountMint4 | 4,256 | 🔴 **+135 (3.28%)** | +| boxedInterfaceAccountMint8 | 7,950 | 🔴 **+139 (1.78%)** | +| boxedInterfaceAccountToken1 | 2,198 | 🔴 **+142 (6.91%)** | +| boxedInterfaceAccountToken2 | 3,803 | 🔴 **+143 (3.91%)** | +| boxedInterfaceAccountToken4 | 7,004 | 🔴 **+146 (2.13%)** | +| boxedInterfaceAccountToken8 | 13,434 | 🔴 **+150 (1.13%)** | +| interfaceAccountMint1 | 1,626 | 🔴 **+154 (10.46%)** | +| interfaceAccountMint2 | 2,788 | 🔴 **+157 (5.97%)** | +| interfaceAccountMint4 | 5,110 | 🔴 **+159 (3.21%)** | +| interfaceAccountMint8 | 9,749 | 🔴 **+161 (1.68%)** | +| interfaceAccountToken1 | 2,296 | 🔴 **+166 (7.79%)** | +| interfaceAccountToken2 | 4,096 | 🔴 **+168 (4.28%)** | +| interfaceAccountToken4 | 7,692 | 🔴 **+171 (2.27%)** | +| interface1 | 774 | 🔴 **+174 (29.00%)** | +| interface2 | 923 | 🔴 **+178 (23.89%)** | +| interface4 | 1,214 | 🔴 **+181 (17.52%)** | +| interface8 | 1,799 | 🔴 **+183 (11.32%)** | +| program1 | 782 | 🔴 **+186 (31.21%)** | +| program2 | 927 | 🔴 **+190 (25.78%)** | +| program4 | 1,210 | 🔴 **+191 (18.74%)** | +| program8 | 1,779 | 🔴 **+195 (12.31%)** | +| signer1 | 779 | 🔴 **+199 (34.31%)** | +| signer2 | 1,074 | 🔴 **+202 (23.17%)** | +| signer4 | 1,657 | 🔴 **+203 (13.96%)** | +| signer8 | 2,826 | 🔴 **+208 (7.94%)** | +| systemAccount1 | 802 | 🔴 **+210 (35.47%)** | +| systemAccount2 | 1,108 | 🔴 **+214 (23.94%)** | +| systemAccount4 | 1,713 | 🔴 **+216 (14.43%)** | +| systemAccount8 | 2,926 | 🔴 **+219 (8.09%)** | +| uncheckedAccount1 | 785 | 🔴 **+222 (39.43%)** | +| uncheckedAccount2 | 1,061 | 🔴 **+225 (26.91%)** | +| uncheckedAccount4 | 1,604 | 🔴 **+226 (16.40%)** | +| uncheckedAccount8 | 2,699 | 🔴 **+231 (9.36%)** | + +### Notable changes + +- lang: Update `dispatch` function to support dynamic discriminators ([#3104](https://github.com/coral-xyz/anchor/pull/3104)). +- lang: Remove unnecessary clone in account exit routine ([#3139](https://github.com/coral-xyz/anchor/pull/3139)). + +--- + +## [0.30.1] + +Solana version: 1.18.17 | Instruction | Compute Units | - | | --------------------------- | ------------- | --- | -| accountInfo1 | 695 | - | -| accountInfo2 | 1,035 | - | -| accountInfo4 | 1,730 | - | -| accountInfo8 | 3,342 | - | -| accountEmptyInit1 | 5,552 | - | -| accountEmpty1 | 819 | - | -| accountEmptyInit2 | 10,421 | - | -| accountEmpty2 | 1,275 | - | -| accountEmptyInit4 | 19,803 | - | -| accountEmpty4 | 2,177 | - | -| accountEmptyInit8 | 38,609 | - | -| accountEmpty8 | 3,990 | - | -| accountSizedInit1 | 5,647 | - | -| accountSized1 | 843 | - | -| accountSizedInit2 | 10,607 | - | -| accountSized2 | 1,317 | - | -| accountSizedInit4 | 20,225 | - | -| accountSized4 | 2,274 | - | -| accountSizedInit8 | 39,376 | - | -| accountSized8 | 4,185 | - | -| accountUnsizedInit1 | 5,740 | - | -| accountUnsized1 | 870 | - | -| accountUnsizedInit2 | 10,856 | - | -| accountUnsized2 | 1,379 | - | -| accountUnsizedInit4 | 20,652 | - | -| accountUnsized4 | 2,411 | - | -| accountUnsizedInit8 | 39,969 | - | -| accountUnsized8 | 4,478 | - | -| boxedAccountEmptyInit1 | 5,605 | - | -| boxedAccountEmpty1 | 856 | - | -| boxedAccountEmptyInit2 | 10,522 | - | -| boxedAccountEmpty2 | 1,347 | - | -| boxedAccountEmptyInit4 | 20,002 | - | -| boxedAccountEmpty4 | 2,324 | - | -| boxedAccountEmptyInit8 | 39,002 | - | -| boxedAccountEmpty8 | 4,311 | - | -| boxedAccountSizedInit1 | 5,686 | - | -| boxedAccountSized1 | 878 | - | -| boxedAccountSizedInit2 | 10,690 | - | -| boxedAccountSized2 | 1,394 | - | -| boxedAccountSizedInit4 | 20,338 | - | -| boxedAccountSized4 | 2,413 | - | -| boxedAccountSizedInit8 | 39,670 | - | -| boxedAccountSized8 | 4,493 | - | -| boxedAccountUnsizedInit1 | 5,774 | - | -| boxedAccountUnsized1 | 908 | - | -| boxedAccountUnsizedInit2 | 10,866 | - | -| boxedAccountUnsized2 | 1,457 | - | -| boxedAccountUnsizedInit4 | 20,688 | - | -| boxedAccountUnsized4 | 2,546 | - | -| boxedAccountUnsizedInit8 | 40,375 | - | -| boxedAccountUnsized8 | 4,759 | - | -| boxedInterfaceAccountMint1 | 2,196 | - | -| boxedInterfaceAccountMint2 | 3,847 | - | -| boxedInterfaceAccountMint4 | 7,132 | - | -| boxedInterfaceAccountMint8 | 13,743 | - | -| boxedInterfaceAccountToken1 | 2,126 | - | -| boxedInterfaceAccountToken2 | 3,706 | - | -| boxedInterfaceAccountToken4 | 6,853 | - | -| boxedInterfaceAccountToken8 | 13,184 | - | -| interfaceAccountMint1 | 2,285 | - | -| interfaceAccountMint2 | 4,178 | - | -| interfaceAccountMint4 | 7,964 | - | -| interfaceAccountMint8 | 15,538 | - | -| interfaceAccountToken1 | 2,212 | - | -| interfaceAccountToken2 | 4,030 | - | -| interfaceAccountToken4 | 7,663 | - | -| interface1 | 741 | - | -| interface2 | 934 | - | -| interface4 | 1,315 | - | -| interface8 | 2,086 | - | -| program1 | 741 | - | -| program2 | 934 | - | -| program4 | 1,317 | - | -| program8 | 2,086 | - | -| signer1 | 675 | - | -| signer2 | 987 | - | -| signer4 | 1,606 | - | -| signer8 | 2,846 | - | -| systemAccount1 | 729 | - | -| systemAccount2 | 1,093 | - | -| systemAccount4 | 1,817 | - | -| systemAccount8 | 3,271 | - | -| uncheckedAccount1 | 657 | - | -| uncheckedAccount2 | 949 | - | -| uncheckedAccount4 | 1,526 | - | -| uncheckedAccount8 | 2,688 | - | +| accountInfo1 | 601 | - | +| accountInfo2 | 923 | - | +| accountInfo4 | 1,583 | - | +| accountInfo8 | 2,975 | - | +| accountEmptyInit1 | 5,034 | - | +| accountEmpty1 | 652 | - | +| accountEmptyInit2 | 9,687 | - | +| accountEmpty2 | 1,016 | - | +| accountEmptyInit4 | 18,501 | - | +| accountEmpty4 | 1,737 | - | +| accountEmptyInit8 | 36,169 | - | +| accountEmpty8 | 3,186 | - | +| accountSizedInit1 | 5,106 | - | +| accountSized1 | 668 | - | +| accountSizedInit2 | 9,828 | - | +| accountSized2 | 1,046 | - | +| accountSizedInit4 | 18,837 | - | +| accountSized4 | 1,807 | - | +| accountSizedInit8 | 36,761 | - | +| accountSized8 | 3,326 | - | +| accountUnsizedInit1 | 5,199 | - | +| accountUnsized1 | 702 | - | +| accountUnsizedInit2 | 10,078 | - | +| accountUnsized2 | 1,116 | - | +| accountUnsizedInit4 | 19,259 | - | +| accountUnsized4 | 1,953 | - | +| accountUnsizedInit8 | 37,331 | - | +| accountUnsized8 | 3,626 | - | +| boxedAccountEmptyInit1 | 5,064 | - | +| boxedAccountEmpty1 | 671 | - | +| boxedAccountEmptyInit2 | 9,721 | - | +| boxedAccountEmpty2 | 1,052 | - | +| boxedAccountEmptyInit4 | 18,582 | - | +| boxedAccountEmpty4 | 1,811 | - | +| boxedAccountEmptyInit8 | 36,329 | - | +| boxedAccountEmpty8 | 3,357 | - | +| boxedAccountSizedInit1 | 5,119 | - | +| boxedAccountSized1 | 686 | - | +| boxedAccountSizedInit2 | 9,845 | - | +| boxedAccountSized2 | 1,085 | - | +| boxedAccountSizedInit4 | 18,825 | - | +| boxedAccountSized4 | 1,874 | - | +| boxedAccountSizedInit8 | 36,824 | - | +| boxedAccountSized8 | 3,490 | - | +| boxedAccountUnsizedInit1 | 5,207 | - | +| boxedAccountUnsized1 | 721 | - | +| boxedAccountUnsizedInit2 | 10,015 | - | +| boxedAccountUnsized2 | 1,157 | - | +| boxedAccountUnsizedInit4 | 19,160 | - | +| boxedAccountUnsized4 | 2,019 | - | +| boxedAccountUnsizedInit8 | 37,496 | - | +| boxedAccountUnsized8 | 3,776 | - | +| boxedInterfaceAccountMint1 | 1,372 | - | +| boxedInterfaceAccountMint2 | 2,293 | - | +| boxedInterfaceAccountMint4 | 4,121 | - | +| boxedInterfaceAccountMint8 | 7,811 | - | +| boxedInterfaceAccountToken1 | 2,056 | - | +| boxedInterfaceAccountToken2 | 3,660 | - | +| boxedInterfaceAccountToken4 | 6,858 | - | +| boxedInterfaceAccountToken8 | 13,284 | - | +| interfaceAccountMint1 | 1,472 | - | +| interfaceAccountMint2 | 2,631 | - | +| interfaceAccountMint4 | 4,951 | - | +| interfaceAccountMint8 | 9,588 | - | +| interfaceAccountToken1 | 2,130 | - | +| interfaceAccountToken2 | 3,928 | - | +| interfaceAccountToken4 | 7,521 | - | +| interface1 | 600 | - | +| interface2 | 745 | - | +| interface4 | 1,033 | - | +| interface8 | 1,616 | - | +| program1 | 596 | - | +| program2 | 737 | - | +| program4 | 1,019 | - | +| program8 | 1,584 | - | +| signer1 | 580 | - | +| signer2 | 872 | - | +| signer4 | 1,454 | - | +| signer8 | 2,618 | - | +| systemAccount1 | 592 | - | +| systemAccount2 | 894 | - | +| systemAccount4 | 1,497 | - | +| systemAccount8 | 2,707 | - | +| uncheckedAccount1 | 563 | - | +| uncheckedAccount2 | 836 | - | +| uncheckedAccount4 | 1,378 | - | +| uncheckedAccount8 | 2,468 | - | ### Notable changes --- +## [0.30.0] + +Solana version: 1.18.8 + +| Instruction | Compute Units | - | +| --------------------------- | ------------- | ---------------------- | +| accountInfo1 | 601 | 🟢 **-94 (13.53%)** | +| accountInfo2 | 923 | 🟢 **-112 (10.82%)** | +| accountInfo4 | 1,583 | 🟢 **-147 (8.50%)** | +| accountInfo8 | 2,975 | 🟢 **-367 (10.98%)** | +| accountEmptyInit1 | 5,034 | 🟢 **-518 (9.33%)** | +| accountEmpty1 | 652 | 🟢 **-167 (20.39%)** | +| accountEmptyInit2 | 9,687 | 🟢 **-734 (7.04%)** | +| accountEmpty2 | 1,016 | 🟢 **-259 (20.31%)** | +| accountEmptyInit4 | 18,501 | 🟢 **-1,302 (6.57%)** | +| accountEmpty4 | 1,737 | 🟢 **-440 (20.21%)** | +| accountEmptyInit8 | 36,169 | 🟢 **-2,440 (6.32%)** | +| accountEmpty8 | 3,186 | 🟢 **-804 (20.15%)** | +| accountSizedInit1 | 5,106 | 🟢 **-541 (9.58%)** | +| accountSized1 | 668 | 🟢 **-175 (20.76%)** | +| accountSizedInit2 | 9,828 | 🟢 **-779 (7.34%)** | +| accountSized2 | 1,046 | 🟢 **-271 (20.58%)** | +| accountSizedInit4 | 18,837 | 🟢 **-1,388 (6.86%)** | +| accountSized4 | 1,807 | 🟢 **-467 (20.54%)** | +| accountSizedInit8 | 36,761 | 🟢 **-2,615 (6.64%)** | +| accountSized8 | 3,326 | 🟢 **-859 (20.53%)** | +| accountUnsizedInit1 | 5,199 | 🟢 **-541 (9.43%)** | +| accountUnsized1 | 702 | 🟢 **-168 (19.31%)** | +| accountUnsizedInit2 | 10,078 | 🟢 **-778 (7.17%)** | +| accountUnsized2 | 1,116 | 🟢 **-263 (19.07%)** | +| accountUnsizedInit4 | 19,259 | 🟢 **-1,393 (6.75%)** | +| accountUnsized4 | 1,953 | 🟢 **-458 (19.00%)** | +| accountUnsizedInit8 | 37,331 | 🟢 **-2,638 (6.60%)** | +| accountUnsized8 | 3,626 | 🟢 **-852 (19.03%)** | +| boxedAccountEmptyInit1 | 5,064 | 🟢 **-541 (9.65%)** | +| boxedAccountEmpty1 | 671 | 🟢 **-185 (21.61%)** | +| boxedAccountEmptyInit2 | 9,721 | 🟢 **-801 (7.61%)** | +| boxedAccountEmpty2 | 1,052 | 🟢 **-295 (21.90%)** | +| boxedAccountEmptyInit4 | 18,582 | 🟢 **-1,420 (7.10%)** | +| boxedAccountEmpty4 | 1,811 | 🟢 **-513 (22.07%)** | +| boxedAccountEmptyInit8 | 36,329 | 🟢 **-2,673 (6.85%)** | +| boxedAccountEmpty8 | 3,357 | 🟢 **-954 (22.13%)** | +| boxedAccountSizedInit1 | 5,119 | 🟢 **-567 (9.97%)** | +| boxedAccountSized1 | 686 | 🟢 **-192 (21.87%)** | +| boxedAccountSizedInit2 | 9,845 | 🟢 **-845 (7.90%)** | +| boxedAccountSized2 | 1,085 | 🟢 **-309 (22.17%)** | +| boxedAccountSizedInit4 | 18,825 | 🟢 **-1,513 (7.44%)** | +| boxedAccountSized4 | 1,874 | 🟢 **-539 (22.34%)** | +| boxedAccountSizedInit8 | 36,824 | 🟢 **-2,846 (7.17%)** | +| boxedAccountSized8 | 3,490 | 🟢 **-1,003 (22.32%)** | +| boxedAccountUnsizedInit1 | 5,207 | 🟢 **-567 (9.82%)** | +| boxedAccountUnsized1 | 721 | 🟢 **-187 (20.59%)** | +| boxedAccountUnsizedInit2 | 10,015 | 🟢 **-851 (7.83%)** | +| boxedAccountUnsized2 | 1,157 | 🟢 **-300 (20.59%)** | +| boxedAccountUnsizedInit4 | 19,160 | 🟢 **-1,528 (7.39%)** | +| boxedAccountUnsized4 | 2,019 | 🟢 **-527 (20.70%)** | +| boxedAccountUnsizedInit8 | 37,496 | 🟢 **-2,879 (7.13%)** | +| boxedAccountUnsized8 | 3,776 | 🟢 **-983 (20.66%)** | +| boxedInterfaceAccountMint1 | 1,372 | 🟢 **-824 (37.52%)** | +| boxedInterfaceAccountMint2 | 2,293 | 🟢 **-1,554 (40.40%)** | +| boxedInterfaceAccountMint4 | 4,121 | 🟢 **-3,011 (42.22%)** | +| boxedInterfaceAccountMint8 | 7,811 | 🟢 **-5,932 (43.16%)** | +| boxedInterfaceAccountToken1 | 2,056 | 🟢 **-70 (3.29%)** | +| boxedInterfaceAccountToken2 | 3,660 | 🟢 **-46 (1.24%)** | +| boxedInterfaceAccountToken4 | 6,858 | 🔴 **+5 (0.07%)** | +| boxedInterfaceAccountToken8 | 13,284 | 🔴 **+100 (0.76%)** | +| interfaceAccountMint1 | 1,472 | 🟢 **-813 (35.58%)** | +| interfaceAccountMint2 | 2,631 | 🟢 **-1,547 (37.03%)** | +| interfaceAccountMint4 | 4,951 | 🟢 **-3,013 (37.83%)** | +| interfaceAccountMint8 | 9,588 | 🟢 **-5,950 (38.29%)** | +| interfaceAccountToken1 | 2,130 | 🟢 **-82 (3.71%)** | +| interfaceAccountToken2 | 3,928 | 🟢 **-102 (2.53%)** | +| interfaceAccountToken4 | 7,521 | 🟢 **-142 (1.85%)** | +| interface1 | 600 | 🟢 **-141 (19.03%)** | +| interface2 | 745 | 🟢 **-189 (20.24%)** | +| interface4 | 1,033 | 🟢 **-282 (21.44%)** | +| interface8 | 1,616 | 🟢 **-470 (22.53%)** | +| program1 | 596 | 🟢 **-145 (19.57%)** | +| program2 | 737 | 🟢 **-197 (21.09%)** | +| program4 | 1,019 | 🟢 **-298 (22.63%)** | +| program8 | 1,584 | 🟢 **-502 (24.07%)** | +| signer1 | 580 | 🟢 **-95 (14.07%)** | +| signer2 | 872 | 🟢 **-115 (11.65%)** | +| signer4 | 1,454 | 🟢 **-152 (9.46%)** | +| signer8 | 2,618 | 🟢 **-228 (8.01%)** | +| systemAccount1 | 592 | 🟢 **-137 (18.79%)** | +| systemAccount2 | 894 | 🟢 **-199 (18.21%)** | +| systemAccount4 | 1,497 | 🟢 **-320 (17.61%)** | +| systemAccount8 | 2,707 | 🟢 **-564 (17.24%)** | +| uncheckedAccount1 | 563 | 🟢 **-94 (14.31%)** | +| uncheckedAccount2 | 836 | 🟢 **-113 (11.91%)** | +| uncheckedAccount4 | 1,378 | 🟢 **-148 (9.70%)** | +| uncheckedAccount8 | 2,468 | 🟢 **-220 (8.18%)** | + +### Notable changes + +- Upgrade Solana to `1.18.8` ([#2867](https://github.com/coral-xyz/anchor/pull/2867)). + +--- + ## [0.29.0] Solana version: 1.17.0 diff --git a/bench/STACK_MEMORY.md b/bench/STACK_MEMORY.md index 986631d50d..21621c8ee8 100644 --- a/bench/STACK_MEMORY.md +++ b/bench/STACK_MEMORY.md @@ -14,100 +14,298 @@ The programs and their tests are located in [/tests/bench](https://github.com/co ## [Unreleased] -Solana version: 1.17.0 +Solana version: 1.18.17 + +| Instruction | Stack Memory | - | +| ------------------------------ | ------------ | --- | +| account_info1 | 144 | - | +| account_info2 | 144 | - | +| account_info4 | 144 | - | +| account_info8 | 144 | - | +| account_empty_init1 | 144 | - | +| account_empty_init2 | 144 | - | +| account_empty_init4 | 192 | - | +| account_empty_init8 | 224 | - | +| account_empty1 | 144 | - | +| account_empty2 | 144 | - | +| account_empty4 | 144 | - | +| account_empty8 | 144 | - | +| account_sized_init1 | 176 | - | +| account_sized_init2 | 192 | - | +| account_sized_init4 | 224 | - | +| account_sized_init8 | 288 | - | +| account_sized1 | 144 | - | +| account_sized2 | 144 | - | +| account_sized4 | 144 | - | +| account_sized8 | 144 | - | +| account_unsized_init1 | 192 | - | +| account_unsized_init2 | 224 | - | +| account_unsized_init4 | 288 | - | +| account_unsized_init8 | 416 | - | +| account_unsized1 | 144 | - | +| account_unsized2 | 144 | - | +| account_unsized4 | 144 | - | +| account_unsized8 | 144 | - | +| boxed_account_empty_init1 | 144 | - | +| boxed_account_empty_init2 | 144 | - | +| boxed_account_empty_init4 | 192 | - | +| boxed_account_empty_init8 | 224 | - | +| boxed_account_empty1 | 144 | - | +| boxed_account_empty2 | 144 | - | +| boxed_account_empty4 | 144 | - | +| boxed_account_empty8 | 144 | - | +| boxed_account_sized_init1 | 144 | - | +| boxed_account_sized_init2 | 144 | - | +| boxed_account_sized_init4 | 192 | - | +| boxed_account_sized_init8 | 224 | - | +| boxed_account_sized1 | 144 | - | +| boxed_account_sized2 | 144 | - | +| boxed_account_sized4 | 144 | - | +| boxed_account_sized8 | 144 | - | +| boxed_account_unsized_init1 | 144 | - | +| boxed_account_unsized_init2 | 144 | - | +| boxed_account_unsized_init4 | 192 | - | +| boxed_account_unsized_init8 | 224 | - | +| boxed_account_unsized1 | 144 | - | +| boxed_account_unsized2 | 144 | - | +| boxed_account_unsized4 | 144 | - | +| boxed_account_unsized8 | 144 | - | +| boxed_interface_account_mint1 | 144 | - | +| boxed_interface_account_mint2 | 144 | - | +| boxed_interface_account_mint4 | 144 | - | +| boxed_interface_account_mint8 | 144 | - | +| boxed_interface_account_token1 | 144 | - | +| boxed_interface_account_token2 | 144 | - | +| boxed_interface_account_token4 | 144 | - | +| boxed_interface_account_token8 | 144 | - | +| interface_account_mint1 | 144 | - | +| interface_account_mint2 | 144 | - | +| interface_account_mint4 | 144 | - | +| interface_account_mint8 | 144 | - | +| interface_account_token1 | 144 | - | +| interface_account_token2 | 144 | - | +| interface_account_token4 | 144 | - | +| interface1 | 144 | - | +| interface2 | 144 | - | +| interface4 | 144 | - | +| interface8 | 144 | - | +| program1 | 144 | - | +| program2 | 144 | - | +| program4 | 144 | - | +| program8 | 144 | - | +| signer1 | 144 | - | +| signer2 | 144 | - | +| signer4 | 144 | - | +| signer8 | 144 | - | +| system_account1 | 144 | - | +| system_account2 | 144 | - | +| system_account4 | 144 | - | +| system_account8 | 144 | - | +| unchecked_account1 | 144 | - | +| unchecked_account2 | 144 | - | +| unchecked_account4 | 144 | - | +| unchecked_account8 | 144 | - | + +### Notable changes + +--- + +## [0.30.1] + +Solana version: 1.18.17 | Instruction | Stack Memory | - | | ------------------------------ | ------------ | --- | -| account_info1 | 128 | - | -| account_info2 | 128 | - | -| account_info4 | 128 | - | -| account_info8 | 128 | - | -| account_empty_init1 | 176 | - | -| account_empty_init2 | 208 | - | -| account_empty_init4 | 208 | - | -| account_empty_init8 | 240 | - | -| account_empty1 | 128 | - | -| account_empty2 | 128 | - | -| account_empty4 | 128 | - | -| account_empty8 | 128 | - | -| account_sized_init1 | 208 | - | -| account_sized_init2 | 256 | - | -| account_sized_init4 | 240 | - | -| account_sized_init8 | 304 | - | -| account_sized1 | 128 | - | -| account_sized2 | 128 | - | -| account_sized4 | 128 | - | -| account_sized8 | 128 | - | -| account_unsized_init1 | 224 | - | -| account_unsized_init2 | 296 | - | -| account_unsized_init4 | 304 | - | -| account_unsized_init8 | 432 | - | -| account_unsized1 | 128 | - | +| account_info1 | 144 | - | +| account_info2 | 144 | - | +| account_info4 | 144 | - | +| account_info8 | 144 | - | +| account_empty_init1 | 144 | - | +| account_empty_init2 | 144 | - | +| account_empty_init4 | 192 | - | +| account_empty_init8 | 224 | - | +| account_empty1 | 144 | - | +| account_empty2 | 144 | - | +| account_empty4 | 144 | - | +| account_empty8 | 144 | - | +| account_sized_init1 | 176 | - | +| account_sized_init2 | 192 | - | +| account_sized_init4 | 224 | - | +| account_sized_init8 | 288 | - | +| account_sized1 | 144 | - | +| account_sized2 | 144 | - | +| account_sized4 | 144 | - | +| account_sized8 | 144 | - | +| account_unsized_init1 | 192 | - | +| account_unsized_init2 | 224 | - | +| account_unsized_init4 | 288 | - | +| account_unsized_init8 | 416 | - | +| account_unsized1 | 144 | - | | account_unsized2 | 144 | - | -| account_unsized4 | 128 | - | -| account_unsized8 | 128 | - | -| boxed_account_empty_init1 | 176 | - | -| boxed_account_empty_init2 | 208 | - | -| boxed_account_empty_init4 | 208 | - | -| boxed_account_empty_init8 | 240 | - | -| boxed_account_empty1 | 128 | - | -| boxed_account_empty2 | 128 | - | +| account_unsized4 | 144 | - | +| account_unsized8 | 144 | - | +| boxed_account_empty_init1 | 144 | - | +| boxed_account_empty_init2 | 144 | - | +| boxed_account_empty_init4 | 192 | - | +| boxed_account_empty_init8 | 224 | - | +| boxed_account_empty1 | 144 | - | +| boxed_account_empty2 | 144 | - | | boxed_account_empty4 | 144 | - | | boxed_account_empty8 | 144 | - | -| boxed_account_sized_init1 | 176 | - | -| boxed_account_sized_init2 | 208 | - | -| boxed_account_sized_init4 | 208 | - | -| boxed_account_sized_init8 | 240 | - | -| boxed_account_sized1 | 128 | - | -| boxed_account_sized2 | 128 | - | +| boxed_account_sized_init1 | 144 | - | +| boxed_account_sized_init2 | 144 | - | +| boxed_account_sized_init4 | 192 | - | +| boxed_account_sized_init8 | 224 | - | +| boxed_account_sized1 | 144 | - | +| boxed_account_sized2 | 144 | - | | boxed_account_sized4 | 144 | - | | boxed_account_sized8 | 144 | - | -| boxed_account_unsized_init1 | 176 | - | -| boxed_account_unsized_init2 | 208 | - | -| boxed_account_unsized_init4 | 208 | - | -| boxed_account_unsized_init8 | 240 | - | -| boxed_account_unsized1 | 128 | - | +| boxed_account_unsized_init1 | 144 | - | +| boxed_account_unsized_init2 | 144 | - | +| boxed_account_unsized_init4 | 192 | - | +| boxed_account_unsized_init8 | 224 | - | +| boxed_account_unsized1 | 144 | - | | boxed_account_unsized2 | 144 | - | -| boxed_account_unsized4 | 128 | - | -| boxed_account_unsized8 | 128 | - | -| boxed_interface_account_mint1 | 128 | - | -| boxed_interface_account_mint2 | 128 | - | +| boxed_account_unsized4 | 144 | - | +| boxed_account_unsized8 | 144 | - | +| boxed_interface_account_mint1 | 144 | - | +| boxed_interface_account_mint2 | 144 | - | | boxed_interface_account_mint4 | 144 | - | | boxed_interface_account_mint8 | 144 | - | -| boxed_interface_account_token1 | 128 | - | -| boxed_interface_account_token2 | 128 | - | +| boxed_interface_account_token1 | 144 | - | +| boxed_interface_account_token2 | 144 | - | | boxed_interface_account_token4 | 144 | - | | boxed_interface_account_token8 | 144 | - | -| interface_account_mint1 | 128 | - | -| interface_account_mint2 | 128 | - | -| interface_account_mint4 | 128 | - | -| interface_account_mint8 | 128 | - | -| interface_account_token1 | 128 | - | -| interface_account_token2 | 128 | - | -| interface_account_token4 | 128 | - | -| interface1 | 128 | - | -| interface2 | 128 | - | -| interface4 | 128 | - | -| interface8 | 128 | - | -| program1 | 128 | - | -| program2 | 128 | - | -| program4 | 128 | - | -| program8 | 128 | - | -| signer1 | 128 | - | -| signer2 | 128 | - | -| signer4 | 128 | - | -| signer8 | 128 | - | -| system_account1 | 128 | - | -| system_account2 | 128 | - | -| system_account4 | 128 | - | -| system_account8 | 128 | - | -| unchecked_account1 | 128 | - | -| unchecked_account2 | 128 | - | -| unchecked_account4 | 128 | - | -| unchecked_account8 | 128 | - | +| interface_account_mint1 | 144 | - | +| interface_account_mint2 | 144 | - | +| interface_account_mint4 | 144 | - | +| interface_account_mint8 | 144 | - | +| interface_account_token1 | 144 | - | +| interface_account_token2 | 144 | - | +| interface_account_token4 | 144 | - | +| interface1 | 144 | - | +| interface2 | 144 | - | +| interface4 | 144 | - | +| interface8 | 144 | - | +| program1 | 144 | - | +| program2 | 144 | - | +| program4 | 144 | - | +| program8 | 144 | - | +| signer1 | 144 | - | +| signer2 | 144 | - | +| signer4 | 144 | - | +| signer8 | 144 | - | +| system_account1 | 144 | - | +| system_account2 | 144 | - | +| system_account4 | 144 | - | +| system_account8 | 144 | - | +| unchecked_account1 | 144 | - | +| unchecked_account2 | 144 | - | +| unchecked_account4 | 144 | - | +| unchecked_account8 | 144 | - | + +### Notable changes + +--- + +## [0.30.0] + +Solana version: 1.18.8 + +| Instruction | Stack Memory | - | +| ------------------------------ | ------------ | ------------------- | +| account_info1 | 144 | 🔴 **+16 (12.50%)** | +| account_info2 | 144 | 🔴 **+16 (12.50%)** | +| account_info4 | 144 | 🔴 **+16 (12.50%)** | +| account_info8 | 144 | 🔴 **+16 (12.50%)** | +| account_empty_init1 | 144 | 🟢 **-32 (18.18%)** | +| account_empty_init2 | 144 | 🟢 **-64 (30.77%)** | +| account_empty_init4 | 192 | 🟢 **-16 (7.69%)** | +| account_empty_init8 | 224 | 🟢 **-16 (6.67%)** | +| account_empty1 | 144 | 🔴 **+16 (12.50%)** | +| account_empty2 | 144 | 🔴 **+16 (12.50%)** | +| account_empty4 | 144 | 🔴 **+16 (12.50%)** | +| account_empty8 | 144 | 🔴 **+16 (12.50%)** | +| account_sized_init1 | 176 | 🟢 **-32 (15.38%)** | +| account_sized_init2 | 192 | 🟢 **-64 (25.00%)** | +| account_sized_init4 | 224 | 🟢 **-16 (6.67%)** | +| account_sized_init8 | 288 | 🟢 **-16 (5.26%)** | +| account_sized1 | 144 | 🔴 **+16 (12.50%)** | +| account_sized2 | 144 | 🔴 **+16 (12.50%)** | +| account_sized4 | 144 | 🔴 **+16 (12.50%)** | +| account_sized8 | 144 | 🔴 **+16 (12.50%)** | +| account_unsized_init1 | 192 | 🟢 **-32 (14.29%)** | +| account_unsized_init2 | 224 | 🟢 **-72 (24.32%)** | +| account_unsized_init4 | 288 | 🟢 **-16 (5.26%)** | +| account_unsized_init8 | 416 | 🟢 **-16 (3.70%)** | +| account_unsized1 | 144 | 🔴 **+16 (12.50%)** | +| account_unsized2 | 144 | - | +| account_unsized4 | 144 | 🔴 **+16 (12.50%)** | +| account_unsized8 | 144 | 🔴 **+16 (12.50%)** | +| boxed_account_empty_init1 | 144 | 🟢 **-32 (18.18%)** | +| boxed_account_empty_init2 | 144 | 🟢 **-64 (30.77%)** | +| boxed_account_empty_init4 | 192 | 🟢 **-16 (7.69%)** | +| boxed_account_empty_init8 | 224 | 🟢 **-16 (6.67%)** | +| boxed_account_empty1 | 144 | 🔴 **+16 (12.50%)** | +| boxed_account_empty2 | 144 | 🔴 **+16 (12.50%)** | +| boxed_account_empty4 | 144 | - | +| boxed_account_empty8 | 144 | - | +| boxed_account_sized_init1 | 144 | 🟢 **-32 (18.18%)** | +| boxed_account_sized_init2 | 144 | 🟢 **-64 (30.77%)** | +| boxed_account_sized_init4 | 192 | 🟢 **-16 (7.69%)** | +| boxed_account_sized_init8 | 224 | 🟢 **-16 (6.67%)** | +| boxed_account_sized1 | 144 | 🔴 **+16 (12.50%)** | +| boxed_account_sized2 | 144 | 🔴 **+16 (12.50%)** | +| boxed_account_sized4 | 144 | - | +| boxed_account_sized8 | 144 | - | +| boxed_account_unsized_init1 | 144 | 🟢 **-32 (18.18%)** | +| boxed_account_unsized_init2 | 144 | 🟢 **-64 (30.77%)** | +| boxed_account_unsized_init4 | 192 | 🟢 **-16 (7.69%)** | +| boxed_account_unsized_init8 | 224 | 🟢 **-16 (6.67%)** | +| boxed_account_unsized1 | 144 | 🔴 **+16 (12.50%)** | +| boxed_account_unsized2 | 144 | - | +| boxed_account_unsized4 | 144 | 🔴 **+16 (12.50%)** | +| boxed_account_unsized8 | 144 | 🔴 **+16 (12.50%)** | +| boxed_interface_account_mint1 | 144 | 🔴 **+16 (12.50%)** | +| boxed_interface_account_mint2 | 144 | 🔴 **+16 (12.50%)** | +| boxed_interface_account_mint4 | 144 | - | +| boxed_interface_account_mint8 | 144 | - | +| boxed_interface_account_token1 | 144 | 🔴 **+16 (12.50%)** | +| boxed_interface_account_token2 | 144 | 🔴 **+16 (12.50%)** | +| boxed_interface_account_token4 | 144 | - | +| boxed_interface_account_token8 | 144 | - | +| interface_account_mint1 | 144 | 🔴 **+16 (12.50%)** | +| interface_account_mint2 | 144 | 🔴 **+16 (12.50%)** | +| interface_account_mint4 | 144 | 🔴 **+16 (12.50%)** | +| interface_account_mint8 | 144 | 🔴 **+16 (12.50%)** | +| interface_account_token1 | 144 | 🔴 **+16 (12.50%)** | +| interface_account_token2 | 144 | 🔴 **+16 (12.50%)** | +| interface_account_token4 | 144 | 🔴 **+16 (12.50%)** | +| interface1 | 144 | 🔴 **+16 (12.50%)** | +| interface2 | 144 | 🔴 **+16 (12.50%)** | +| interface4 | 144 | 🔴 **+16 (12.50%)** | +| interface8 | 144 | 🔴 **+16 (12.50%)** | +| program1 | 144 | 🔴 **+16 (12.50%)** | +| program2 | 144 | 🔴 **+16 (12.50%)** | +| program4 | 144 | 🔴 **+16 (12.50%)** | +| program8 | 144 | 🔴 **+16 (12.50%)** | +| signer1 | 144 | 🔴 **+16 (12.50%)** | +| signer2 | 144 | 🔴 **+16 (12.50%)** | +| signer4 | 144 | 🔴 **+16 (12.50%)** | +| signer8 | 144 | 🔴 **+16 (12.50%)** | +| system_account1 | 144 | 🔴 **+16 (12.50%)** | +| system_account2 | 144 | 🔴 **+16 (12.50%)** | +| system_account4 | 144 | 🔴 **+16 (12.50%)** | +| system_account8 | 144 | 🔴 **+16 (12.50%)** | +| unchecked_account1 | 144 | 🔴 **+16 (12.50%)** | +| unchecked_account2 | 144 | 🔴 **+16 (12.50%)** | +| unchecked_account4 | 144 | 🔴 **+16 (12.50%)** | +| unchecked_account8 | 144 | 🔴 **+16 (12.50%)** | ### Notable changes +- Upgrade Solana to `1.18.8` ([#2867](https://github.com/coral-xyz/anchor/pull/2867)). + --- ## [0.29.0] diff --git a/cli/Cargo.toml b/cli/Cargo.toml index cca6c18d95..029ca8e60e 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "anchor-cli" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] -rust-version = "1.60" edition = "2021" repository = "https://github.com/coral-xyz/anchor" description = "Anchor CLI" @@ -16,13 +15,13 @@ path = "src/bin/main.rs" dev = [] [dependencies] -anchor-client = { path = "../client", version = "0.29.0" } -anchor-lang = { path = "../lang", version = "0.29.0" } -anchor-syn = { path = "../lang/syn", features = ["event-cpi", "idl-parse", "init-if-needed"], version = "0.29.0" } +anchor-client = { path = "../client", version = "0.30.1" } +anchor-lang-idl = { path = "../idl", version = "0.1.1", features = ["build", "convert"] } +anchor-lang = { path = "../lang", version = "0.30.1" } anyhow = "1.0.32" base64 = "0.21" bincode = "1.3.3" -cargo_toml = "0.15.3" +cargo_toml = "0.19.2" chrono = "0.4.19" clap = { version = "4.2.4", features = ["derive"] } dirs = "4.0" @@ -36,11 +35,11 @@ semver = "1.0.4" serde = { version = "1.0.122", features = ["derive"] } serde_json = "1.0" shellexpand = "2.1.0" -solana-client = ">=1.16, <1.18" -solana-cli-config = ">=1.16, <1.18" -solana-faucet = ">=1.16, <1.18" -solana-program = ">=1.16, <1.18" -solana-sdk = ">=1.16, <1.18" +solana-client = "1.17.3" +solana-cli-config = "1.17.3" +solana-faucet = "1.17.3" +solana-program = "1.17.3" +solana-sdk = "1.17.3" # Pin solang-parser because it may break in a backwards incompatible way in minor versions solang-parser = "=0.3.3" syn = { version = "1.0.60", features = ["full", "extra-traits"] } diff --git a/cli/npm-package/package.json b/cli/npm-package/package.json index 73e62acb2b..e331f8f406 100644 --- a/cli/npm-package/package.json +++ b/cli/npm-package/package.json @@ -1,6 +1,6 @@ { "name": "@coral-xyz/anchor-cli", - "version": "0.29.0", + "version": "0.30.1", "description": "Anchor CLI tool", "homepage": "https://github.com/coral-xyz/anchor#readme", "bugs": { diff --git a/cli/src/checks.rs b/cli/src/checks.rs index b048cff9e1..20069c4455 100644 --- a/cli/src/checks.rs +++ b/cli/src/checks.rs @@ -1,7 +1,7 @@ -use std::path::Path; +use std::{fs, path::Path}; use anyhow::{anyhow, Result}; -use semver::Version; +use semver::{Version, VersionReq}; use crate::{ config::{Config, Manifest, WithPath}, @@ -25,12 +25,16 @@ pub fn check_overflow(cargo_toml_path: impl AsRef) -> Result { )) } -/// Check whether there is a mismatch between the current CLI version and the `anchor-lang` crate -/// version. +/// Check whether there is a mismatch between the current CLI version and: +/// +/// - `anchor-lang` crate version +/// - `@coral-xyz/anchor` package version /// /// This function logs warnings in the case of a mismatch. pub fn check_anchor_version(cfg: &WithPath) -> Result<()> { let cli_version = Version::parse(VERSION)?; + + // Check lang crate let mismatched_lang_version = cfg .get_rust_program_list()? .into_iter() @@ -52,5 +56,69 @@ pub fn check_anchor_version(cfg: &WithPath) -> Result<()> { ); } + // Check TS package + let package_json = { + let package_json_path = cfg.path().parent().unwrap().join("package.json"); + let package_json_content = fs::read_to_string(package_json_path)?; + serde_json::from_str::(&package_json_content)? + }; + let mismatched_ts_version = package_json + .get("dependencies") + .and_then(|deps| deps.get("@coral-xyz/anchor")) + .and_then(|ver| ver.as_str()) + .and_then(|ver| VersionReq::parse(ver).ok()) + .filter(|ver| !ver.matches(&cli_version)); + + if let Some(ver) = mismatched_ts_version { + eprintln!( + "WARNING: `@coral-xyz/anchor` version({ver}) and the current CLI version\ + ({cli_version}) don't match.\n\n\t\ + This can lead to unwanted behavior. To fix, upgrade the package by running:\n\n\t\ + yarn upgrade @coral-xyz/anchor@{cli_version}\n" + ); + } + + Ok(()) +} + +/// Check whether the `idl-build` feature is being used correctly. +/// +/// **Note:** The check expects the current directory to be a program directory. +pub fn check_idl_build_feature() -> Result<()> { + let manifest = Manifest::from_path("Cargo.toml")?; + + // Check if `idl-build` is enabled by default + manifest + .dependencies + .iter() + .filter(|(_, dep)| dep.req_features().contains(&"idl-build".into())) + .for_each(|(name, _)| { + eprintln!( + "WARNING: `idl-build` feature of crate `{name}` is enabled by default. \ + This is not the intended usage.\n\n\t\ + To solve, do not enable the `idl-build` feature and include crates that have \ + `idl-build` feature in the `idl-build` feature list:\n\n\t\ + [features]\n\t\ + idl-build = [\"{name}/idl-build\", ...]\n" + ) + }); + + // Check `anchor-spl`'s `idl-build` feature + manifest + .dependencies + .get("anchor-spl") + .and_then(|_| manifest.features.get("idl-build")) + .map(|feature_list| !feature_list.contains(&"anchor-spl/idl-build".into())) + .unwrap_or_default() + .then(|| { + eprintln!( + "WARNING: `idl-build` feature of `anchor-spl` is not enabled. \ + This is likely to result in cryptic compile errors.\n\n\t\ + To solve, add `anchor-spl/idl-build` to the `idl-build` feature list:\n\n\t\ + [features]\n\t\ + idl-build = [\"anchor-spl/idl-build\", ...]\n" + ) + }); + Ok(()) } diff --git a/cli/src/config.rs b/cli/src/config.rs index efce7fd0ad..1b5ee602d9 100644 --- a/cli/src/config.rs +++ b/cli/src/config.rs @@ -1,6 +1,6 @@ -use crate::is_hidden; +use crate::{get_keypair, is_hidden, keys_sync}; use anchor_client::Cluster; -use anchor_syn::idl::types::Idl; +use anchor_lang_idl::types::Idl; use anyhow::{anyhow, bail, Context, Error, Result}; use clap::{Parser, ValueEnum}; use dirs::home_dir; @@ -375,14 +375,33 @@ pub struct ToolchainConfig { pub solana_version: Option, } -#[derive(Default, Clone, Debug, Serialize, Deserialize)] +#[derive(Clone, Debug, Serialize, Deserialize)] pub struct FeaturesConfig { - #[serde(default)] - pub seeds: bool, + /// Enable account resolution. + /// + /// Not able to specify default bool value: https://github.com/serde-rs/serde/issues/368 + #[serde(default = "FeaturesConfig::get_default_resolution")] + pub resolution: bool, + /// Disable safety comment checks #[serde(default, rename = "skip-lint")] pub skip_lint: bool, } +impl FeaturesConfig { + fn get_default_resolution() -> bool { + true + } +} + +impl Default for FeaturesConfig { + fn default() -> Self { + Self { + resolution: Self::get_default_resolution(), + skip_lint: false, + } + } +} + #[derive(Clone, Debug, Serialize, Deserialize)] pub struct RegistryConfig { pub url: String, @@ -493,7 +512,16 @@ impl Config { .path(); if let Some(filename) = p.file_name() { if filename.to_str() == Some("Anchor.toml") { - let cfg = Config::from_path(&p)?; + // Make sure the program id is correct (only on the initial build) + let mut cfg = Config::from_path(&p)?; + let deploy_dir = p.parent().unwrap().join("target").join("deploy"); + if !deploy_dir.exists() && !cfg.programs.contains_key(&Cluster::Localnet) { + println!("Updating program ids..."); + fs::create_dir_all(deploy_dir)?; + keys_sync(&ConfigOverride::default(), None)?; + cfg = Config::from_path(&p)?; + } + return Ok(Some(WithPath::new(cfg, p))); } } @@ -512,8 +540,7 @@ impl Config { } pub fn wallet_kp(&self) -> Result { - solana_sdk::signature::read_keypair_file(&self.provider.wallet.to_string()) - .map_err(|_| anyhow!("Unable to read keypair file")) + get_keypair(&self.provider.wallet.to_string()) } } @@ -583,8 +610,8 @@ where deserializer.deserialize_any(StringOrCustomCluster(PhantomData)) } -impl ToString for Config { - fn to_string(&self) -> String { +impl fmt::Display for Config { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let programs = { let c = ser_programs(&self.programs); if c.is_empty() { @@ -611,7 +638,8 @@ impl ToString for Config { .then(|| self.workspace.clone()), }; - toml::to_string(&cfg).expect("Must be well formed") + let cfg = toml::to_string(&cfg).expect("Must be well formed"); + write!(f, "{}", cfg) } } @@ -619,8 +647,8 @@ impl FromStr for Config { type Err = Error; fn from_str(s: &str) -> Result { - let cfg: _Config = toml::from_str(s) - .map_err(|e| anyhow::format_err!("Unable to deserialize config: {}", e.to_string()))?; + let cfg: _Config = + toml::from_str(s).map_err(|e| anyhow!("Unable to deserialize config: {e}"))?; Ok(Config { toolchain: cfg.toolchain.unwrap_or_default(), features: cfg.features.unwrap_or_default(), @@ -804,6 +832,8 @@ pub struct _TestToml { } impl _TestToml { + // TODO: Remove if/when false positive gets fixed + #[allow(clippy::needless_borrows_for_generic_args)] fn from_path(path: impl AsRef) -> Result { let s = fs::read_to_string(&path)?; let parsed_toml: Self = toml::from_str(&s)?; @@ -1040,6 +1070,9 @@ pub struct _Validator { // Warp the ledger to WARP_SLOT after starting the validator. #[serde(skip_serializing_if = "Option::is_none")] pub warp_slot: Option, + // Deactivate one or more features. + #[serde(skip_serializing_if = "Option::is_none")] + pub deactivate_feature: Option>, } #[derive(Debug, Default, Clone, Serialize, Deserialize)] @@ -1075,6 +1108,8 @@ pub struct Validator { pub ticks_per_slot: Option, #[serde(skip_serializing_if = "Option::is_none")] pub warp_slot: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub deactivate_feature: Option>, } impl From<_Validator> for Validator { @@ -1103,6 +1138,7 @@ impl From<_Validator> for Validator { slots_per_epoch: _validator.slots_per_epoch, ticks_per_slot: _validator.ticks_per_slot, warp_slot: _validator.warp_slot, + deactivate_feature: _validator.deactivate_feature, } } } @@ -1127,11 +1163,12 @@ impl From for _Validator { slots_per_epoch: validator.slots_per_epoch, ticks_per_slot: validator.ticks_per_slot, warp_slot: validator.warp_slot, + deactivate_feature: validator.deactivate_feature, } } } -const DEFAULT_LEDGER_PATH: &str = ".anchor/test-ledger"; +pub const DEFAULT_LEDGER_PATH: &str = ".anchor/test-ledger"; const DEFAULT_BIND_ADDRESS: &str = "0.0.0.0"; impl Merge for _Validator { @@ -1216,6 +1253,9 @@ impl Merge for _Validator { .or_else(|| self.slots_per_epoch.take()), ticks_per_slot: other.ticks_per_slot.or_else(|| self.ticks_per_slot.take()), warp_slot: other.warp_slot.or_else(|| self.warp_slot.take()), + deactivate_feature: other + .deactivate_feature + .or_else(|| self.deactivate_feature.take()), }; } } @@ -1236,8 +1276,7 @@ impl Program { pub fn keypair(&self) -> Result { let file = self.keypair_file()?; - solana_sdk::signature::read_keypair_file(file.path()) - .map_err(|_| anyhow!("failed to read keypair for program: {}", self.lib_name)) + get_keypair(file.path().to_str().unwrap()) } // Lazily initializes the keypair file with a new key if it doesn't exist. @@ -1368,9 +1407,9 @@ macro_rules! home_path { } } - impl ToString for $my_struct { - fn to_string(&self) -> String { - self.0.clone() + impl fmt::Display for $my_struct { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{}", self.0) } } }; diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 051ded15d4..017c5db9ab 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -1,30 +1,28 @@ use crate::config::{ AnchorPackage, BootstrapMode, BuildConfig, Config, ConfigOverride, Manifest, ProgramArch, - ProgramDeployment, ProgramWorkspace, ScriptsConfig, TestValidator, WithPath, SHUTDOWN_WAIT, - STARTUP_WAIT, + ProgramDeployment, ProgramWorkspace, ScriptsConfig, TestValidator, WithPath, + DEFAULT_LEDGER_PATH, SHUTDOWN_WAIT, STARTUP_WAIT, }; use anchor_client::Cluster; use anchor_lang::idl::{IdlAccount, IdlInstruction, ERASED_AUTHORITY}; -use anchor_lang::{AccountDeserialize, AnchorDeserialize, AnchorSerialize}; -use anchor_syn::idl::types::{ - EnumFields, Idl, IdlConst, IdlErrorCode, IdlEvent, IdlType, IdlTypeDefinition, - IdlTypeDefinitionTy, -}; +use anchor_lang::{AccountDeserialize, AnchorDeserialize, AnchorSerialize, Discriminator}; +use anchor_lang_idl::convert::convert_idl; +use anchor_lang_idl::types::{Idl, IdlArrayLen, IdlDefinedFields, IdlType, IdlTypeDefTy}; use anyhow::{anyhow, Context, Result}; -use checks::{check_anchor_version, check_overflow}; +use checks::{check_anchor_version, check_idl_build_feature, check_overflow}; use clap::Parser; use dirs::home_dir; use flate2::read::GzDecoder; use flate2::read::ZlibDecoder; use flate2::write::{GzEncoder, ZlibEncoder}; use flate2::Compression; -use heck::{ToKebabCase, ToSnakeCase}; +use heck::{ToKebabCase, ToLowerCamelCase, ToPascalCase, ToSnakeCase}; use regex::{Regex, RegexBuilder}; use reqwest::blocking::multipart::{Form, Part}; use reqwest::blocking::Client; -use rust_template::ProgramTemplate; +use rust_template::{ProgramTemplate, TestTemplate}; use semver::{Version, VersionReq}; -use serde::{Deserialize, Serialize}; +use serde::Deserialize; use serde_json::{json, Map, Value as JsonValue}; use solana_client::rpc_client::RpcClient; use solana_program::instruction::{AccountMeta, Instruction}; @@ -33,6 +31,7 @@ use solana_sdk::bpf_loader; use solana_sdk::bpf_loader_deprecated; use solana_sdk::bpf_loader_upgradeable::{self, UpgradeableLoaderState}; use solana_sdk::commitment_config::CommitmentConfig; +use solana_sdk::compute_budget::ComputeBudgetInstruction; use solana_sdk::pubkey::Pubkey; use solana_sdk::signature::Keypair; use solana_sdk::signature::Signer; @@ -80,15 +79,18 @@ pub enum Command { /// Use Solidity instead of Rust #[clap(short, long)] solidity: bool, + /// Don't install JavaScript dependencies + #[clap(long)] + no_install: bool, /// Don't initialize git #[clap(long)] no_git: bool, - /// Use `jest` instead of `mocha` for tests - #[clap(long)] - jest: bool, /// Rust program template to use #[clap(value_enum, short, long, default_value = "single")] template: ProgramTemplate, + /// Test template to use + #[clap(value_enum, long, default_value = "mocha")] + test_template: TestTemplate, /// Initialize even if there are files #[clap(long, action)] force: bool, @@ -96,19 +98,22 @@ pub enum Command { /// Builds the workspace. #[clap(name = "build", alias = "b")] Build { + /// True if the build should not fail even if there are no "CHECK" comments + #[clap(long)] + skip_lint: bool, + /// Do not build the IDL + #[clap(long)] + no_idl: bool, /// Output directory for the IDL. #[clap(short, long)] idl: Option, - /// True if the build should not fail even if there are - /// no "CHECK" comments where normally required - #[clap(long)] - skip_lint: bool, /// Output directory for the TypeScript IDL. #[clap(short = 't', long)] idl_ts: Option, /// True if the build artifact needs to be deterministic and verifiable. #[clap(short, long)] verifiable: bool, + /// Name of the program to build #[clap(short, long)] program_name: Option, /// Version of the Solana toolchain to use. For --verifiable builds @@ -183,8 +188,11 @@ pub enum Command { skip_build: bool, }, #[clap(name = "test", alias = "t")] - /// Runs integration tests against a localnetwork. + /// Runs integration tests. Test { + /// Build and test only this program + #[clap(short, long)] + program_name: Option, /// Use this flag if you want to run tests against previously deployed /// programs. #[clap(long)] @@ -266,6 +274,9 @@ pub enum Command { program_id: Pubkey, /// Filepath to the new program binary. program_filepath: String, + /// Arguments to pass to the underlying `solana program deploy` command. + #[clap(required = false, last = true)] + solana_args: Vec, }, #[cfg(feature = "dev")] /// Runs an airdrop loop, continuously funding the configured wallet. @@ -372,6 +383,8 @@ pub enum IdlCommand { program_id: Pubkey, #[clap(short, long)] filepath: String, + #[clap(long)] + priority_fee: Option, }, Close { program_id: Pubkey, @@ -382,6 +395,8 @@ pub enum IdlCommand { /// Useful for multisig execution when the local wallet keypair is not available. #[clap(long)] print_only: bool, + #[clap(long)] + priority_fee: Option, }, /// Writes an IDL into a buffer account. This can be used with SetBuffer /// to perform an upgrade. @@ -389,6 +404,8 @@ pub enum IdlCommand { program_id: Pubkey, #[clap(short, long)] filepath: String, + #[clap(long)] + priority_fee: Option, }, /// Sets a new IDL buffer for the program. SetBuffer { @@ -400,6 +417,8 @@ pub enum IdlCommand { /// Useful for multisig execution when the local wallet keypair is not available. #[clap(long)] print_only: bool, + #[clap(long)] + priority_fee: Option, }, /// Upgrades the IDL to the new file. An alias for first writing and then /// then setting the idl buffer account. @@ -407,6 +426,8 @@ pub enum IdlCommand { program_id: Pubkey, #[clap(short, long)] filepath: String, + #[clap(long)] + priority_fee: Option, }, /// Sets a new authority on the IDL account. SetAuthority { @@ -423,6 +444,8 @@ pub enum IdlCommand { /// Useful for multisig execution when the local wallet keypair is not available. #[clap(long)] print_only: bool, + #[clap(long)] + priority_fee: Option, }, /// Command to remove the ability to modify the IDL account. This should /// likely be used in conjection with eliminating an "upgrade authority" on @@ -430,29 +453,19 @@ pub enum IdlCommand { EraseAuthority { #[clap(short, long)] program_id: Pubkey, + #[clap(long)] + priority_fee: Option, }, /// Outputs the authority for the IDL account. Authority { /// The program to view. program_id: Pubkey, }, - /// Parses an IDL from source. - Parse { - /// Path to the program's interface definition. - #[clap(short, long)] - file: String, - /// Output file for the IDL (stdout if not specified). - #[clap(short, long)] - out: Option, - /// Output file for the TypeScript IDL. - #[clap(short = 't', long)] - out_ts: Option, - /// Suppress doc strings in output - #[clap(long)] - no_docs: bool, - }, /// Generates the IDL for the program using the compilation method. Build { + // Program name to build the IDL of(current dir's program if not specified) + #[clap(short, long)] + program_name: Option, /// Output file for the IDL (stdout if not specified) #[clap(short, long)] out: Option, @@ -462,12 +475,34 @@ pub enum IdlCommand { /// Suppress doc strings in output #[clap(long)] no_docs: bool, + /// Do not check for safety comments + #[clap(long)] + skip_lint: bool, + /// Arguments to pass to the underlying `cargo test` command + #[clap(required = false, last = true)] + cargo_args: Vec, }, /// Fetches an IDL for the given address from a cluster. /// The address can be a program, IDL account, or IDL buffer. Fetch { address: Pubkey, - /// Output file for the idl (stdout if not specified). + /// Output file for the IDL (stdout if not specified). + #[clap(short, long)] + out: Option, + }, + /// Convert legacy IDLs (pre Anchor 0.30) to the new IDL spec + Convert { + /// Path to the IDL file + path: String, + /// Output file for the IDL (stdout if not specified) + #[clap(short, long)] + out: Option, + }, + /// Generate TypeScript type for the IDL + Type { + /// Path to the IDL file + path: String, + /// Output file for the IDL (stdout if not specified) #[clap(short, long)] out: Option, }, @@ -479,6 +514,11 @@ pub enum ClusterCommand { List, } +fn get_keypair(path: &str) -> Result { + solana_sdk::signature::read_keypair_file(path) + .map_err(|_| anyhow!("Unable to read keypair file ({path})")) +} + pub fn entry(opts: Opts) -> Result<()> { let restore_cbs = override_toolchain(&opts.cfg_override)?; let result = process_command(opts); @@ -644,24 +684,42 @@ fn restore_toolchain(restore_cbs: RestoreToolchainCallbacks) -> Result<()> { Ok(()) } +/// Get the system's default license - what 'npm init' would use. +fn get_npm_init_license() -> Result { + let npm_init_license_output = std::process::Command::new("npm") + .arg("config") + .arg("get") + .arg("init-license") + .output()?; + + if !npm_init_license_output.status.success() { + return Err(anyhow!("Failed to get npm init license")); + } + + let license = String::from_utf8(npm_init_license_output.stdout)?; + Ok(license.trim().to_string()) +} + fn process_command(opts: Opts) -> Result<()> { match opts.command { Command::Init { name, javascript, solidity, + no_install, no_git, - jest, template, + test_template, force, } => init( &opts.cfg_override, name, javascript, solidity, + no_install, no_git, - jest, template, + test_template, force, ), Command::New { @@ -671,6 +729,7 @@ fn process_command(opts: Opts) -> Result<()> { force, } => new(&opts.cfg_override, solidity, name, template, force), Command::Build { + no_idl, idl, idl_ts, verifiable, @@ -685,6 +744,7 @@ fn process_command(opts: Opts) -> Result<()> { arch, } => build( &opts.cfg_override, + no_idl, idl, idl_ts, verifiable, @@ -742,10 +802,17 @@ fn process_command(opts: Opts) -> Result<()> { Command::Upgrade { program_id, program_filepath, - } => upgrade(&opts.cfg_override, program_id, program_filepath), + solana_args, + } => upgrade( + &opts.cfg_override, + program_id, + program_filepath, + solana_args, + ), Command::Idl { subcmd } => idl(&opts.cfg_override, subcmd), Command::Migrate => migrate(&opts.cfg_override), Command::Test { + program_name, skip_deploy, skip_local_validator, skip_build, @@ -758,6 +825,7 @@ fn process_command(opts: Opts) -> Result<()> { arch, } => test( &opts.cfg_override, + program_name, skip_deploy, skip_local_validator, skip_build, @@ -823,9 +891,10 @@ fn init( name: String, javascript: bool, solidity: bool, + no_install: bool, no_git: bool, - jest: bool, template: ProgramTemplate, + test_template: TestTemplate, force: bool, ) -> Result<()> { if !force && Config::discover(cfg_override)?.is_some() { @@ -861,27 +930,9 @@ fn init( fs::create_dir_all("app")?; let mut cfg = Config::default(); - if jest { - cfg.scripts.insert( - "test".to_owned(), - if javascript { - "yarn run jest" - } else { - "yarn run jest --preset ts-jest" - } - .to_owned(), - ); - } else { - cfg.scripts.insert( - "test".to_owned(), - if javascript { - "yarn run mocha -t 1000000 tests/" - } else { - "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" - } - .to_owned(), - ); - } + let test_script = test_template.get_test_script(javascript); + cfg.scripts + .insert("test".to_owned(), test_script.to_owned()); let mut localnet = BTreeMap::new(); let program_id = rust_template::get_or_create_program_id(&rust_name); @@ -919,31 +970,16 @@ fn init( rust_template::create_program(&project_name, template)?; } - // Build the test suite. - fs::create_dir_all("tests")?; // Build the migrations directory. fs::create_dir_all("migrations")?; + let license = get_npm_init_license()?; + + let jest = TestTemplate::Jest == test_template; if javascript { // Build javascript config let mut package_json = File::create("package.json")?; - package_json.write_all(rust_template::package_json(jest).as_bytes())?; - - if jest { - let mut test = File::create(format!("tests/{}.test.js", &project_name))?; - if solidity { - test.write_all(solidity_template::jest(&project_name).as_bytes())?; - } else { - test.write_all(rust_template::jest(&project_name).as_bytes())?; - } - } else { - let mut test = File::create(format!("tests/{}.js", &project_name))?; - if solidity { - test.write_all(solidity_template::mocha(&project_name).as_bytes())?; - } else { - test.write_all(rust_template::mocha(&project_name).as_bytes())?; - } - } + package_json.write_all(rust_template::package_json(jest, license).as_bytes())?; let mut deploy = File::create("migrations/deploy.js")?; @@ -954,23 +990,25 @@ fn init( ts_config.write_all(rust_template::ts_config(jest).as_bytes())?; let mut ts_package_json = File::create("package.json")?; - ts_package_json.write_all(rust_template::ts_package_json(jest).as_bytes())?; + ts_package_json.write_all(rust_template::ts_package_json(jest, license).as_bytes())?; let mut deploy = File::create("migrations/deploy.ts")?; deploy.write_all(rust_template::ts_deploy_script().as_bytes())?; - - let mut mocha = File::create(format!("tests/{}.ts", &project_name))?; - if solidity { - mocha.write_all(solidity_template::ts_mocha(&project_name).as_bytes())?; - } else { - mocha.write_all(rust_template::ts_mocha(&project_name).as_bytes())?; - } } - let yarn_result = install_node_modules("yarn")?; - if !yarn_result.status.success() { - println!("Failed yarn install will attempt to npm install"); - install_node_modules("npm")?; + test_template.create_test_files( + &project_name, + javascript, + solidity, + &program_id.to_string(), + )?; + + if !no_install { + let yarn_result = install_node_modules("yarn")?; + if !yarn_result.status.success() { + println!("Failed yarn install will attempt to npm install"); + install_node_modules("npm")?; + } } if !no_git { @@ -1093,6 +1131,32 @@ pub fn create_files(files: &Files) -> Result<()> { Ok(()) } +/// Override or create files from the given (path, content) tuple array. +/// +/// # Example +/// +/// ```ignore +/// override_or_create_files(vec![("programs/my_program/src/lib.rs".into(), "// Content".into())])?; +/// ``` +pub fn override_or_create_files(files: &Files) -> Result<()> { + for (path, content) in files { + let path = Path::new(path); + if path.exists() { + let mut f = fs::OpenOptions::new() + .write(true) + .truncate(true) + .open(path)?; + f.write_all(content.as_bytes())?; + f.flush()?; + } else { + fs::create_dir_all(path.parent().unwrap())?; + fs::write(path, content)?; + } + } + + Ok(()) +} + pub fn expand( cfg_override: &ConfigOverride, program_name: Option, @@ -1191,6 +1255,7 @@ fn expand_program( #[allow(clippy::too_many_arguments)] pub fn build( cfg_override: &ConfigOverride, + no_idl: bool, idl: Option, idl_ts: Option, verifiable: bool, @@ -1210,7 +1275,6 @@ pub fn build( if let Some(program_name) = program_name.as_ref() { cd_member(cfg_override, program_name)?; } - let cfg = Config::discover(cfg_override)?.expect("Not in workspace."); let cfg_parent = cfg.path().parent().expect("Invalid Anchor.toml"); @@ -1220,7 +1284,7 @@ pub fn build( check_overflow(workspace_cargo_toml_path)?; } - // Check whether there is a mismatch between CLI and lang crate versions + // Check whether there is a mismatch between CLI and crate/package versions check_anchor_version(&cfg).ok(); let idl_out = match idl { @@ -1251,6 +1315,7 @@ pub fn build( None => build_all( &cfg, cfg.path(), + no_idl, idl_out, idl_ts_out, &build_config, @@ -1266,6 +1331,7 @@ pub fn build( Some(cargo) if cargo.path().parent() == cfg.path().parent() => build_all( &cfg, cfg.path(), + no_idl, idl_out, idl_ts_out, &build_config, @@ -1281,6 +1347,7 @@ pub fn build( Some(cargo) => build_rust_cwd( &cfg, cargo.path().to_path_buf(), + no_idl, idl_out, idl_ts_out, &build_config, @@ -1303,6 +1370,7 @@ pub fn build( fn build_all( cfg: &WithPath, cfg_path: &Path, + no_idl: bool, idl_out: Option, idl_ts_out: Option, build_config: &BuildConfig, @@ -1322,6 +1390,7 @@ fn build_all( build_rust_cwd( cfg, p.join("Cargo.toml"), + no_idl, idl_out.clone(), idl_ts_out.clone(), build_config, @@ -1359,6 +1428,7 @@ fn build_all( fn build_rust_cwd( cfg: &WithPath, cargo_toml: PathBuf, + no_idl: bool, idl_out: Option, idl_ts_out: Option, build_config: &BuildConfig, @@ -1376,7 +1446,7 @@ fn build_rust_cwd( }; match build_config.verifiable { false => _build_rust_cwd( - cfg, idl_out, idl_ts_out, skip_lint, no_docs, arch, cargo_args, + cfg, no_idl, idl_out, idl_ts_out, skip_lint, no_docs, arch, cargo_args, ), true => build_cwd_verifiable( cfg, @@ -1453,7 +1523,7 @@ fn build_cwd_verifiable( stdout, stderr, env_vars, - cargo_args, + cargo_args.clone(), arch, ); @@ -1464,16 +1534,16 @@ fn build_cwd_verifiable( Ok(_) => { // Build the idl. println!("Extracting the IDL"); - let idl = generate_idl(cfg, skip_lint, no_docs)?; + let idl = generate_idl(cfg, skip_lint, no_docs, &cargo_args)?; // Write out the JSON file. println!("Writing the IDL file"); - let out_file = workspace_dir.join(format!("target/idl/{}.json", idl.name)); + let out_file = workspace_dir.join(format!("target/idl/{}.json", idl.metadata.name)); write_idl(&idl, OutFile::File(out_file))?; // Write out the TypeScript type. println!("Writing the .ts file"); - let ts_file = workspace_dir.join(format!("target/types/{}.ts", idl.name)); - fs::write(&ts_file, rust_template::idl_ts(&idl)?)?; + let ts_file = workspace_dir.join(format!("target/types/{}.ts", idl.metadata.name)); + fs::write(&ts_file, idl_ts(&idl)?)?; // Copy out the TypeScript type. if !&cfg.workspace.types.is_empty() { @@ -1481,7 +1551,7 @@ fn build_cwd_verifiable( ts_file, workspace_dir .join(&cfg.workspace.types) - .join(idl.name) + .join(idl.metadata.name) .with_extension("ts"), )?; } @@ -1736,8 +1806,10 @@ fn docker_exec(container_name: &str, args: &[&str]) -> Result<()> { } } +#[allow(clippy::too_many_arguments)] fn _build_rust_cwd( cfg: &WithPath, + no_idl: bool, idl_out: Option, idl_ts_out: Option, skip_lint: bool, @@ -1745,10 +1817,9 @@ fn _build_rust_cwd( arch: &ProgramArch, cargo_args: Vec, ) -> Result<()> { - let subcommand = arch.build_subcommand(); let exit = std::process::Command::new("cargo") - .arg(subcommand) - .args(cargo_args) + .arg(arch.build_subcommand()) + .args(cargo_args.clone()) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .output() @@ -1758,32 +1829,40 @@ fn _build_rust_cwd( } // Generate IDL - let idl = generate_idl(cfg, skip_lint, no_docs)?; - // JSON out path. - let out = match idl_out { - None => PathBuf::from(".").join(&idl.name).with_extension("json"), - Some(o) => PathBuf::from(&o.join(&idl.name).with_extension("json")), - }; - // TS out path. - let ts_out = match idl_ts_out { - None => PathBuf::from(".").join(&idl.name).with_extension("ts"), - Some(o) => PathBuf::from(&o.join(&idl.name).with_extension("ts")), - }; - - // Write out the JSON file. - write_idl(&idl, OutFile::File(out))?; - // Write out the TypeScript type. - fs::write(&ts_out, rust_template::idl_ts(&idl)?)?; - // Copy out the TypeScript type. - let cfg_parent = cfg.path().parent().expect("Invalid Anchor.toml"); - if !&cfg.workspace.types.is_empty() { - fs::copy( - &ts_out, - cfg_parent - .join(&cfg.workspace.types) - .join(&idl.name) + if !no_idl { + let idl = generate_idl(cfg, skip_lint, no_docs, &cargo_args)?; + + // JSON out path. + let out = match idl_out { + None => PathBuf::from(".") + .join(&idl.metadata.name) + .with_extension("json"), + Some(o) => PathBuf::from(&o.join(&idl.metadata.name).with_extension("json")), + }; + // TS out path. + let ts_out = match idl_ts_out { + None => PathBuf::from(".") + .join(&idl.metadata.name) .with_extension("ts"), - )?; + Some(o) => PathBuf::from(&o.join(&idl.metadata.name).with_extension("ts")), + }; + + // Write out the JSON file. + write_idl(&idl, OutFile::File(out))?; + // Write out the TypeScript type. + fs::write(&ts_out, idl_ts(&idl)?)?; + + // Copy out the TypeScript type. + let cfg_parent = cfg.path().parent().expect("Invalid Anchor.toml"); + if !&cfg.workspace.types.is_empty() { + fs::copy( + &ts_out, + cfg_parent + .join(&cfg.workspace.types) + .join(&idl.metadata.name) + .with_extension("ts"), + )?; + } } Ok(()) @@ -1842,12 +1921,14 @@ fn _build_solidity_cwd( // TS out path. let ts_out = match idl_ts_out { - None => PathBuf::from(".").join(&idl.name).with_extension("ts"), - Some(o) => PathBuf::from(&o.join(&idl.name).with_extension("ts")), + None => PathBuf::from(".") + .join(&idl.metadata.name) + .with_extension("ts"), + Some(o) => PathBuf::from(&o.join(&idl.metadata.name).with_extension("ts")), }; // Write out the TypeScript type. - fs::write(&ts_out, rust_template::idl_ts(&idl)?)?; + fs::write(&ts_out, idl_ts(&idl)?)?; // Copy out the TypeScript type. let cfg_parent = cfg.path().parent().expect("Invalid Anchor.toml"); if !&cfg.workspace.types.is_empty() { @@ -1855,7 +1936,7 @@ fn _build_solidity_cwd( &ts_out, cfg_parent .join(&cfg.workspace.types) - .join(&idl.name) + .join(&idl.metadata.name) .with_extension("ts"), )?; } @@ -1890,18 +1971,19 @@ fn verify( if !skip_build { build( cfg_override, - None, // idl - None, // idl ts - true, // verifiable - true, // skip lint - None, // program name - solana_version.or_else(|| cfg.toolchain.solana_version.clone()), // solana version - docker_image, // docker image - bootstrap, // bootstrap docker image - None, // stdout - None, // stderr + false, + None, + None, + true, + true, + None, + solana_version.or_else(|| cfg.toolchain.solana_version.clone()), + docker_image, + bootstrap, + None, + None, env_vars, - cargo_args, + cargo_args.clone(), false, arch, )?; @@ -1925,7 +2007,7 @@ fn verify( } // Verify IDL (only if it's not a buffer account). - let local_idl = generate_idl(&cfg, true, false)?; + let local_idl = generate_idl(&cfg, true, false, &cargo_args)?; if bin_ver.state != BinVerificationState::Buffer { let deployed_idl = fetch_idl(cfg_override, program_id)?; if local_idl != deployed_idl { @@ -1957,13 +2039,17 @@ fn cd_member(cfg_override: &ConfigOverride, program_name: &str) -> Result<()> { program.path.display() )); } - let p_lib_name = Manifest::from_path(&cargo_toml)?.lib_name()?; - if program_name == p_lib_name { + + let manifest = Manifest::from_path(&cargo_toml)?; + let pkg_name = manifest.package().name(); + let lib_name = manifest.lib_name()?; + if program_name == pkg_name || program_name == lib_name { std::env::set_current_dir(&program.path)?; return Ok(()); } } } + Err(anyhow!("{} is not part of the workspace", program_name,)) } @@ -2063,13 +2149,21 @@ fn idl(cfg_override: &ConfigOverride, subcmd: IdlCommand) -> Result<()> { IdlCommand::Init { program_id, filepath, - } => idl_init(cfg_override, program_id, filepath), + priority_fee, + } => idl_init(cfg_override, program_id, filepath, priority_fee), IdlCommand::Close { program_id, idl_address, print_only, + priority_fee, } => { - let closed_address = idl_close(cfg_override, program_id, idl_address, print_only)?; + let closed_address = idl_close( + cfg_override, + program_id, + idl_address, + print_only, + priority_fee, + )?; if !print_only { println!("Idl account closed: {closed_address}"); } @@ -2078,8 +2172,9 @@ fn idl(cfg_override: &ConfigOverride, subcmd: IdlCommand) -> Result<()> { IdlCommand::WriteBuffer { program_id, filepath, + priority_fee, } => { - let idl_buffer = idl_write_buffer(cfg_override, program_id, filepath)?; + let idl_buffer = idl_write_buffer(cfg_override, program_id, filepath, priority_fee)?; println!("Idl buffer created: {idl_buffer}"); Ok(()) } @@ -2087,31 +2182,51 @@ fn idl(cfg_override: &ConfigOverride, subcmd: IdlCommand) -> Result<()> { program_id, buffer, print_only, - } => idl_set_buffer(cfg_override, program_id, buffer, print_only).map(|_| ()), + priority_fee, + } => idl_set_buffer(cfg_override, program_id, buffer, print_only, priority_fee).map(|_| ()), IdlCommand::Upgrade { program_id, filepath, - } => idl_upgrade(cfg_override, program_id, filepath), + priority_fee, + } => idl_upgrade(cfg_override, program_id, filepath, priority_fee), IdlCommand::SetAuthority { program_id, address, new_authority, print_only, - } => idl_set_authority(cfg_override, program_id, address, new_authority, print_only), - IdlCommand::EraseAuthority { program_id } => idl_erase_authority(cfg_override, program_id), + priority_fee, + } => idl_set_authority( + cfg_override, + program_id, + address, + new_authority, + print_only, + priority_fee, + ), + IdlCommand::EraseAuthority { + program_id, + priority_fee, + } => idl_erase_authority(cfg_override, program_id, priority_fee), IdlCommand::Authority { program_id } => idl_authority(cfg_override, program_id), - IdlCommand::Parse { - file, + IdlCommand::Build { + program_name, out, out_ts, no_docs, - } => idl_parse(cfg_override, file, out, out_ts, no_docs), - IdlCommand::Build { + skip_lint, + cargo_args, + } => idl_build( + cfg_override, + program_name, out, out_ts, no_docs, - } => idl_build(out, out_ts, no_docs), + skip_lint, + cargo_args, + ), IdlCommand::Fetch { address, out } => idl_fetch(cfg_override, address, out), + IdlCommand::Convert { path, out } => idl_convert(path, out), + IdlCommand::Type { path, out } => idl_type(path, out), } } @@ -2141,7 +2256,7 @@ fn fetch_idl(cfg_override: &ConfigOverride, idl_addr: Pubkey) -> Result { } // Cut off account discriminator. - let mut d: &[u8] = &account.data[8..]; + let mut d: &[u8] = &account.data[IdlAccount::DISCRIMINATOR.len()..]; let idl_account: IdlAccount = AnchorDeserialize::deserialize(&mut d)?; let compressed_len: usize = idl_account.data_len.try_into().unwrap(); @@ -2158,14 +2273,19 @@ fn get_idl_account(client: &RpcClient, idl_address: &Pubkey) -> Result Result<()> { +fn idl_init( + cfg_override: &ConfigOverride, + program_id: Pubkey, + idl_filepath: String, + priority_fee: Option, +) -> Result<()> { with_workspace(cfg_override, |cfg| { let keypair = cfg.provider.wallet.to_string(); let bytes = fs::read(idl_filepath)?; let idl: Idl = serde_json::from_reader(&*bytes)?; - let idl_address = create_idl_account(cfg, &keypair, &program_id, &idl)?; + let idl_address = create_idl_account(cfg, &keypair, &program_id, &idl, priority_fee)?; println!("Idl account created: {idl_address:?}"); Ok(()) @@ -2177,10 +2297,11 @@ fn idl_close( program_id: Pubkey, idl_address: Option, print_only: bool, + priority_fee: Option, ) -> Result { with_workspace(cfg_override, |cfg| { let idl_address = idl_address.unwrap_or_else(|| IdlAccount::address(&program_id)); - idl_close_account(cfg, &program_id, idl_address, print_only)?; + idl_close_account(cfg, &program_id, idl_address, print_only, priority_fee)?; Ok(idl_address) }) @@ -2190,6 +2311,7 @@ fn idl_write_buffer( cfg_override: &ConfigOverride, program_id: Pubkey, idl_filepath: String, + priority_fee: Option, ) -> Result { with_workspace(cfg_override, |cfg| { let keypair = cfg.provider.wallet.to_string(); @@ -2197,8 +2319,8 @@ fn idl_write_buffer( let bytes = fs::read(idl_filepath)?; let idl: Idl = serde_json::from_reader(&*bytes)?; - let idl_buffer = create_idl_buffer(cfg, &keypair, &program_id, &idl)?; - idl_write(cfg, &program_id, &idl, idl_buffer)?; + let idl_buffer = create_idl_buffer(cfg, &keypair, &program_id, &idl, priority_fee)?; + idl_write(cfg, &program_id, &idl, idl_buffer, priority_fee)?; Ok(idl_buffer) }) @@ -2209,10 +2331,10 @@ fn idl_set_buffer( program_id: Pubkey, buffer: Pubkey, print_only: bool, + priority_fee: Option, ) -> Result { with_workspace(cfg_override, |cfg| { - let keypair = solana_sdk::signature::read_keypair_file(&cfg.provider.wallet.to_string()) - .map_err(|_| anyhow!("Unable to read keypair file"))?; + let keypair = get_keypair(&cfg.provider.wallet.to_string())?; let url = cluster_url(cfg, &cfg.test_validator); let client = create_client(url); @@ -2242,16 +2364,31 @@ fn idl_set_buffer( print_idl_instruction("SetBuffer", &ix, &idl_address)?; } else { // Build the transaction. - let latest_hash = client.get_latest_blockhash()?; - let tx = Transaction::new_signed_with_payer( - &[ix], - Some(&keypair.pubkey()), - &[&keypair], - latest_hash, - ); + let instructions = prepend_compute_unit_ix(vec![ix], &client, priority_fee)?; // Send the transaction. - client.send_and_confirm_transaction_with_spinner(&tx)?; + let mut latest_hash = client.get_latest_blockhash()?; + for retries in 0..20 { + if !client.is_blockhash_valid(&latest_hash, client.commitment())? { + latest_hash = client.get_latest_blockhash()?; + } + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&keypair.pubkey()), + &[&keypair], + latest_hash, + ); + + match client.send_and_confirm_transaction_with_spinner(&tx) { + Ok(_) => break, + Err(e) => { + if retries == 19 { + return Err(anyhow!("Error: {e}. Failed to send transaction.")); + } + println!("Error: {e}. Retrying transaction."); + } + } + } } Ok(idl_address) @@ -2262,10 +2399,23 @@ fn idl_upgrade( cfg_override: &ConfigOverride, program_id: Pubkey, idl_filepath: String, + priority_fee: Option, ) -> Result<()> { - let buffer_address = idl_write_buffer(cfg_override, program_id, idl_filepath)?; - let idl_address = idl_set_buffer(cfg_override, program_id, buffer_address, false)?; - idl_close(cfg_override, program_id, Some(buffer_address), false)?; + let buffer_address = idl_write_buffer(cfg_override, program_id, idl_filepath, priority_fee)?; + let idl_address = idl_set_buffer( + cfg_override, + program_id, + buffer_address, + false, + priority_fee, + )?; + idl_close( + cfg_override, + program_id, + Some(buffer_address), + false, + priority_fee, + )?; println!("Idl account {idl_address} successfully upgraded"); Ok(()) } @@ -2297,6 +2447,7 @@ fn idl_set_authority( address: Option, new_authority: Pubkey, print_only: bool, + priority_fee: Option, ) -> Result<()> { with_workspace(cfg_override, |cfg| { // Misc. @@ -2304,8 +2455,7 @@ fn idl_set_authority( None => IdlAccount::address(&program_id), Some(addr) => addr, }; - let keypair = solana_sdk::signature::read_keypair_file(&cfg.provider.wallet.to_string()) - .map_err(|_| anyhow!("Unable to read keypair file"))?; + let keypair = get_keypair(&cfg.provider.wallet.to_string())?; let url = cluster_url(cfg, &cfg.test_validator); let client = create_client(url); @@ -2335,10 +2485,12 @@ fn idl_set_authority( if print_only { print_idl_instruction("SetAuthority", &ix, &idl_address)?; } else { + let instructions = prepend_compute_unit_ix(vec![ix], &client, priority_fee)?; + // Send transaction. let latest_hash = client.get_latest_blockhash()?; let tx = Transaction::new_signed_with_payer( - &[ix], + &instructions, Some(&keypair.pubkey()), &[&keypair], latest_hash, @@ -2352,7 +2504,11 @@ fn idl_set_authority( }) } -fn idl_erase_authority(cfg_override: &ConfigOverride, program_id: Pubkey) -> Result<()> { +fn idl_erase_authority( + cfg_override: &ConfigOverride, + program_id: Pubkey, + priority_fee: Option, +) -> Result<()> { println!("Are you sure you want to erase the IDL authority: [y/n]"); let stdin = std::io::stdin(); @@ -2363,7 +2519,14 @@ fn idl_erase_authority(cfg_override: &ConfigOverride, program_id: Pubkey) -> Res return Ok(()); } - idl_set_authority(cfg_override, program_id, None, ERASED_AUTHORITY, false)?; + idl_set_authority( + cfg_override, + program_id, + None, + ERASED_AUTHORITY, + false, + priority_fee, + )?; Ok(()) } @@ -2373,9 +2536,9 @@ fn idl_close_account( program_id: &Pubkey, idl_address: Pubkey, print_only: bool, + priority_fee: Option, ) -> Result<()> { - let keypair = solana_sdk::signature::read_keypair_file(&cfg.provider.wallet.to_string()) - .map_err(|_| anyhow!("Unable to read keypair file"))?; + let keypair = get_keypair(&cfg.provider.wallet.to_string())?; let url = cluster_url(cfg, &cfg.test_validator); let client = create_client(url); @@ -2400,10 +2563,12 @@ fn idl_close_account( if print_only { print_idl_instruction("Close", &ix, &idl_address)?; } else { + let instructions = prepend_compute_unit_ix(vec![ix], &client, priority_fee)?; + // Send transaction. let latest_hash = client.get_latest_blockhash()?; let tx = Transaction::new_signed_with_payer( - &[ix], + &instructions, Some(&keypair.pubkey()), &[&keypair], latest_hash, @@ -2417,28 +2582,32 @@ fn idl_close_account( // Write the idl to the account buffer, chopping up the IDL into pieces // and sending multiple transactions in the event the IDL doesn't fit into // a single transaction. -fn idl_write(cfg: &Config, program_id: &Pubkey, idl: &Idl, idl_address: Pubkey) -> Result<()> { - // Remove the metadata before deploy. - let mut idl = idl.clone(); - idl.metadata = None; - +fn idl_write( + cfg: &Config, + program_id: &Pubkey, + idl: &Idl, + idl_address: Pubkey, + priority_fee: Option, +) -> Result<()> { // Misc. - let keypair = solana_sdk::signature::read_keypair_file(&cfg.provider.wallet.to_string()) - .map_err(|_| anyhow!("Unable to read keypair file"))?; + let keypair = get_keypair(&cfg.provider.wallet.to_string())?; let url = cluster_url(cfg, &cfg.test_validator); let client = create_client(url); // Serialize and compress the idl. let idl_data = { - let json_bytes = serde_json::to_vec(&idl)?; + let json_bytes = serde_json::to_vec(idl)?; let mut e = ZlibEncoder::new(Vec::new(), Compression::default()); e.write_all(&json_bytes)?; e.finish()? }; - const MAX_WRITE_SIZE: usize = 1000; + println!("Idl data length: {:?} bytes", idl_data.len()); + + const MAX_WRITE_SIZE: usize = 600; let mut offset = 0; while offset < idl_data.len() { + println!("Step {offset}/{} ", idl_data.len()); // Instruction data. let data = { let start = offset; @@ -2459,300 +2628,119 @@ fn idl_write(cfg: &Config, program_id: &Pubkey, idl: &Idl, idl_address: Pubkey) data, }; // Send transaction. - let latest_hash = client.get_latest_blockhash()?; - let tx = Transaction::new_signed_with_payer( - &[ix], - Some(&keypair.pubkey()), - &[&keypair], - latest_hash, - ); - client.send_and_confirm_transaction_with_spinner(&tx)?; + let instructions = prepend_compute_unit_ix(vec![ix], &client, priority_fee)?; + + let mut latest_hash = client.get_latest_blockhash()?; + for retries in 0..20 { + if !client.is_blockhash_valid(&latest_hash, client.commitment())? { + latest_hash = client.get_latest_blockhash()?; + } + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&keypair.pubkey()), + &[&keypair], + latest_hash, + ); + + match client.send_and_confirm_transaction_with_spinner(&tx) { + Ok(_) => break, + Err(e) => { + if retries == 19 { + return Err(anyhow!("Error: {e}. Failed to send transaction.")); + } + println!("Error: {e}. Retrying transaction."); + } + } + } + offset += MAX_WRITE_SIZE; } Ok(()) } -fn idl_parse( +fn idl_build( cfg_override: &ConfigOverride, - file: String, + program_name: Option, out: Option, out_ts: Option, no_docs: bool, + skip_lint: bool, + cargo_args: Vec, ) -> Result<()> { - let cfg = Config::discover(cfg_override)?.expect("Not in workspace."); - let file = shellexpand::tilde(&file); - let manifest_path = std::env::current_dir()?.join(PathBuf::from(&*file).parent().unwrap()); - let manifest = Manifest::discover_from_path(manifest_path)? - .ok_or_else(|| anyhow!("Cargo.toml not found"))?; - let idl = generate_idl_parse( - &*file, - manifest.version(), - cfg.features.seeds, + let cfg = Config::discover(cfg_override)?.expect("Not in workspace"); + let program_path = match program_name { + Some(name) => cfg.get_program(&name)?.path, + None => { + let current_dir = std::env::current_dir()?; + cfg.read_all_programs()? + .into_iter() + .find(|program| program.path == current_dir) + .ok_or_else(|| anyhow!("Not in a program directory"))? + .path + } + }; + check_idl_build_feature().ok(); + let idl = anchor_lang_idl::build::build_idl_with_cargo_args( + program_path, + cfg.features.resolution, + cfg.features.skip_lint || skip_lint, no_docs, - !cfg.features.skip_lint, + &cargo_args, )?; - let out = match out { + Some(path) => OutFile::File(PathBuf::from(path)), None => OutFile::Stdout, - Some(out) => OutFile::File(PathBuf::from(out)), }; write_idl(&idl, out)?; - // Write out the TypeScript IDL. - if let Some(out) = out_ts { - fs::write(out, rust_template::idl_ts(&idl)?)?; + if let Some(path) = out_ts { + fs::write(path, idl_ts(&idl)?)?; } Ok(()) } -fn idl_build(out: Option, out_ts: Option, no_docs: bool) -> Result<()> { - let idls = generate_idl_build(no_docs)?; - if idls.len() == 1 { - let idl = &idls[0]; - let out = match out { - None => OutFile::Stdout, - Some(path) => OutFile::File(PathBuf::from(path)), - }; - write_idl(idl, out)?; - - if let Some(path) = out_ts { - fs::write(path, rust_template::idl_ts(idl)?)?; - } - } else { - println!("{}", serde_json::to_string_pretty(&idls)?); - }; - - Ok(()) -} - /// Generate IDL with method decided by whether manifest file has `idl-build` feature or not. -fn generate_idl(cfg: &WithPath, skip_lint: bool, no_docs: bool) -> Result { - let manifest = Manifest::discover()?.ok_or_else(|| anyhow!("Cargo.toml not found"))?; - +fn generate_idl( + cfg: &WithPath, + skip_lint: bool, + no_docs: bool, + cargo_args: &[String], +) -> Result { // Check whether the manifest has `idl-build` feature + let manifest = Manifest::discover()?.ok_or_else(|| anyhow!("Cargo.toml not found"))?; let is_idl_build = manifest .features .iter() .any(|(feature, _)| feature == "idl-build"); - if is_idl_build { - generate_idl_build(no_docs)? - .into_iter() - .next() - .ok_or_else(|| anyhow!("Could not build IDL")) - } else { - generate_idl_parse( - "src/lib.rs", - manifest.version(), - cfg.features.seeds, - no_docs, - !(cfg.features.skip_lint || skip_lint), - ) - } -} - -/// Generate IDL with the parsing method(default). -fn generate_idl_parse( - path: impl AsRef, - version: String, - seeds_feature: bool, - no_docs: bool, - safety_checks: bool, -) -> Result { - anchor_syn::idl::parse::file::parse(path, version, seeds_feature, no_docs, safety_checks) -} - -/// Generate IDL with the build method. -fn generate_idl_build(no_docs: bool) -> Result> { - let no_docs = if no_docs { "TRUE" } else { "FALSE" }; - - let cfg = Config::discover(&ConfigOverride::default())?.expect("Not in workspace."); - let seeds_feature = if cfg.features.seeds { "TRUE" } else { "FALSE" }; - - let exit = std::process::Command::new("cargo") - .args([ - "test", - "__anchor_private_print_idl", - "--features", - "idl-build", - "--", - "--show-output", - "--quiet", - ]) - .env("ANCHOR_IDL_BUILD_NO_DOCS", no_docs) - .env("ANCHOR_IDL_BUILD_SEEDS_FEATURE", seeds_feature) - .stderr(Stdio::inherit()) - .output() - .map_err(|e| anyhow::format_err!("{}", e.to_string()))?; - if !exit.status.success() { - std::process::exit(exit.status.code().unwrap_or(1)); - } - - enum State { - Pass, - ConstLines(Vec), - EventLines(Vec), - ErrorsLines(Vec), - ProgramLines(Vec), - } - - #[derive(Serialize, Deserialize)] - struct IdlBuildEventPrint { - event: IdlEvent, - defined_types: Vec, - } - - let mut state = State::Pass; - - let mut events: Vec = vec![]; - let mut error_codes: Option> = None; - let mut constants: Vec = vec![]; - let mut defined_types: BTreeMap = BTreeMap::new(); - let mut curr_idl: Option = None; - - let mut idls: Vec = vec![]; - - let output = String::from_utf8_lossy(&exit.stdout); - for line in output.lines() { - match &mut state { - State::Pass => { - if line == "---- IDL begin const ----" { - state = State::ConstLines(vec![]); - continue; - } else if line == "---- IDL begin event ----" { - state = State::EventLines(vec![]); - continue; - } else if line == "---- IDL begin errors ----" { - state = State::ErrorsLines(vec![]); - continue; - } else if line == "---- IDL begin program ----" { - state = State::ProgramLines(vec![]); - continue; - } else if line.starts_with("test result: ok") { - let events = std::mem::take(&mut events); - let error_codes = error_codes.take(); - let constants = std::mem::take(&mut constants); - let mut defined_types = std::mem::take(&mut defined_types); - let curr_idl = curr_idl.take(); - - let events = if !events.is_empty() { - Some(events) - } else { - None - }; - - let mut idl = match curr_idl { - Some(idl) => idl, - None => continue, - }; - - idl.events = events; - idl.errors = error_codes; - idl.constants = constants; + if !is_idl_build { + let path = manifest.path().display(); + let anchor_spl_idl_build = manifest + .dependencies + .iter() + .any(|dep| dep.0 == "anchor-spl") + .then_some(r#", "anchor-spl/idl-build""#) + .unwrap_or_default(); - idl.constants.sort_by(|a, b| a.name.cmp(&b.name)); - idl.accounts.sort_by(|a, b| a.name.cmp(&b.name)); - if let Some(e) = idl.events.as_mut() { - e.sort_by(|a, b| a.name.cmp(&b.name)) - } + return Err(anyhow!( + r#"`idl-build` feature is missing. To solve, add - let prog_ty = std::mem::take(&mut idl.types); - defined_types.extend(prog_ty.into_iter().map(|ty| (ty.name.clone(), ty))); - idl.types = defined_types.into_values().collect::>(); +[features] +idl-build = ["anchor-lang/idl-build"{anchor_spl_idl_build}] - idls.push(idl); - continue; - } - } - State::ConstLines(lines) => { - if line == "---- IDL end const ----" { - let constant: IdlConst = serde_json::from_str(&lines.join("\n"))?; - constants.push(constant); - state = State::Pass; - continue; - } - lines.push(line.to_string()); - } - State::EventLines(lines) => { - if line == "---- IDL end event ----" { - let event: IdlBuildEventPrint = serde_json::from_str(&lines.join("\n"))?; - events.push(event.event); - defined_types.extend( - event - .defined_types - .into_iter() - .map(|ty| (ty.name.clone(), ty)), - ); - state = State::Pass; - continue; - } - lines.push(line.to_string()); - } - State::ErrorsLines(lines) => { - if line == "---- IDL end errors ----" { - let errs: Vec = serde_json::from_str(&lines.join("\n"))?; - error_codes = Some(errs); - state = State::Pass; - continue; - } - lines.push(line.to_string()); - } - State::ProgramLines(lines) => { - if line == "---- IDL end program ----" { - let idl: Idl = serde_json::from_str(&lines.join("\n"))?; - curr_idl = Some(idl); - state = State::Pass; - continue; - } - lines.push(line.to_string()); - } - } +in `{path}`."# + )); } - // Convert path to name if there are no conflicts - let path_regex = Regex::new(r#""((\w+::)+)(\w+)""#).unwrap(); - let idls = idls - .into_iter() - .filter_map(|idl| { - let mut modified_idl = serde_json::to_string(&idl).unwrap(); - - // TODO: Remove. False positive https://github.com/rust-lang/rust-clippy/issues/10577 - #[allow(clippy::redundant_clone)] - for captures in path_regex.captures_iter(&modified_idl.clone()) { - let path = captures.get(0).unwrap().as_str(); - let name = captures.get(3).unwrap().as_str(); - - // Replace path with name - let replaced_idl = modified_idl.replace(path, &format!(r#""{name}""#)); - - // Check whether there is a conflict - let has_conflict = replaced_idl.contains(&format!(r#"::{name}""#)); - if !has_conflict { - modified_idl = replaced_idl; - } - } - - serde_json::from_str::(&modified_idl).ok() - }) - .collect::>(); - - // Verify IDLs are valid - for idl in &idls { - let full_path_account = idl - .accounts - .iter() - .find(|account| account.name.contains("::")); - - if let Some(account) = full_path_account { - return Err(anyhow!( - "Conflicting accounts names are not allowed.\nProgram: {}\nAccount: {}", - idl.name, - account.name - )); - } - } + check_idl_build_feature().ok(); - Ok(idls) + anchor_lang_idl::build::build_idl_with_cargo_args( + std::env::current_dir()?, + cfg.features.resolution, + cfg.features.skip_lint || skip_lint, + no_docs, + cargo_args, + ) } fn idl_fetch(cfg_override: &ConfigOverride, address: Pubkey, out: Option) -> Result<()> { @@ -2764,6 +2752,62 @@ fn idl_fetch(cfg_override: &ConfigOverride, address: Pubkey, out: Option write_idl(&idl, out) } +fn idl_convert(path: String, out: Option) -> Result<()> { + let idl = fs::read(path)?; + let idl = convert_idl(&idl)?; + let out = match out { + None => OutFile::Stdout, + Some(out) => OutFile::File(PathBuf::from(out)), + }; + write_idl(&idl, out) +} + +fn idl_type(path: String, out: Option) -> Result<()> { + let idl = fs::read(path)?; + let idl = convert_idl(&idl)?; + let types = idl_ts(&idl)?; + match out { + Some(out) => fs::write(out, types)?, + _ => println!("{types}"), + }; + Ok(()) +} + +fn idl_ts(idl: &Idl) -> Result { + let idl_name = &idl.metadata.name; + let type_name = idl_name.to_pascal_case(); + let idl = serde_json::to_string(idl)?; + + // Convert every field of the IDL to camelCase + let camel_idl = Regex::new(r#""\w+":"([\w\d]+)""#)? + .captures_iter(&idl) + .fold(idl.clone(), |acc, cur| { + let name = cur.get(1).unwrap().as_str(); + + // Do not modify pubkeys + if Pubkey::from_str(name).is_ok() { + return acc; + } + + let camel_name = name.to_lower_camel_case(); + acc.replace(&format!(r#""{name}""#), &format!(r#""{camel_name}""#)) + }); + + // Pretty format + let camel_idl = serde_json::to_string_pretty(&serde_json::from_str::(&camel_idl)?)?; + + Ok(format!( + r#"/** + * Program IDL in camelCase format in order to be used in JS/TS. + * + * Note that this is only a type helper and is not the actual IDL. The original + * IDL can be found at `target/idl/{idl_name}.json`. + */ +export type {type_name} = {camel_idl}; +"# + )) +} + fn write_idl(idl: &Idl, out: OutFile) -> Result<()> { let idl_json = serde_json::to_string_pretty(idl)?; match out { @@ -2813,7 +2857,7 @@ fn account( idl_filepath: Option, ) -> Result<()> { let (program_name, account_type_name) = account_type - .split_once('.') // Split at first occurance of dot + .split_once('.') // Split at first occurrence of dot .and_then(|(x, y)| y.find('.').map_or_else(|| Some((x, y)), |_| None)) // ensures no dots in second substring .ok_or_else(|| { anyhow!( @@ -2840,7 +2884,7 @@ fn account( let bytes = fs::read(idl_path).expect("Unable to read IDL."); let idl: Idl = serde_json::from_reader(&*bytes).expect("Invalid IDL format."); - if idl.name != program_name { + if idl.metadata.name != program_name { panic!("IDL does not match program {program_name}."); } @@ -2856,12 +2900,13 @@ fn account( }; let data = create_client(cluster.url()).get_account_data(&address)?; - if data.len() < 8 { - return Err(anyhow!( - "The account has less than 8 bytes and is not an Anchor account." - )); - } - let mut data_view = &data[8..]; + let disc_len = idl + .accounts + .iter() + .find(|acc| acc.name == account_type_name) + .map(|acc| acc.discriminator.len()) + .ok_or_else(|| anyhow!("Account `{account_type_name}` not found in IDL"))?; + let mut data_view = &data[disc_len..]; let deserialized_json = deserialize_idl_defined_type_to_json(&idl, account_type_name, &mut data_view)?; @@ -2881,25 +2926,40 @@ fn deserialize_idl_defined_type_to_json( data: &mut &[u8], ) -> Result { let defined_type = &idl - .types + .accounts .iter() - .chain(idl.accounts.iter()) - .find(|defined_type| defined_type.name == defined_type_name) + .find(|acc| acc.name == defined_type_name) + .and_then(|acc| idl.types.iter().find(|ty| ty.name == acc.name)) + .or_else(|| idl.types.iter().find(|ty| ty.name == defined_type_name)) .ok_or_else(|| anyhow!("Type `{}` not found in IDL.", defined_type_name))? .ty; let mut deserialized_fields = Map::new(); match defined_type { - IdlTypeDefinitionTy::Struct { fields } => { - for field in fields { - deserialized_fields.insert( - field.name.clone(), - deserialize_idl_type_to_json(&field.ty, data, idl)?, - ); + IdlTypeDefTy::Struct { fields } => { + if let Some(fields) = fields { + match fields { + IdlDefinedFields::Named(fields) => { + for field in fields { + deserialized_fields.insert( + field.name.clone(), + deserialize_idl_type_to_json(&field.ty, data, idl)?, + ); + } + } + IdlDefinedFields::Tuple(fields) => { + let mut values = Vec::new(); + for field in fields { + values.push(deserialize_idl_type_to_json(field, data, idl)?); + } + deserialized_fields + .insert(defined_type_name.to_owned(), JsonValue::Array(values)); + } + } } } - IdlTypeDefinitionTy::Enum { variants } => { + IdlTypeDefTy::Enum { variants } => { let repr = ::deserialize(data)?; let variant = variants @@ -2910,25 +2970,21 @@ fn deserialize_idl_defined_type_to_json( if let Some(enum_field) = &variant.fields { match enum_field { - EnumFields::Named(fields) => { + IdlDefinedFields::Named(fields) => { let mut values = Map::new(); - for field in fields { values.insert( field.name.clone(), deserialize_idl_type_to_json(&field.ty, data, idl)?, ); } - value = JsonValue::Object(values); } - EnumFields::Tuple(fields) => { + IdlDefinedFields::Tuple(fields) => { let mut values = Vec::new(); - for field in fields { values.push(deserialize_idl_type_to_json(field, data, idl)?); } - value = JsonValue::Array(values); } } @@ -2936,8 +2992,8 @@ fn deserialize_idl_defined_type_to_json( deserialized_fields.insert(variant.name.clone(), value); } - IdlTypeDefinitionTy::Alias { value } => { - return deserialize_idl_type_to_json(value, data, idl); + IdlTypeDefTy::Type { alias } => { + return deserialize_idl_type_to_json(alias, data, idl); } } @@ -2999,12 +3055,22 @@ fn deserialize_idl_type_to_json( .collect(), ), IdlType::String => json!(::deserialize(data)?), - IdlType::PublicKey => { + IdlType::Pubkey => { json!(::deserialize(data)?.to_string()) } - IdlType::Defined(type_name) => { - deserialize_idl_defined_type_to_json(parent_idl, type_name, data)? - } + IdlType::Array(ty, size) => match size { + IdlArrayLen::Value(size) => { + let mut array_data: Vec = Vec::with_capacity(*size); + + for _ in 0..*size { + array_data.push(deserialize_idl_type_to_json(ty, data, parent_idl)?); + } + + JsonValue::Array(array_data) + } + // TODO: + IdlArrayLen::Generic(_) => unimplemented!("Generic array length is not yet supported"), + }, IdlType::Option(ty) => { let is_present = ::deserialize(data)?; @@ -3027,20 +3093,15 @@ fn deserialize_idl_type_to_json( JsonValue::Array(vec_data) } - IdlType::Array(ty, size) => { - let mut array_data: Vec = Vec::with_capacity(*size); - - for _ in 0..*size { - array_data.push(deserialize_idl_type_to_json(ty, data, parent_idl)?); - } - - JsonValue::Array(array_data) - } - IdlType::GenericLenArray(_, _) => todo!("Generic length arrays are not yet supported"), - IdlType::Generic(_) => todo!("Generic types are not yet supported"), - IdlType::DefinedWithTypeArgs { name: _, args: _ } => { - todo!("Defined types with type args are not yet supported") + IdlType::Defined { + name, + generics: _generics, + } => { + // TODO: Generics + deserialize_idl_defined_type_to_json(parent_idl, name, data)? } + IdlType::Generic(generic) => json!(generic), + _ => unimplemented!("{idl_type:?}"), }) } @@ -3053,6 +3114,7 @@ enum OutFile { #[allow(clippy::too_many_arguments)] fn test( cfg_override: &ConfigOverride, + program_name: Option, skip_deploy: bool, skip_local_validator: bool, skip_build: bool, @@ -3078,11 +3140,12 @@ fn test( if !skip_build { build( cfg_override, + false, None, None, false, skip_lint, - None, + program_name.clone(), None, None, BootstrapMode::None, @@ -3109,12 +3172,36 @@ fn test( deploy(cfg_override, None, None, false, vec![])?; } let mut is_first_suite = true; - if cfg.scripts.get("test").is_some() { + if let Some(test_script) = cfg.scripts.get_mut("test") { is_first_suite = false; - println!("\nFound a 'test' script in the Anchor.toml. Running it as a test suite!"); + + match program_name { + Some(program_name) => { + if let Some((from, to)) = Regex::new("\\s(tests/\\S+\\.(js|ts))") + .unwrap() + .captures_iter(&test_script.clone()) + .last() + .and_then(|c| c.get(1).and_then(|mtch| c.get(2).map(|ext| (mtch, ext)))) + .map(|(mtch, ext)| { + ( + mtch.as_str(), + format!("tests/{program_name}.{}", ext.as_str()), + ) + }) + { + println!("\nRunning tests of program `{program_name}`!"); + // Replace the last path to the program name's path + *test_script = test_script.replace(from, &to); + } + } + _ => println!( + "\nFound a 'test' script in the Anchor.toml. Running it as a test suite!" + ), + } + run_test_suite( - cfg.path(), cfg, + cfg.path(), is_localnet, skip_local_validator, skip_deploy, @@ -3140,8 +3227,8 @@ fn test( } run_test_suite( - test_suite.0, cfg, + test_suite.0, is_localnet, skip_local_validator, skip_deploy, @@ -3158,8 +3245,8 @@ fn test( #[allow(clippy::too_many_arguments)] fn run_test_suite( - test_suite_path: impl AsRef, cfg: &WithPath, + test_suite_path: impl AsRef, is_localnet: bool, skip_local_validator: bool, skip_deploy: bool, @@ -3196,7 +3283,7 @@ fn run_test_suite( let log_streams = stream_logs(cfg, &url); // Run the tests. - let test_result: Result<_> = { + let test_result = { let cmd = scripts .get("test") .expect("Not able to find script for `test`") @@ -3248,6 +3335,7 @@ fn run_test_suite( Ok(()) } + // Returns the solana-test-validator flags. This will embed the workspace // programs in the genesis block so we don't have to deploy every time. It also // allows control of other solana-test-validator features. @@ -3287,11 +3375,11 @@ fn validator_flags( if let Some(idl) = program.idl.as_mut() { // Add program address to the IDL. - idl.metadata = Some(serde_json::to_value(IdlTestMetadata { address })?); + idl.address = address; // Persist it. let idl_out = PathBuf::from("target/idl") - .join(&idl.name) + .join(&idl.metadata.name) .with_extension("json"); write_idl(idl, OutFile::File(idl_out))?; } @@ -3349,7 +3437,7 @@ fn validator_flags( )); }; - let mut pubkeys = value + let pubkeys = value .as_array() .unwrap() .iter() @@ -3358,35 +3446,50 @@ fn validator_flags( Pubkey::from_str(address) .map_err(|_| anyhow!("Invalid pubkey {}", address)) }) - .collect::>>()?; - - let accounts_keys = pubkeys.iter().cloned().collect::>(); - let accounts = client.get_multiple_accounts(&accounts_keys)?; - - // Check if there are program accounts - for (account, acc_key) in accounts.iter().zip(accounts_keys) { - if let Some(account) = account { - if account.owner == bpf_loader_upgradeable::id() { - let upgradable: UpgradeableLoaderState = account - .deserialize_data() - .map_err(|_| anyhow!("Invalid program account {}", acc_key))?; - - if let UpgradeableLoaderState::Program { - programdata_address, - } = upgradable + .collect::>>()? + .into_iter() + .collect::>(); + let accounts = client.get_multiple_accounts(&pubkeys)?; + + for (pubkey, account) in pubkeys.into_iter().zip(accounts) { + match account { + Some(account) => { + // Use a different flag for program accounts to fix the problem + // described in https://github.com/anza-xyz/agave/issues/522 + if account.owner == bpf_loader_upgradeable::id() + // Only programs are supported with `--clone-upgradeable-program` + && matches!( + account.deserialize_data::()?, + UpgradeableLoaderState::Program { .. } + ) { - pubkeys.insert(programdata_address); + flags.push("--clone-upgradeable-program".to_string()); + flags.push(pubkey.to_string()); + } else { + flags.push("--clone".to_string()); + flags.push(pubkey.to_string()); } } - } else { - return Err(anyhow!("Account {} not found", acc_key)); + _ => return Err(anyhow!("Account {} not found", pubkey)), } } - - for pubkey in &pubkeys { - // Push the clone flag for each array entry - flags.push("--clone".to_string()); - flags.push(pubkey.to_string()); + } else if key == "deactivate_feature" { + // Verify that the feature flags are valid pubkeys + let pubkeys_result: Result, _> = value + .as_array() + .unwrap() + .iter() + .map(|entry| { + let feature_flag = entry.as_str().unwrap(); + Pubkey::from_str(feature_flag).map_err(|_| { + anyhow!("Invalid pubkey (feature flag) {}", feature_flag) + }) + }) + .collect(); + let features = pubkeys_result?; + for feature in features { + flags.push("--deactivate-feature".to_string()); + flags.push(feature.to_string()); } } else { // Remaining validator flags are non-array types @@ -3416,22 +3519,15 @@ fn stream_logs(config: &WithPath, rpc_url: &str) -> Result, rpc_url: &str) -> Result, @@ -3470,7 +3561,7 @@ fn start_test_validator( test_log_stdout: bool, ) -> Result { let (test_ledger_directory, test_ledger_log_filename) = - test_validator_file_paths(test_validator); + test_validator_file_paths(test_validator)?; // Start a validator for testing. let (test_validator_stdout, test_validator_stderr) = match test_log_stdout { @@ -3517,7 +3608,7 @@ fn start_test_validator( .stdout(test_validator_stdout) .stderr(test_validator_stderr) .spawn() - .map_err(|e| anyhow::format_err!("{}", e.to_string()))?; + .map_err(|e| anyhow!("Failed to spawn `solana-test-validator`: {e}"))?; // Wait for the validator to be ready. let client = create_client(rpc_url); @@ -3531,12 +3622,13 @@ fn start_test_validator( if r.is_ok() { break; } - std::thread::sleep(std::time::Duration::from_millis(1)); - count += 1; + std::thread::sleep(std::time::Duration::from_millis(100)); + count += 100; } - if count == ms_wait { + if count >= ms_wait { eprintln!( - "Unable to get latest blockhash. Test validator does not look started. Check {test_ledger_log_filename} for errors. Consider increasing [test.startup_wait] in Anchor.toml." + "Unable to get latest blockhash. Test validator does not look started. \ + Check {test_ledger_log_filename:?} for errors. Consider increasing [test.startup_wait] in Anchor.toml." ); validator_handle.kill()?; std::process::exit(1); @@ -3558,31 +3650,32 @@ fn test_validator_rpc_url(test_validator: &Option) -> String { // Setup and return paths to the solana-test-validator ledger directory and log // files given the configuration -fn test_validator_file_paths(test_validator: &Option) -> (String, String) { - let ledger_directory = match test_validator { +fn test_validator_file_paths(test_validator: &Option) -> Result<(PathBuf, PathBuf)> { + let ledger_path = match test_validator { Some(TestValidator { validator: Some(validator), .. }) => &validator.ledger, - _ => ".anchor/test-ledger", + _ => DEFAULT_LEDGER_PATH, }; + let ledger_path = Path::new(ledger_path); - if !Path::new(&ledger_directory).is_relative() { + if !ledger_path.is_relative() { // Prevent absolute paths to avoid someone using / or similar, as the // directory gets removed - eprintln!("Ledger directory {ledger_directory} must be relative"); + eprintln!("Ledger directory {ledger_path:?} must be relative"); std::process::exit(1); } - if Path::new(&ledger_directory).exists() { - fs::remove_dir_all(ledger_directory).unwrap(); + if ledger_path.exists() { + fs::remove_dir_all(ledger_path)?; } - fs::create_dir_all(ledger_directory).unwrap(); + fs::create_dir_all(ledger_path)?; - ( - ledger_directory.to_string(), - format!("{ledger_directory}/test-ledger-log.txt"), - ) + Ok(( + ledger_path.to_owned(), + ledger_path.join("test-ledger-log.txt"), + )) } fn cluster_url(cfg: &Config, test_validator: &Option) -> String { @@ -3654,12 +3747,7 @@ fn deploy( println!("Program path: {}...", binary_path); let (program_keypair_filepath, program_id) = match &program_keypair { - Some(path) => ( - path.clone(), - solana_sdk::signature::read_keypair_file(path) - .map_err(|_| anyhow!("Unable to read keypair file"))? - .pubkey(), - ), + Some(path) => (path.clone(), get_keypair(path)?.pubkey()), None => ( program.keypair_file()?.path().display().to_string(), program.pubkey()?, @@ -3691,13 +3779,11 @@ fn deploy( if let Some(idl) = program.idl.as_mut() { // Add program address to the IDL. - idl.metadata = Some(serde_json::to_value(IdlTestMetadata { - address: program_id.to_string(), - })?); + idl.address = program_id.to_string(); // Persist it. let idl_out = PathBuf::from("target/idl") - .join(&idl.name) + .join(&idl.metadata.name) .with_extension("json"); write_idl(idl, OutFile::File(idl_out))?; } @@ -3713,6 +3799,7 @@ fn upgrade( cfg_override: &ConfigOverride, program_id: Pubkey, program_filepath: String, + solana_args: Vec, ) -> Result<()> { let path: PathBuf = program_filepath.parse().unwrap(); let program_filepath = path.canonicalize()?.display().to_string(); @@ -3725,10 +3812,11 @@ fn upgrade( .arg("--url") .arg(url) .arg("--keypair") - .arg(&cfg.provider.wallet.to_string()) + .arg(cfg.provider.wallet.to_string()) .arg("--program-id") .arg(strip_workspace_prefix(program_id.to_string())) .arg(strip_workspace_prefix(program_filepath)) + .args(&solana_args) .stdout(Stdio::inherit()) .stderr(Stdio::inherit()) .output() @@ -3746,11 +3834,11 @@ fn create_idl_account( keypair_path: &str, program_id: &Pubkey, idl: &Idl, + priority_fee: Option, ) -> Result { // Misc. let idl_address = IdlAccount::address(program_id); - let keypair = solana_sdk::signature::read_keypair_file(keypair_path) - .map_err(|_| anyhow!("Unable to read keypair file"))?; + let keypair = get_keypair(keypair_path)?; let url = cluster_url(cfg, &cfg.test_validator); let client = create_client(url); let idl_data = serialize_idl(idl)?; @@ -3800,18 +3888,41 @@ fn create_idl_account( data, }); } - let latest_hash = client.get_latest_blockhash()?; - let tx = Transaction::new_signed_with_payer( - &instructions, - Some(&keypair.pubkey()), - &[&keypair], - latest_hash, - ); - client.send_and_confirm_transaction_with_spinner(&tx)?; + instructions = prepend_compute_unit_ix(instructions, &client, priority_fee)?; + + let mut latest_hash = client.get_latest_blockhash()?; + for retries in 0..20 { + if !client.is_blockhash_valid(&latest_hash, client.commitment())? { + latest_hash = client.get_latest_blockhash()?; + } + + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&keypair.pubkey()), + &[&keypair], + latest_hash, + ); + + match client.send_and_confirm_transaction_with_spinner(&tx) { + Ok(_) => break, + Err(err) => { + if retries == 19 { + return Err(anyhow!("Error creating IDL account: {}", err)); + } + println!("Error creating IDL account: {}. Retrying...", err); + } + } + } } // Write directly to the IDL account buffer. - idl_write(cfg, program_id, idl, IdlAccount::address(program_id))?; + idl_write( + cfg, + program_id, + idl, + IdlAccount::address(program_id), + priority_fee, + )?; Ok(idl_address) } @@ -3821,9 +3932,9 @@ fn create_idl_buffer( keypair_path: &str, program_id: &Pubkey, idl: &Idl, + priority_fee: Option, ) -> Result { - let keypair = solana_sdk::signature::read_keypair_file(keypair_path) - .map_err(|_| anyhow!("Unable to read keypair file"))?; + let keypair = get_keypair(keypair_path)?; let url = cluster_url(cfg, &cfg.test_validator); let client = create_client(url); @@ -3831,7 +3942,7 @@ fn create_idl_buffer( // Creates the new buffer account with the system program. let create_account_ix = { - let space = 8 + 32 + 4 + serialize_idl(idl)?.len(); + let space = IdlAccount::DISCRIMINATOR.len() + 32 + 4 + serialize_idl(idl)?.len(); let lamports = client.get_minimum_balance_for_rent_exemption(space)?; solana_sdk::system_instruction::create_account( &keypair.pubkey(), @@ -3858,17 +3969,33 @@ fn create_idl_buffer( } }; - // Build the transaction. - let latest_hash = client.get_latest_blockhash()?; - let tx = Transaction::new_signed_with_payer( - &[create_account_ix, create_buffer_ix], - Some(&keypair.pubkey()), - &[&keypair, &buffer], - latest_hash, - ); + let instructions = prepend_compute_unit_ix( + vec![create_account_ix, create_buffer_ix], + &client, + priority_fee, + )?; - // Send the transaction. - client.send_and_confirm_transaction_with_spinner(&tx)?; + let mut latest_hash = client.get_latest_blockhash()?; + for retries in 0..20 { + if !client.is_blockhash_valid(&latest_hash, client.commitment())? { + latest_hash = client.get_latest_blockhash()?; + } + let tx = Transaction::new_signed_with_payer( + &instructions, + Some(&keypair.pubkey()), + &[&keypair, &buffer], + latest_hash, + ); + match client.send_and_confirm_transaction_with_spinner(&tx) { + Ok(_) => break, + Err(err) => { + if retries == 19 { + return Err(anyhow!("Error creating buffer account: {}", err)); + } + println!("Error creating buffer account: {}. Retrying...", err); + } + } + } Ok(buffer.pubkey()) } @@ -4017,7 +4144,7 @@ fn shell(cfg_override: &ConfigOverride) -> Result<()> { .filter(|program| program.idl.is_some()) .map(|program| { ( - program.idl.as_ref().unwrap().name.clone(), + program.idl.as_ref().unwrap().metadata.name.clone(), program.idl.clone().unwrap(), ) }) @@ -4233,6 +4360,7 @@ fn publish( if !skip_build { build( cfg_override, + false, None, None, true, @@ -4403,6 +4531,7 @@ fn localnet( if !skip_build { build( cfg_override, + false, None, None, false, @@ -4496,6 +4625,46 @@ fn get_node_version() -> Result { Version::parse(output).map_err(Into::into) } +fn get_recommended_micro_lamport_fee(client: &RpcClient, priority_fee: Option) -> Result { + if let Some(priority_fee) = priority_fee { + return Ok(priority_fee); + } + + let mut fees = client.get_recent_prioritization_fees(&[])?; + + // Get the median fee from the most recent recent 150 slots' prioritization fee + fees.sort_unstable_by_key(|fee| fee.prioritization_fee); + let median_index = fees.len() / 2; + + let median_priority_fee = if fees.len() % 2 == 0 { + (fees[median_index - 1].prioritization_fee + fees[median_index].prioritization_fee) / 2 + } else { + fees[median_index].prioritization_fee + }; + + Ok(median_priority_fee) +} +/// Prepend a compute unit ix, if the priority fee is greater than 0. +/// This helps to improve the chances that the transaction will land. +fn prepend_compute_unit_ix( + instructions: Vec, + client: &RpcClient, + priority_fee: Option, +) -> Result> { + let priority_fee = get_recommended_micro_lamport_fee(client, priority_fee)?; + + if priority_fee > 0 { + let mut instructions_appended = instructions.clone(); + instructions_appended.insert( + 0, + ComputeBudgetInstruction::set_compute_unit_price(priority_fee), + ); + Ok(instructions_appended) + } else { + Ok(instructions) + } +} + fn get_node_dns_option() -> Result<&'static str> { let version = get_node_version()?; let req = VersionReq::parse(">=16.4.0").unwrap(); @@ -4540,9 +4709,10 @@ mod tests { "await".to_string(), true, false, - false, + true, false, ProgramTemplate::default(), + TestTemplate::default(), false, ) .unwrap(); @@ -4559,9 +4729,10 @@ mod tests { "fn".to_string(), true, false, - false, + true, false, ProgramTemplate::default(), + TestTemplate::default(), false, ) .unwrap(); @@ -4578,9 +4749,10 @@ mod tests { "1project".to_string(), true, false, - false, + true, false, ProgramTemplate::default(), + TestTemplate::default(), false, ) .unwrap(); diff --git a/cli/src/rust_template.rs b/cli/src/rust_template.rs index 7375908a87..efea3b360d 100644 --- a/cli/src/rust_template.rs +++ b/cli/src/rust_template.rs @@ -1,15 +1,22 @@ -use crate::VERSION; -use crate::{config::ProgramWorkspace, create_files, Files}; -use anchor_syn::idl::types::Idl; +use crate::{ + config::ProgramWorkspace, create_files, override_or_create_files, solidity_template, Files, + VERSION, +}; use anyhow::Result; use clap::{Parser, ValueEnum}; -use heck::{ToLowerCamelCase, ToSnakeCase, ToUpperCamelCase}; +use heck::{ToPascalCase, ToSnakeCase}; use solana_sdk::{ pubkey::Pubkey, signature::{read_keypair_file, write_keypair_file, Keypair}, signer::Signer, }; -use std::{fmt::Write, path::Path}; +use std::{ + fmt::Write as _, + fs::{self, File}, + io::Write as _, + path::Path, + process::Stdio, +}; /// Program initialization template #[derive(Clone, Debug, Default, Eq, PartialEq, Parser, ValueEnum)] @@ -52,6 +59,7 @@ pub mod {} {{ use super::*; pub fn initialize(ctx: Context) -> Result<()> {{ + msg!("Greetings from: {{:?}}", ctx.program_id); Ok(()) }} }} @@ -135,6 +143,7 @@ pub use initialize::*; pub struct Initialize {} pub fn handler(ctx: Context) -> Result<()> { + msg!("Greetings from: {{:?}}", ctx.program_id); Ok(()) } "# @@ -175,11 +184,12 @@ crate-type = ["cdylib", "lib"] name = "{1}" [features] +default = [] +cpi = ["no-entrypoint"] no-entrypoint = [] no-idl = [] no-log-ix-name = [] -cpi = ["no-entrypoint"] -default = [] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = "{2}" @@ -219,24 +229,6 @@ token = "{token}" ) } -pub fn idl_ts(idl: &Idl) -> Result { - let mut idl = idl.clone(); - for acc in idl.accounts.iter_mut() { - acc.name = acc.name.to_lower_camel_case(); - } - let idl_json = serde_json::to_string_pretty(&idl)?; - Ok(format!( - r#"export type {} = {}; - -export const IDL: {} = {}; -"#, - idl.name.to_upper_camel_case(), - idl_json, - idl.name.to_upper_camel_case(), - idl_json - )) -} - pub fn deploy_js_script_host(cluster_url: &str, script_path: &str) -> String { format!( r#" @@ -339,7 +331,7 @@ describe("{}", () => {{ }}); "#, name, - name.to_upper_camel_case(), + name.to_pascal_case(), ) } @@ -360,91 +352,95 @@ describe("{}", () => {{ }}); "#, name, - name.to_upper_camel_case(), + name.to_pascal_case(), ) } -pub fn package_json(jest: bool) -> String { +pub fn package_json(jest: bool, license: String) -> String { if jest { format!( r#"{{ - "scripts": {{ - "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", - "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" - }}, - "dependencies": {{ - "@coral-xyz/anchor": "^{VERSION}" - }}, - "devDependencies": {{ - "jest": "^29.0.3", - "prettier": "^2.6.2" - }} - }} + "license": "{license}", + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{VERSION}" + }}, + "devDependencies": {{ + "jest": "^29.0.3", + "prettier": "^2.6.2" + }} +}} "# ) } else { format!( r#"{{ - "scripts": {{ - "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", - "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" - }}, - "dependencies": {{ - "@coral-xyz/anchor": "^{VERSION}" - }}, - "devDependencies": {{ - "chai": "^4.3.4", - "mocha": "^9.0.3", - "prettier": "^2.6.2" - }} + "license": "{license}", + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{VERSION}" + }}, + "devDependencies": {{ + "chai": "^4.3.4", + "mocha": "^9.0.3", + "prettier": "^2.6.2" + }} }} "# ) } } -pub fn ts_package_json(jest: bool) -> String { +pub fn ts_package_json(jest: bool, license: String) -> String { if jest { format!( r#"{{ - "scripts": {{ - "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", - "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" - }}, - "dependencies": {{ - "@coral-xyz/anchor": "^{VERSION}" - }}, - "devDependencies": {{ - "@types/bn.js": "^5.1.0", - "@types/jest": "^29.0.3", - "jest": "^29.0.3", - "prettier": "^2.6.2", - "ts-jest": "^29.0.2", - "typescript": "^4.3.5" - }} - }} - "# + "license": "{license}", + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{VERSION}" + }}, + "devDependencies": {{ + "@types/bn.js": "^5.1.0", + "@types/jest": "^29.0.3", + "jest": "^29.0.3", + "prettier": "^2.6.2", + "ts-jest": "^29.0.2", + "typescript": "^4.3.5" + }} +}} +"# ) } else { format!( r#"{{ - "scripts": {{ - "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", - "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" - }}, - "dependencies": {{ - "@coral-xyz/anchor": "^{VERSION}" - }}, - "devDependencies": {{ - "chai": "^4.3.4", - "mocha": "^9.0.3", - "ts-mocha": "^10.0.0", - "@types/bn.js": "^5.1.0", - "@types/chai": "^4.3.0", - "@types/mocha": "^9.0.0", - "typescript": "^4.3.5", - "prettier": "^2.6.2" - }} + "license": "{license}", + "scripts": {{ + "lint:fix": "prettier */*.js \"*/**/*{{.js,.ts}}\" -w", + "lint": "prettier */*.js \"*/**/*{{.js,.ts}}\" --check" + }}, + "dependencies": {{ + "@coral-xyz/anchor": "^{VERSION}" + }}, + "devDependencies": {{ + "chai": "^4.3.4", + "mocha": "^9.0.3", + "ts-mocha": "^10.0.0", + "@types/bn.js": "^5.1.0", + "@types/chai": "^4.3.0", + "@types/mocha": "^9.0.0", + "typescript": "^4.3.5", + "prettier": "^2.6.2" + }} }} "# ) @@ -470,11 +466,11 @@ describe("{}", () => {{ }}); }}); "#, - name.to_upper_camel_case(), + name.to_pascal_case(), name.to_snake_case(), name, - name.to_upper_camel_case(), - name.to_upper_camel_case(), + name.to_pascal_case(), + name.to_pascal_case(), ) } @@ -497,45 +493,44 @@ describe("{}", () => {{ }}); }}); "#, - name.to_upper_camel_case(), + name.to_pascal_case(), name.to_snake_case(), name, - name.to_upper_camel_case(), - name.to_upper_camel_case(), + name.to_pascal_case(), + name.to_pascal_case(), ) } pub fn ts_config(jest: bool) -> &'static str { if jest { r#"{ - "compilerOptions": { - "types": ["jest"], - "typeRoots": ["./node_modules/@types"], - "lib": ["es2015"], - "module": "commonjs", - "target": "es6", - "esModuleInterop": true - } - } - "# + "compilerOptions": { + "types": ["jest"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } +} +"# } else { r#"{ - "compilerOptions": { - "types": ["mocha", "chai"], - "typeRoots": ["./node_modules/@types"], - "lib": ["es2015"], - "module": "commonjs", - "target": "es6", - "esModuleInterop": true - } - } - "# + "compilerOptions": { + "types": ["mocha", "chai"], + "typeRoots": ["./node_modules/@types"], + "lib": ["es2015"], + "module": "commonjs", + "target": "es6", + "esModuleInterop": true + } +} +"# } } pub fn git_ignore() -> &'static str { - r#" -.anchor + r#".anchor .DS_Store target **/*.rs.bk @@ -546,8 +541,7 @@ test-ledger } pub fn prettier_ignore() -> &'static str { - r#" -.anchor + r#".anchor .DS_Store target node_modules @@ -598,7 +592,7 @@ anchor.setProvider(provider); r#" anchor.workspace.{} = new anchor.Program({}, new PublicKey("{}"), provider); "#, - program.name.to_upper_camel_case(), + program.name.to_pascal_case(), serde_json::to_string(&program.idl)?, program.program_id )?; @@ -606,3 +600,176 @@ anchor.workspace.{} = new anchor.Program({}, new PublicKey("{}"), provider); Ok(eval_string) } + +/// Test initialization template +#[derive(Clone, Debug, Default, Eq, PartialEq, Parser, ValueEnum)] +pub enum TestTemplate { + /// Generate template for Mocha unit-test + #[default] + Mocha, + /// Generate template for Jest unit-test + Jest, + /// Generate template for Rust unit-test + Rust, +} + +impl TestTemplate { + pub fn get_test_script(&self, js: bool) -> &str { + match &self { + Self::Mocha => { + if js { + "yarn run mocha -t 1000000 tests/" + } else { + "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" + } + } + Self::Jest => { + if js { + "yarn run jest" + } else { + "yarn run jest --preset ts-jest" + } + } + Self::Rust => "cargo test", + } + } + + pub fn create_test_files( + &self, + project_name: &str, + js: bool, + solidity: bool, + program_id: &str, + ) -> Result<()> { + match self { + Self::Mocha => { + // Build the test suite. + fs::create_dir_all("tests")?; + + if js { + let mut test = File::create(format!("tests/{}.js", &project_name))?; + if solidity { + test.write_all(solidity_template::mocha(project_name).as_bytes())?; + } else { + test.write_all(mocha(project_name).as_bytes())?; + } + } else { + let mut mocha = File::create(format!("tests/{}.ts", &project_name))?; + if solidity { + mocha.write_all(solidity_template::ts_mocha(project_name).as_bytes())?; + } else { + mocha.write_all(ts_mocha(project_name).as_bytes())?; + } + } + } + Self::Jest => { + // Build the test suite. + fs::create_dir_all("tests")?; + + let mut test = File::create(format!("tests/{}.test.js", &project_name))?; + if solidity { + test.write_all(solidity_template::jest(project_name).as_bytes())?; + } else { + test.write_all(jest(project_name).as_bytes())?; + } + } + Self::Rust => { + // Do not initilize git repo + let exit = std::process::Command::new("cargo") + .arg("new") + .arg("--vcs") + .arg("none") + .arg("--lib") + .arg("tests") + .stderr(Stdio::inherit()) + .output() + .map_err(|e| anyhow::format_err!("{}", e.to_string()))?; + if !exit.status.success() { + eprintln!("'cargo new --lib tests' failed"); + std::process::exit(exit.status.code().unwrap_or(1)); + } + + let mut files = Vec::new(); + let tests_path = Path::new("tests"); + files.extend(vec![( + tests_path.join("Cargo.toml"), + tests_cargo_toml(project_name), + )]); + files.extend(create_program_template_rust_test( + project_name, + tests_path, + program_id, + )); + override_or_create_files(&files)?; + } + } + + Ok(()) + } +} + +pub fn tests_cargo_toml(name: &str) -> String { + format!( + r#"[package] +name = "tests" +version = "0.1.0" +description = "Created with Anchor" +edition = "2021" + +[dependencies] +anchor-client = "{0}" +{1} = {{ version = "0.1.0", path = "../programs/{1}" }} +"#, + VERSION, name, + ) +} + +/// Generate template for Rust unit-test +fn create_program_template_rust_test(name: &str, tests_path: &Path, program_id: &str) -> Files { + let src_path = tests_path.join("src"); + vec![ + ( + src_path.join("lib.rs"), + r#"#[cfg(test)] +mod test_initialize; +"# + .into(), + ), + ( + src_path.join("test_initialize.rs"), + format!( + r#"use std::str::FromStr; + +use anchor_client::{{ + solana_sdk::{{ + commitment_config::CommitmentConfig, pubkey::Pubkey, signature::read_keypair_file, + }}, + Client, Cluster, +}}; + +#[test] +fn test_initialize() {{ + let program_id = "{0}"; + let anchor_wallet = std::env::var("ANCHOR_WALLET").unwrap(); + let payer = read_keypair_file(&anchor_wallet).unwrap(); + + let client = Client::new_with_options(Cluster::Localnet, &payer, CommitmentConfig::confirmed()); + let program_id = Pubkey::from_str(program_id).unwrap(); + let program = client.program(program_id).unwrap(); + + let tx = program + .request() + .accounts({1}::accounts::Initialize {{}}) + .args({1}::instruction::Initialize {{}}) + .send() + .expect(""); + + println!("Your transaction signature {{}}", tx); +}} +"#, + program_id, + name.to_snake_case(), + ), + ), + ] +} diff --git a/client/Cargo.toml b/client/Cargo.toml index b92d7c641d..603c7ce1ee 100644 --- a/client/Cargo.toml +++ b/client/Cargo.toml @@ -1,8 +1,7 @@ [package] name = "anchor-client" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] -rust-version = "1.60" edition = "2021" license = "Apache-2.0" description = "An RPC client to interact with Anchor programs" @@ -14,16 +13,17 @@ rustdoc-args = ["--cfg", "docsrs"] [features] async = [] debug = [] +mock = [] [dependencies] -anchor-lang = { path = "../lang", version = "0.29.0" } +anchor-lang = { path = "../lang", version = "0.30.1" } anyhow = "1" futures = "0.3" regex = "1" serde = { version = "1", features = ["derive"] } -solana-account-decoder = ">=1.16, <1.18" -solana-client = ">=1.16, <1.18" -solana-sdk = ">=1.16, <1.18" +solana-account-decoder = "1.17.3" +solana-client = "1.17.3" +solana-sdk = "1.17.3" thiserror = "1" tokio = { version = "1", features = ["rt", "sync"] } url = "2" diff --git a/client/example/Cargo.toml b/client/example/Cargo.toml index 99c7649520..681d105e70 100644 --- a/client/example/Cargo.toml +++ b/client/example/Cargo.toml @@ -2,7 +2,6 @@ name = "example" version = "0.1.0" authors = ["Armani Ferrante "] -rust-version = "1.60" edition = "2021" [workspace] @@ -20,5 +19,5 @@ events = { path = "../../tests/events/programs/events", features = ["no-entrypoi anyhow = "1.0.32" clap = { version = "4.2.4", features = ["derive"] } shellexpand = "2.1.0" -solana-sdk = ">=1.16, <1.18" +solana-sdk = "1.17.3" tokio = { version = "1", features = ["full"] } diff --git a/client/example/run-test.sh b/client/example/run-test.sh index 13f3e47f8b..5aba1a4372 100755 --- a/client/example/run-test.sh +++ b/client/example/run-test.sh @@ -28,6 +28,17 @@ main() { local events_pid="2dhGsWUzy5YKUsjZdLHLmkNpUDAXkNa9MYWsPc4Ziqzy" local optional_pid="FNqz6pqLAwvMSds2FYjR4nKV3moVpPNtvkfGFrqLKrgG" + cd ../../tests/composite && anchor build && cd - + [ $? -ne 0 ] && exit 1 + cd ../../examples/tutorial/basic-2 && anchor build && cd - + [ $? -ne 0 ] && exit 1 + cd ../../examples/tutorial/basic-4 && anchor build && cd - + [ $? -ne 0 ] && exit 1 + cd ../../tests/events && anchor build && cd - + [ $? -ne 0 ] && exit 1 + cd ../../tests/optional && anchor build && cd - + [ $? -ne 0 ] && exit 1 + # # Bootup validator. # @@ -38,7 +49,10 @@ main() { --bpf-program $events_pid ../../tests/events/target/deploy/events.so \ --bpf-program $optional_pid ../../tests/optional/target/deploy/optional.so \ > test-validator.log & + test_validator_pid=$! + sleep 5 + check_solana_validator_running $test_validator_pid # # Run single threaded test. @@ -61,7 +75,10 @@ main() { --bpf-program $events_pid ../../tests/events/target/deploy/events.so \ --bpf-program $optional_pid ../../tests/optional/target/deploy/optional.so \ > test-validator.log & + test_validator_pid=$! + sleep 5 + check_solana_validator_running $test_validator_pid # # Run multi threaded test. @@ -85,7 +102,10 @@ main() { --bpf-program $events_pid ../../tests/events/target/deploy/events.so \ --bpf-program $optional_pid ../../tests/optional/target/deploy/optional.so \ > test-validator.log & + test_validator_pid=$! + sleep 5 + check_solana_validator_running $test_validator_pid # # Run async test. @@ -117,6 +137,15 @@ trap_add() { done } +check_solana_validator_running() { + local pid=$1 + exit_state=$(kill -0 "$pid" && echo 'living' || echo 'exited') + if [ "$exit_state" == 'exited' ]; then + echo "Cannot start test validator, see ./test-validator.log" + exit 1 + fi +} + declare -f -t trap_add trap_add 'cleanup' EXIT main diff --git a/client/example/src/nonblocking.rs b/client/example/src/nonblocking.rs index eeee5d4f18..4c7b0fd66b 100644 --- a/client/example/src/nonblocking.rs +++ b/client/example/src/nonblocking.rs @@ -26,7 +26,7 @@ use composite::instruction as composite_instruction; use composite::{DummyA, DummyB}; use optional::account::{DataAccount, DataPda}; use std::ops::Deref; -use std::rc::Rc; +use std::sync::Arc; use std::time::Duration; use tokio::sync::mpsc; use tokio::time::sleep; @@ -43,7 +43,7 @@ pub async fn main() -> Result<()> { ); // Client. - let payer = Rc::new(payer); + let payer = Arc::new(payer); let client = Client::new_with_options(url.clone(), payer.clone(), CommitmentConfig::processed()); @@ -51,6 +51,7 @@ pub async fn main() -> Result<()> { composite(&client, opts.composite_pid).await?; basic_2(&client, opts.basic_2_pid).await?; basic_4(&client, opts.basic_4_pid).await?; + test_tokio(client, opts.basic_2_pid).await?; // Can also use references, since they deref to a signer let payer: &Keypair = &payer; @@ -61,6 +62,42 @@ pub async fn main() -> Result<()> { Ok(()) } +pub async fn test_tokio(client: Client>, pid: Pubkey) -> Result<()> { + tokio::spawn(async move { + let program = client.program(pid).unwrap(); + + // `Create` parameters. + let counter = Arc::new(Keypair::new()); + let counter_pubkey = counter.pubkey(); + let authority = program.payer(); + + // Build and send a transaction. + program + .request() + .signer(counter) + .accounts(basic_2_accounts::Create { + counter: counter_pubkey, + user: authority, + system_program: system_program::ID, + }) + .args(basic_2_instruction::Create { authority }) + .send() + .await + .unwrap(); + + let counter_account: Counter = program.account(counter_pubkey).await.unwrap(); + + assert_eq!(counter_account.authority, authority); + assert_eq!(counter_account.count, 0); + }) + .await + .unwrap(); + + println!("Tokio success!"); + + Ok(()) +} + pub async fn composite + Clone>( client: &Client, pid: Pubkey, @@ -69,8 +106,8 @@ pub async fn composite + Clone>( let program = client.program(pid)?; // `Initialize` parameters. - let dummy_a = Keypair::new(); - let dummy_b = Keypair::new(); + let dummy_a = Arc::new(Keypair::new()); + let dummy_b = Arc::new(Keypair::new()); // Build and send a transaction. program @@ -79,7 +116,7 @@ pub async fn composite + Clone>( &program.payer(), &dummy_a.pubkey(), program - .async_rpc() + .rpc() .get_minimum_balance_for_rent_exemption(500) .await?, 500, @@ -89,14 +126,14 @@ pub async fn composite + Clone>( &program.payer(), &dummy_b.pubkey(), program - .async_rpc() + .rpc() .get_minimum_balance_for_rent_exemption(500) .await?, 500, &program.id(), )) - .signer(&dummy_a) - .signer(&dummy_b) + .signer(dummy_a.clone()) + .signer(dummy_b.clone()) .accounts(Initialize { dummy_a: dummy_a.pubkey(), dummy_b: dummy_b.pubkey(), @@ -147,13 +184,13 @@ pub async fn basic_2 + Clone>( let program = client.program(pid)?; // `Create` parameters. - let counter = Keypair::new(); + let counter = Arc::new(Keypair::new()); let authority = program.payer(); // Build and send a transaction. program .request() - .signer(&counter) + .signer(counter.clone()) .accounts(basic_2_accounts::Create { counter: counter.pubkey(), user: authority, @@ -253,13 +290,13 @@ pub async fn optional + Clone>( let program = client.program(pid)?; // `Initialize` parameters. - let data_account_keypair = Keypair::new(); + let data_account_keypair = Arc::new(Keypair::new()); let data_account_key = data_account_keypair.pubkey(); let data_pda_seeds = &[DataPda::PREFIX.as_ref(), data_account_key.as_ref()]; let data_pda_key = Pubkey::find_program_address(data_pda_seeds, &pid).0; - let required_keypair = Keypair::new(); + let required_keypair = Arc::new(Keypair::new()); let value: u64 = 10; // Build and send a transaction. @@ -270,14 +307,14 @@ pub async fn optional + Clone>( &program.payer(), &required_keypair.pubkey(), program - .async_rpc() + .rpc() .get_minimum_balance_for_rent_exemption(DataAccount::LEN) .await?, DataAccount::LEN as u64, &program.id(), )) - .signer(&data_account_keypair) - .signer(&required_keypair) + .signer(data_account_keypair.clone()) + .signer(required_keypair.clone()) .accounts(OptionalInitialize { payer: Some(program.payer()), required: required_keypair.pubkey(), diff --git a/client/src/blocking.rs b/client/src/blocking.rs index 492729d630..a0522d7ed0 100644 --- a/client/src/blocking.rs +++ b/client/src/blocking.rs @@ -3,7 +3,12 @@ use crate::{ RequestBuilder, }; use anchor_lang::{prelude::Pubkey, AccountDeserialize, Discriminator}; -use solana_client::{rpc_config::RpcSendTransactionConfig, rpc_filter::RpcFilterType}; +#[cfg(not(feature = "mock"))] +use solana_client::rpc_client::RpcClient; +use solana_client::{ + nonblocking::rpc_client::RpcClient as AsyncRpcClient, rpc_config::RpcSendTransactionConfig, + rpc_filter::RpcFilterType, +}; use solana_sdk::{ commitment_config::CommitmentConfig, signature::Signature, signer::Signer, transaction::Transaction, @@ -22,17 +27,55 @@ impl<'a> EventUnsubscriber<'a> { } impl + Clone> Program { - pub fn new(program_id: Pubkey, cfg: Config) -> Result { + pub fn new( + program_id: Pubkey, + cfg: Config, + #[cfg(feature = "mock")] rpc_client: AsyncRpcClient, + ) -> Result { let rt: tokio::runtime::Runtime = Builder::new_multi_thread().enable_all().build()?; + #[cfg(not(feature = "mock"))] + let rpc_client = { + let comm_config = cfg.options.unwrap_or_default(); + let cluster_url = cfg.cluster.url().to_string(); + AsyncRpcClient::new_with_commitment(cluster_url.clone(), comm_config) + }; + Ok(Self { program_id, cfg, sub_client: Arc::new(RwLock::new(None)), + internal_rpc_client: rpc_client, rt, }) } + // We disable the `rpc` method for `mock` feature because otherwise we'd either have to + // return a new `RpcClient` instance (which is different to the one used internally) + // or require the user to pass another one in for blocking (since we use the non-blocking one under the hood). + // The former of these would be confusing and the latter would be very annoying, especially since a user + // using the mock feature likely already has a `RpcClient` instance at hand anyway. + #[cfg(not(feature = "mock"))] + pub fn rpc(&self) -> RpcClient { + RpcClient::new_with_commitment( + self.cfg.cluster.url().to_string(), + self.cfg.options.unwrap_or_default(), + ) + } + + /// Returns a request builder. + pub fn request(&self) -> RequestBuilder<'_, C, Box> { + RequestBuilder::from( + self.program_id, + self.cfg.cluster.url(), + self.cfg.payer.clone(), + self.cfg.options, + #[cfg(not(feature = "async"))] + self.rt.handle(), + &self.internal_rpc_client, + ) + } + /// Returns the account at the given address. pub fn account(&self, address: Pubkey) -> Result { self.rt.block_on(self.account_internal(address)) @@ -70,13 +113,14 @@ impl + Clone> Program { } } -impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { +impl<'a, C: Deref + Clone> RequestBuilder<'a, C, Box> { pub fn from( program_id: Pubkey, cluster: &str, payer: C, options: Option, handle: &'a Handle, + rpc_client: &'a AsyncRpcClient, ) -> Self { Self { program_id, @@ -88,9 +132,17 @@ impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { instruction_data: None, signers: Vec::new(), handle, + internal_rpc_client: rpc_client, + _phantom: PhantomData, } } + #[must_use] + pub fn signer(mut self, signer: T) -> Self { + self.signers.push(Box::new(signer)); + self + } + pub fn signed_transaction(&self) -> Result { self.handle.block_on(self.signed_transaction_internal()) } diff --git a/client/src/cluster.rs b/client/src/cluster.rs index 1ef9a7d2e7..0407d66aea 100644 --- a/client/src/cluster.rs +++ b/client/src/cluster.rs @@ -3,22 +3,17 @@ use serde::{Deserialize, Serialize}; use std::str::FromStr; use url::Url; -#[derive(Serialize, Deserialize, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +#[derive(Serialize, Deserialize, Clone, Debug, Default, Eq, PartialEq, Ord, PartialOrd)] pub enum Cluster { Testnet, Mainnet, Devnet, + #[default] Localnet, Debug, Custom(String, String), } -impl Default for Cluster { - fn default() -> Self { - Cluster::Localnet - } -} - impl FromStr for Cluster { type Err = anyhow::Error; fn from_str(s: &str) -> Result { diff --git a/client/src/lib.rs b/client/src/lib.rs index 50ede1fdeb..84ad8bb747 100644 --- a/client/src/lib.rs +++ b/client/src/lib.rs @@ -50,24 +50,23 @@ //! //! More examples can be found in [here]. //! -//! [here]: https://github.com/coral-xyz/anchor/tree/v0.29.0/client/example/src +//! [here]: https://github.com/coral-xyz/anchor/tree/v0.30.1/client/example/src //! //! # Features //! //! The client is blocking by default. To enable asynchronous client, add `async` feature: //! //! ```toml -//! anchor-client = { version = "0.29.0 ", features = ["async"] } +//! anchor-client = { version = "0.30.1 ", features = ["async"] } //! ```` -use anchor_lang::solana_program::hash::Hash; -use anchor_lang::solana_program::instruction::{AccountMeta, Instruction}; use anchor_lang::solana_program::program_error::ProgramError; use anchor_lang::solana_program::pubkey::Pubkey; use anchor_lang::{AccountDeserialize, Discriminator, InstructionData, ToAccountMetas}; use futures::{Future, StreamExt}; use regex::Regex; use solana_account_decoder::UiAccountEncoding; +use solana_client::nonblocking::rpc_client::RpcClient as AsyncRpcClient; use solana_client::rpc_config::{ RpcAccountInfoConfig, RpcProgramAccountsConfig, RpcSendTransactionConfig, RpcTransactionLogsConfig, RpcTransactionLogsFilter, @@ -75,15 +74,13 @@ use solana_client::rpc_config::{ use solana_client::rpc_filter::{Memcmp, RpcFilterType}; use solana_client::{ client_error::ClientError as SolanaClientError, - nonblocking::{ - pubsub_client::{PubsubClient, PubsubClientError}, - rpc_client::RpcClient as AsyncRpcClient, - }, - rpc_client::RpcClient, + nonblocking::pubsub_client::{PubsubClient, PubsubClientError}, rpc_response::{Response as RpcResponse, RpcLogsResponse}, }; use solana_sdk::account::Account; use solana_sdk::commitment_config::CommitmentConfig; +use solana_sdk::hash::Hash; +use solana_sdk::instruction::{AccountMeta, Instruction}; use solana_sdk::signature::{Signature, Signer}; use solana_sdk::transaction::Transaction; use std::iter::Map; @@ -104,6 +101,8 @@ use tokio::{ pub use anchor_lang; pub use cluster::Cluster; +#[cfg(feature = "async")] +pub use nonblocking::ThreadSafeSigner; pub use solana_client; pub use solana_sdk; @@ -146,14 +145,23 @@ impl> Client { } } - pub fn program(&self, program_id: Pubkey) -> Result, ClientError> { + pub fn program( + &self, + program_id: Pubkey, + #[cfg(feature = "mock")] rpc_client: AsyncRpcClient, + ) -> Result, ClientError> { let cfg = Config { cluster: self.cfg.cluster.clone(), options: self.cfg.options, payer: self.cfg.payer.clone(), }; - Program::new(program_id, cfg) + Program::new( + program_id, + cfg, + #[cfg(feature = "mock")] + rpc_client, + ) } } @@ -220,6 +228,7 @@ pub struct Program { sub_client: Arc>>, #[cfg(not(feature = "async"))] rt: tokio::runtime::Runtime, + internal_rpc_client: AsyncRpcClient, } impl + Clone> Program { @@ -227,45 +236,21 @@ impl + Clone> Program { self.cfg.payer.pubkey() } - /// Returns a request builder. - pub fn request(&self) -> RequestBuilder { - RequestBuilder::from( - self.program_id, - self.cfg.cluster.url(), - self.cfg.payer.clone(), - self.cfg.options, - #[cfg(not(feature = "async"))] - self.rt.handle(), - ) - } - pub fn id(&self) -> Pubkey { self.program_id } - pub fn rpc(&self) -> RpcClient { - RpcClient::new_with_commitment( - self.cfg.cluster.url().to_string(), - self.cfg.options.unwrap_or_default(), - ) - } - - pub fn async_rpc(&self) -> AsyncRpcClient { - AsyncRpcClient::new_with_commitment( - self.cfg.cluster.url().to_string(), - self.cfg.options.unwrap_or_default(), - ) + #[cfg(feature = "mock")] + pub fn internal_rpc(&self) -> &AsyncRpcClient { + &self.internal_rpc_client } async fn account_internal( &self, address: Pubkey, ) -> Result { - let rpc_client = AsyncRpcClient::new_with_commitment( - self.cfg.cluster.url().to_string(), - self.cfg.options.unwrap_or_default(), - ); - let account = rpc_client + let account = self + .internal_rpc_client .get_account_with_commitment(&address, CommitmentConfig::processed()) .await? .value @@ -279,7 +264,7 @@ impl + Clone> Program { filters: Vec, ) -> Result, ClientError> { let account_type_filter = - RpcFilterType::Memcmp(Memcmp::new_base58_encoded(0, &T::discriminator())); + RpcFilterType::Memcmp(Memcmp::new_base58_encoded(0, T::DISCRIMINATOR)); let config = RpcProgramAccountsConfig { filters: Some([vec![account_type_filter], filters].concat()), account_config: RpcAccountInfoConfig { @@ -288,9 +273,10 @@ impl + Clone> Program { }, ..RpcProgramAccountsConfig::default() }; + Ok(ProgramAccountsIterator { inner: self - .async_rpc() + .internal_rpc_client .get_program_accounts_with_config(&self.id(), config) .await? .into_iter() @@ -392,8 +378,8 @@ pub fn handle_program_log borsh_bytes, + let log_bytes = match STANDARD.decode(log) { + Ok(log_bytes) => log_bytes, _ => { #[cfg(feature = "debug")] println!("Could not base64 decode log: {}", log); @@ -401,19 +387,14 @@ pub fn handle_program_log (Option, bool) { if log.starts_with(&format!("Program {this_program_str} log:")) { (Some(this_program_str.to_string()), false) - } else if log.contains("invoke") { + + // `Invoke [1]` instructions are pushed to the stack in `parse_logs_response`, + // so this ensures we only push CPIs to the stack at this stage + } else if log.contains("invoke") && !log.ends_with("[1]") { (Some("cpi".to_string()), false) // Any string will do. } else { let re = Regex::new(r"^Program (.*) success*$").unwrap(); @@ -500,23 +484,35 @@ pub enum ClientError { IOError(#[from] std::io::Error), } +pub trait AsSigner { + fn as_signer(&self) -> &dyn Signer; +} + +impl<'a> AsSigner for Box { + fn as_signer(&self) -> &dyn Signer { + self.as_ref() + } +} + /// `RequestBuilder` provides a builder interface to create and send /// transactions to a cluster. -pub struct RequestBuilder<'a, C> { +pub struct RequestBuilder<'a, C, S: 'a> { cluster: String, program_id: Pubkey, accounts: Vec, options: CommitmentConfig, instructions: Vec, payer: C, - // Serialized instruction data for the target RPC. instruction_data: Option>, - signers: Vec<&'a dyn Signer>, + signers: Vec, #[cfg(not(feature = "async"))] handle: &'a Handle, + internal_rpc_client: &'a AsyncRpcClient, + _phantom: PhantomData<&'a ()>, } -impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { +// Shared implementation for all RequestBuilders +impl<'a, C: Deref + Clone, S: AsSigner> RequestBuilder<'a, C, S> { #[must_use] pub fn payer(mut self, payer: C) -> Self { self.payer = payer; @@ -541,6 +537,36 @@ impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { self } + /// Set the accounts to pass to the instruction. + /// + /// `accounts` argument can be: + /// + /// - Any type that implements [`ToAccountMetas`] trait + /// - A vector of [`AccountMeta`]s (for remaining accounts) + /// + /// Note that the given accounts are appended to the previous list of accounts instead of + /// overriding the existing ones (if any). + /// + /// # Example + /// + /// ```ignore + /// program + /// .request() + /// // Regular accounts + /// .accounts(accounts::Initialize { + /// my_account: my_account_kp.pubkey(), + /// payer: program.payer(), + /// system_program: system_program::ID, + /// }) + /// // Remaining accounts + /// .accounts(vec![AccountMeta { + /// pubkey: remaining, + /// is_signer: true, + /// is_writable: true, + /// }]) + /// .args(instruction::Initialize { field: 42 }) + /// .send()?; + /// ``` #[must_use] pub fn accounts(mut self, accounts: impl ToAccountMetas) -> Self { let mut metas = accounts.to_account_metas(None); @@ -560,12 +586,6 @@ impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { self } - #[must_use] - pub fn signer(mut self, signer: &'a dyn Signer) -> Self { - self.signers.push(signer); - self - } - pub fn instructions(&self) -> Result, ClientError> { let mut instructions = self.instructions.clone(); if let Some(ix_data) = &self.instruction_data { @@ -584,13 +604,14 @@ impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { latest_hash: Hash, ) -> Result { let instructions = self.instructions()?; - let mut signers = self.signers.clone(); - signers.push(&*self.payer); + let signers: Vec<&dyn Signer> = self.signers.iter().map(|s| s.as_signer()).collect(); + let mut all_signers = signers; + all_signers.push(&*self.payer); let tx = Transaction::new_signed_with_payer( &instructions, Some(&self.payer.pubkey()), - &signers, + &all_signers, latest_hash, ); @@ -604,21 +625,17 @@ impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { } async fn signed_transaction_internal(&self) -> Result { - let latest_hash = - AsyncRpcClient::new_with_commitment(self.cluster.to_owned(), self.options) - .get_latest_blockhash() - .await?; - let tx = self.signed_transaction_with_blockhash(latest_hash)?; + let latest_hash = self.internal_rpc_client.get_latest_blockhash().await?; + let tx = self.signed_transaction_with_blockhash(latest_hash)?; Ok(tx) } async fn send_internal(&self) -> Result { - let rpc_client = AsyncRpcClient::new_with_commitment(self.cluster.to_owned(), self.options); - let latest_hash = rpc_client.get_latest_blockhash().await?; + let latest_hash = self.internal_rpc_client.get_latest_blockhash().await?; let tx = self.signed_transaction_with_blockhash(latest_hash)?; - rpc_client + self.internal_rpc_client .send_and_confirm_transaction(&tx) .await .map_err(Into::into) @@ -628,14 +645,13 @@ impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { &self, config: RpcSendTransactionConfig, ) -> Result { - let rpc_client = AsyncRpcClient::new_with_commitment(self.cluster.to_owned(), self.options); - let latest_hash = rpc_client.get_latest_blockhash().await?; + let latest_hash = self.internal_rpc_client.get_latest_blockhash().await?; let tx = self.signed_transaction_with_blockhash(latest_hash)?; - rpc_client + self.internal_rpc_client .send_and_confirm_transaction_with_spinner_and_config( &tx, - rpc_client.commitment(), + self.internal_rpc_client.commitment(), config, ) .await @@ -651,7 +667,10 @@ fn parse_logs_response( let mut events: Vec = Vec::new(); if !logs.is_empty() { if let Ok(mut execution) = Execution::new(&mut logs) { - for l in logs { + // Create a new peekable iterator so that we can peek at the next log whilst iterating + let mut logs_iter = logs.iter().peekable(); + + while let Some(l) = logs_iter.next() { // Parse the log. let (event, new_program, did_pop) = { if program_id_str == execution.program() { @@ -675,6 +694,25 @@ fn parse_logs_response( // Program returned. if did_pop { execution.pop(); + + // If the current iteration popped then it means there was a + //`Program x success` log. If the next log in the iteration is + // of depth [1] then we're not within a CPI and this is a new instruction. + // + // We need to ensure that the `Execution` instance is updated with + // the next program ID, or else `execution.program()` will cause + // a panic during the next iteration. + if let Some(&next_log) = logs_iter.peek() { + if next_log.ends_with("invoke [1]") { + let re = Regex::new(r"^Program (.*) invoke.*$").unwrap(); + let next_instruction = + re.captures(next_log).unwrap().get(1).unwrap().as_str(); + // Within this if block, there will always be a regex match. + // Therefore it's safe to unwrap and the captured program ID + // at index 1 can also be safely unwrapped. + execution.push(next_instruction.to_string()); + } + }; } } } @@ -684,6 +722,15 @@ fn parse_logs_response( #[cfg(test)] mod tests { + use solana_client::rpc_response::RpcResponseContext; + + // Creating a mock struct that implements `anchor_lang::events` + // for type inference in `test_logs` + use anchor_lang::prelude::*; + #[derive(Debug, Clone, Copy)] + #[event] + pub struct MockEvent {} + use super::*; #[test] fn new_execution() { @@ -711,4 +758,106 @@ mod tests { assert_eq!(program, None); assert!(!did_pop); } + + #[test] + fn test_parse_logs_response() -> Result<()> { + // Mock logs received within an `RpcResponse`. These are based on a Jupiter transaction. + let logs = vec![ + "Program VeryCoolProgram invoke [1]", // Outer instruction #1 starts + "Program log: Instruction: VeryCoolEvent", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", + "Program log: Instruction: Transfer", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 664387 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program VeryCoolProgram consumed 42417 of 700000 compute units", + "Program VeryCoolProgram success", // Outer instruction #1 ends + "Program EvenCoolerProgram invoke [1]", // Outer instruction #2 starts + "Program log: Instruction: EvenCoolerEvent", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", + "Program log: Instruction: TransferChecked", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6200 of 630919 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt invoke [2]", + "Program log: Instruction: Swap", + "Program log: INVARIANT: SWAP", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: Transfer", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 539321 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: Transfer", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 531933 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt consumed 84670 of 610768 compute units", + "Program HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt success", + "Program EvenCoolerProgram invoke [2]", + "Program EvenCoolerProgram consumed 2021 of 523272 compute units", + "Program EvenCoolerProgram success", + "Program HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt invoke [2]", + "Program log: Instruction: Swap", + "Program log: INVARIANT: SWAP", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: Transfer", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 418618 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: Transfer", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 411230 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt consumed 102212 of 507607 compute units", + "Program HyaB3W9q6XdA5xwpU4XnSZV94htfmbmqJXZcEbRaJutt success", + "Program EvenCoolerProgram invoke [2]", + "Program EvenCoolerProgram consumed 2021 of 402569 compute units", + "Program EvenCoolerProgram success", + "Program 9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP invoke [2]", + "Program log: Instruction: Swap", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: Transfer", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4736 of 371140 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: MintTo", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4492 of 341800 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [3]", + "Program log: Instruction: Transfer", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 4645 of 334370 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program 9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP consumed 57610 of 386812 compute units", + "Program 9W959DqEETiGZocYWCQPaJ6sBmUzgfxXfqGeTEdp3aQP success", + "Program EvenCoolerProgram invoke [2]", + "Program EvenCoolerProgram consumed 2021 of 326438 compute units", + "Program EvenCoolerProgram success", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA invoke [2]", + "Program log: Instruction: TransferChecked", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA consumed 6173 of 319725 compute units", + "Program TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA success", + "Program EvenCoolerProgram consumed 345969 of 657583 compute units", + "Program EvenCoolerProgram success", // Outer instruction #2 ends + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success", + "Program ComputeBudget111111111111111111111111111111 invoke [1]", + "Program ComputeBudget111111111111111111111111111111 success"]; + + // Converting to Vec as expected in `RpcLogsResponse` + let logs: Vec = logs.iter().map(|&l| l.to_string()).collect(); + + let program_id_str = "VeryCoolProgram"; + + // No events returned here. Just ensuring that the function doesn't panic + // due an incorrectly emptied stack. + let _: Vec = parse_logs_response( + RpcResponse { + context: RpcResponseContext::new(0), + value: RpcLogsResponse { + signature: "".to_string(), + err: None, + logs: logs.to_vec(), + }, + }, + program_id_str, + ); + + Ok(()) + } } diff --git a/client/src/nonblocking.rs b/client/src/nonblocking.rs index 93f06c114b..317bc0775a 100644 --- a/client/src/nonblocking.rs +++ b/client/src/nonblocking.rs @@ -1,8 +1,9 @@ use crate::{ - ClientError, Config, EventContext, EventUnsubscriber, Program, ProgramAccountsIterator, - RequestBuilder, + AsSigner, ClientError, Config, EventContext, EventUnsubscriber, Program, + ProgramAccountsIterator, RequestBuilder, }; use anchor_lang::{prelude::Pubkey, AccountDeserialize, Discriminator}; +use solana_client::nonblocking::rpc_client::RpcClient as AsyncRpcClient; use solana_client::{rpc_config::RpcSendTransactionConfig, rpc_filter::RpcFilterType}; use solana_sdk::{ commitment_config::CommitmentConfig, signature::Signature, signer::Signer, @@ -18,15 +19,67 @@ impl<'a> EventUnsubscriber<'a> { } } +pub trait ThreadSafeSigner: Signer + Send + Sync + 'static { + fn to_signer(&self) -> &dyn Signer; +} + +impl ThreadSafeSigner for T { + fn to_signer(&self) -> &dyn Signer { + self + } +} + +impl AsSigner for Arc { + fn as_signer(&self) -> &dyn Signer { + self.to_signer() + } +} + impl + Clone> Program { - pub fn new(program_id: Pubkey, cfg: Config) -> Result { + pub fn new( + program_id: Pubkey, + cfg: Config, + #[cfg(feature = "mock")] rpc_client: AsyncRpcClient, + ) -> Result { + #[cfg(not(feature = "mock"))] + let rpc_client = { + let comm_config = cfg.options.unwrap_or_default(); + let cluster_url = cfg.cluster.url().to_string(); + AsyncRpcClient::new_with_commitment(cluster_url.clone(), comm_config) + }; + Ok(Self { program_id, cfg, sub_client: Arc::new(RwLock::new(None)), + internal_rpc_client: rpc_client, }) } + // We disable the `rpc` method for `mock` feature because otherwise we'd either have to + // return a new `RpcClient` instance (which is different to the one used internally) + // or require the user to pass another one in for blocking (since we use the non-blocking one under the hood). + // The former of these would be confusing and the latter would be very annoying, especially since a user + // using the mock feature likely already has a `RpcClient` instance at hand anyway. + #[cfg(not(feature = "mock"))] + pub fn rpc(&self) -> AsyncRpcClient { + AsyncRpcClient::new_with_commitment( + self.cfg.cluster.url().to_string(), + self.cfg.options.unwrap_or_default(), + ) + } + + /// Returns a threadsafe request builder + pub fn request(&self) -> RequestBuilder<'_, C, Arc> { + RequestBuilder::from( + self.program_id, + self.cfg.cluster.url(), + self.cfg.payer.clone(), + self.cfg.options, + &self.internal_rpc_client, + ) + } + /// Returns the account at the given address. pub async fn account(&self, address: Pubkey) -> Result { self.account_internal(address).await @@ -66,12 +119,13 @@ impl + Clone> Program { } } -impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { +impl<'a, C: Deref + Clone> RequestBuilder<'a, C, Arc> { pub fn from( program_id: Pubkey, cluster: &str, payer: C, options: Option, + rpc_client: &'a AsyncRpcClient, ) -> Self { Self { program_id, @@ -82,9 +136,17 @@ impl<'a, C: Deref + Clone> RequestBuilder<'a, C> { instructions: Vec::new(), instruction_data: None, signers: Vec::new(), + internal_rpc_client: rpc_client, + _phantom: PhantomData, } } + #[must_use] + pub fn signer(mut self, signer: T) -> Self { + self.signers.push(Arc::new(signer)); + self + } + pub async fn signed_transaction(&self) -> Result { self.signed_transaction_internal().await } diff --git a/docker/Makefile b/docker/Makefile index 03b713f528..33e564e142 100644 --- a/docker/Makefile +++ b/docker/Makefile @@ -2,11 +2,11 @@ WORKDIR=$(PWD) # # Anchor version. # -ANCHOR_CLI=v0.29.0 +ANCHOR_CLI=v0.30.1 # # Solana toolchain. # -SOLANA_CLI=v1.17.0 +SOLANA_CLI=v1.18.17 # # Build version should match the Anchor cli version. # diff --git a/docs/programs/tic-tac-toe/.mocharc.json b/docs/programs/tic-tac-toe/.mocharc.json new file mode 100644 index 0000000000..db8a99e1dc --- /dev/null +++ b/docs/programs/tic-tac-toe/.mocharc.json @@ -0,0 +1,8 @@ +{ + "node-option": ["import=tsx"], + "extensions": ["ts"], + "timeout": 1000000, + "spec": [ + "tests/**/*.ts" + ] +} \ No newline at end of file diff --git a/docs/programs/tic-tac-toe/Anchor.toml b/docs/programs/tic-tac-toe/Anchor.toml index 0fcca0714f..2eed945b6b 100644 --- a/docs/programs/tic-tac-toe/Anchor.toml +++ b/docs/programs/tic-tac-toe/Anchor.toml @@ -6,4 +6,4 @@ cluster = "localnet" wallet = "~/.config/solana/id.json" [scripts] -test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts" +test = "yarn run mocha" diff --git a/docs/programs/tic-tac-toe/Cargo.lock b/docs/programs/tic-tac-toe/Cargo.lock index e2a9cff20e..d9b64486c2 100644 --- a/docs/programs/tic-tac-toe/Cargo.lock +++ b/docs/programs/tic-tac-toe/Cargo.lock @@ -4,208 +4,357 @@ version = 3 [[package]] name = "ahash" -version = "0.7.6" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.5", + "getrandom 0.2.15", "once_cell", "version_check", ] +[[package]] +name = "ahash" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011" +dependencies = [ + "cfg-if", + "once_cell", + "version_check", + "zerocopy", +] + [[package]] name = "aho-corasick" -version = "0.7.18" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1e37cfd5e7657ada45f742d6e99ca5788580b5c529dc78faf11ece6dc702656f" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "anchor-attribute-access-control" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf7d535e1381be3de2c0716c0a1c1e32ad9df1042cddcf7bc18d743569e53319" +checksum = "47fe28365b33e8334dd70ae2f34a43892363012fe239cf37d2ee91693575b1f8" dependencies = [ "anchor-syn", - "anyhow", "proc-macro2", "quote", - "regex", - "syn", + "syn 1.0.109", ] [[package]] name = "anchor-attribute-account" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3bcd731f21048a032be27c7791701120e44f3f6371358fc4261a7f716283d29" +checksum = "3c288d496168268d198d9b53ee9f4f9d260a55ba4df9877ea1d4486ad6109e0f" dependencies = [ "anchor-syn", - "anyhow", - "bs58 0.4.0", + "bs58 0.5.1", "proc-macro2", "quote", - "rustversion", - "syn", + "syn 1.0.109", ] [[package]] name = "anchor-attribute-constant" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1be64a48e395fe00b8217287f226078be2cf32dae42fdf8a885b997945c3d28" +checksum = "49b77b6948d0eeaaa129ce79eea5bbbb9937375a9241d909ca8fb9e006bb6e90" dependencies = [ "anchor-syn", - "proc-macro2", - "syn", + "quote", + "syn 1.0.109", ] [[package]] name = "anchor-attribute-error" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38ea6713d1938c0da03656ff8a693b17dc0396da66d1ba320557f07e86eca0d4" +checksum = "4d20bb569c5a557c86101b944721d865e1fd0a4c67c381d31a44a84f07f84828" dependencies = [ "anchor-syn", - "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "anchor-attribute-event" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d401f11efb3644285685f8339829a9786d43ed7490bb1699f33c478d04d5a582" +checksum = "4cebd8d0671a3a9dc3160c48598d652c34c77de6be4d44345b8b514323284d57" dependencies = [ "anchor-syn", - "anyhow", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "anchor-attribute-interface" -version = "0.29.0" +name = "anchor-attribute-program" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6700a6f5c888a9c33fe8afc0c64fd8575fa28d05446037306d0f96102ae4480" +checksum = "efb2a5eb0860e661ab31aff7bb5e0288357b176380e985bade4ccb395981b42d" dependencies = [ + "anchor-lang-idl", "anchor-syn", "anyhow", + "bs58 0.5.1", "heck", "proc-macro2", "quote", - "syn", + "serde_json", + "syn 1.0.109", ] [[package]] -name = "anchor-attribute-program" -version = "0.29.0" +name = "anchor-derive-accounts" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ad769993b5266714e8939e47fbdede90e5c030333c7522d99a4d4748cf26712" +checksum = "04368b5abef4266250ca8d1d12f4dff860242681e4ec22b885dcfe354fd35aa1" dependencies = [ "anchor-syn", - "anyhow", - "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "anchor-attribute-state" -version = "0.29.0" +name = "anchor-derive-serde" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e677fae4a016a554acdd0e3b7f178d3acafaa7e7ffac6b8690cf4e171f1c116" +checksum = "e0bb0e0911ad4a70cab880cdd6287fe1e880a1a9d8e4e6defa8e9044b9796a6c" dependencies = [ "anchor-syn", - "anyhow", + "borsh-derive-internal 0.10.3", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "anchor-derive-accounts" -version = "0.29.0" +name = "anchor-derive-space" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "340beef6809d1c3fcc7ae219153d981e95a8a277ff31985bd7050e32645dc9a8" +checksum = "5ef415ff156dc82e9ecb943189b0cb241b3a6bfc26a180234dc21bd3ef3ce0cb" dependencies = [ - "anchor-syn", - "anyhow", "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] name = "anchor-lang" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "662ceafe667448ee4199a4be2ee83b6bb76da28566eee5cea05f96ab38255af8" +checksum = "6620c9486d9d36a4389cab5e37dc34a42ed0bfaa62e6a75a2999ce98f8f2e373" dependencies = [ "anchor-attribute-access-control", "anchor-attribute-account", "anchor-attribute-constant", "anchor-attribute-error", "anchor-attribute-event", - "anchor-attribute-interface", "anchor-attribute-program", - "anchor-attribute-state", "anchor-derive-accounts", + "anchor-derive-serde", + "anchor-derive-space", + "anchor-lang-idl", "arrayref", - "base64 0.13.0", + "base64 0.21.7", "bincode", - "borsh", + "borsh 0.10.3", "bytemuck", + "getrandom 0.2.15", "solana-program", "thiserror", ] +[[package]] +name = "anchor-lang-idl" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31cf97b4e6f7d6144a05e435660fcf757dbc3446d38d0e2b851d11ed13625bba" +dependencies = [ + "anchor-lang-idl-spec", + "anyhow", + "heck", + "regex", + "serde", + "serde_json", + "sha2 0.10.8", +] + +[[package]] +name = "anchor-lang-idl-spec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bdf143115440fe621bdac3a29a1f7472e09f6cd82b2aa569429a0c13f103838" +dependencies = [ + "anyhow", + "serde", +] + [[package]] name = "anchor-syn" -version = "0.29.0" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0418bcb5daac3b8cb1b60d8fdb1d468ca36f5509f31fb51179326fae1028fdcc" +checksum = "f99daacb53b55cfd37ce14d6c9905929721137fd4c67bbab44a19802aecb622f" dependencies = [ "anyhow", - "bs58 0.3.1", + "bs58 0.5.1", + "cargo_toml", "heck", "proc-macro2", - "proc-macro2-diagnostics", "quote", "serde", "serde_json", - "sha2 0.9.9", - "syn", + "sha2 0.10.8", + "syn 1.0.109", "thiserror", ] [[package]] name = "anyhow" -version = "1.0.56" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" + +[[package]] +name = "ark-bn254" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +dependencies = [ + "ark-ec", + "ark-ff", + "ark-std", +] + +[[package]] +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff", + "ark-poly", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", + "itertools", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm", + "ark-ff-macros", + "ark-serialize", + "ark-std", + "derivative", + "digest 0.10.7", + "itertools", + "num-bigint", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff", + "ark-serialize", + "ark-std", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-serialize" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +dependencies = [ + "ark-serialize-derive", + "ark-std", + "digest 0.10.7", + "num-bigint", +] + +[[package]] +name = "ark-serialize-derive" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-std" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185" +dependencies = [ + "num-traits", + "rand 0.8.5", +] [[package]] name = "arrayref" -version = "0.3.6" +version = "0.3.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4c527152e37cf757a3f78aae5a06fbeefdb07ccc535c980a3208ee3060dd544" +checksum = "9d151e35f61089500b617991b791fc8bfd237ae50cd5950803758a179b41e67a" [[package]] name = "arrayvec" -version = "0.7.2" +version = "0.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6" +checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" [[package]] name = "autocfg" -version = "1.1.0" +version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0" [[package]] name = "base64" @@ -215,9 +364,9 @@ checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff" [[package]] name = "base64" -version = "0.13.0" +version = "0.21.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "904dfeac50f3cdaba28fc6f57fdcddb75f49ed61346676a78c4ffe55877802fd" +checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "bincode" @@ -230,9 +379,12 @@ dependencies = [ [[package]] name = "bitflags" -version = "1.3.2" +version = "2.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" +dependencies = [ + "serde", +] [[package]] name = "bitmaps" @@ -245,16 +397,16 @@ dependencies = [ [[package]] name = "blake3" -version = "1.3.1" +version = "1.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a08e53fc5a564bb15bfe6fae56bd71522205f1f91893f9c0116edad6496c183f" +checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] @@ -268,9 +420,9 @@ dependencies = [ [[package]] name = "block-buffer" -version = "0.10.2" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf7fe51849ea569fd452f37822f606a5cabb684dc918707a0193fd4664ff324" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" dependencies = [ "generic-array", ] @@ -281,8 +433,28 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" dependencies = [ - "borsh-derive", - "hashbrown", + "borsh-derive 0.9.3", + "hashbrown 0.11.2", +] + +[[package]] +name = "borsh" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +dependencies = [ + "borsh-derive 0.10.3", + "hashbrown 0.13.2", +] + +[[package]] +name = "borsh" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed" +dependencies = [ + "borsh-derive 1.5.1", + "cfg_aliases", ] [[package]] @@ -291,11 +463,38 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" dependencies = [ - "borsh-derive-internal", - "borsh-schema-derive-internal", - "proc-macro-crate", + "borsh-derive-internal 0.9.3", + "borsh-schema-derive-internal 0.9.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +dependencies = [ + "borsh-derive-internal 0.10.3", + "borsh-schema-derive-internal 0.10.3", + "proc-macro-crate 0.1.5", + "proc-macro2", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b" +dependencies = [ + "once_cell", + "proc-macro-crate 3.1.0", "proc-macro2", - "syn", + "quote", + "syn 2.0.72", + "syn_derive", ] [[package]] @@ -306,7 +505,18 @@ checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", +] + +[[package]] +name = "borsh-derive-internal" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -317,14 +527,19 @@ checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "bs58" -version = "0.3.1" +name = "borsh-schema-derive-internal" +version = "0.10.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "476e9cd489f9e121e02ffa6014a8ef220ecb15c05ed23fc34cca13925dc283fb" +checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] [[package]] name = "bs58" @@ -332,11 +547,20 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3" +[[package]] +name = "bs58" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4" +dependencies = [ + "tinyvec", +] + [[package]] name = "bumpalo" -version = "3.12.0" +version = "3.16.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d261e256854913907f67ed06efbc3338dfe6179796deefc1ff763fc1aee5535" +checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" [[package]] name = "bv" @@ -350,35 +574,49 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.8.0" +version = "1.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e851ca7c24871e7336801608a4797d7376545b6928a10d32d75685687141ead" +checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.0.1" +version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e215f8c2f9f79cb53c8335e687ffd07d5bfcb6fe5fc80723762d0be46e7cc54" +checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.72", ] [[package]] name = "byteorder" -version = "1.4.3" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cargo_toml" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be" +dependencies = [ + "serde", + "toml 0.8.15", +] [[package]] name = "cc" -version = "1.0.73" +version = "1.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" +checksum = "2aba8f4e9906c7ce3c73463f62a7f0c65183ada1a2d47e397cc8810827f9694f" +dependencies = [ + "jobserver", + "libc", +] [[package]] name = "cfg-if" @@ -386,6 +624,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + [[package]] name = "console_error_panic_hook" version = "0.1.7" @@ -398,9 +642,9 @@ dependencies = [ [[package]] name = "console_log" -version = "0.2.0" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "501a375961cef1a0d44767200e66e4a559283097e91d0730b1d75dfb2f8a1494" +checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f" dependencies = [ "log", "web-sys", @@ -408,61 +652,43 @@ dependencies = [ [[package]] name = "constant_time_eq" -version = "0.1.5" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "245097e9a4535ee1e3e3931fcfcd55a796a44c643e8596ff6566d68f09b87bbc" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" [[package]] name = "cpufeatures" -version = "0.2.2" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" +checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" dependencies = [ "libc", ] -[[package]] -name = "crossbeam-channel" -version = "0.5.7" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf2b3e8478797446514c91ef04bafcb59faba183e621ad488df88983cc14128c" -dependencies = [ - "cfg-if", - "crossbeam-utils", -] - [[package]] name = "crossbeam-deque" -version = "0.8.3" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce6fd6f855243022dcecf8702fef0c297d4338e226845fe067f6341ad9fa0cef" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" dependencies = [ - "cfg-if", "crossbeam-epoch", "crossbeam-utils", ] [[package]] name = "crossbeam-epoch" -version = "0.9.14" +version = "0.9.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46bd5f3f85273295a9d14aedfb86f6aadbff6d8f5295c4a9edb08e819dcf5695" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" dependencies = [ - "autocfg", - "cfg-if", "crossbeam-utils", - "memoffset", - "scopeguard", ] [[package]] name = "crossbeam-utils" -version = "0.8.15" +version = "0.8.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c063cd8cc95f5c377ed0d4b49a4b21f632396ff690e8470c29b3359b346984b" -dependencies = [ - "cfg-if", -] +checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" [[package]] name = "crunchy" @@ -472,9 +698,9 @@ checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" [[package]] name = "crypto-common" -version = "0.1.3" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" dependencies = [ "generic-array", "typenum", @@ -499,10 +725,22 @@ dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", + "serde", "subtle", "zeroize", ] +[[package]] +name = "derivative" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b" +dependencies = [ + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "digest" version = "0.9.0" @@ -514,20 +752,26 @@ dependencies = [ [[package]] name = "digest" -version = "0.10.6" +version = "0.10.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8168378f4e5023e7218c89c891c0fd8ecdb5e5e4f18cb78f38cf245dd021e76f" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ - "block-buffer 0.10.2", + "block-buffer 0.10.4", "crypto-common", "subtle", ] [[package]] name = "either" -version = "1.6.1" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60b1af1c220855b6ceac025d3f6ecdd2b7c4894bfe9cd9bda4fbb4bc7c0d4cf0" + +[[package]] +name = "equivalent" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" [[package]] name = "feature-probe" @@ -537,9 +781,9 @@ checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" [[package]] name = "generic-array" -version = "0.14.5" +version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd48d33ec7f05fbfa152300fdad764757cbded343c1aa1cff2fbaf4134851803" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "serde", "typenum", @@ -561,13 +805,15 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" dependencies = [ "cfg-if", + "js-sys", "libc", - "wasi 0.10.2+wasi-snapshot-preview1", + "wasi 0.11.0+wasi-snapshot-preview1", + "wasm-bindgen", ] [[package]] @@ -576,25 +822,31 @@ version = "0.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" dependencies = [ - "ahash", + "ahash 0.7.8", ] [[package]] -name = "heck" -version = "0.3.3" +name = "hashbrown" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "unicode-segmentation", + "ahash 0.8.11", ] [[package]] -name = "hermit-abi" -version = "0.2.6" +name = "hashbrown" +version = "0.14.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "heck" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee512640fe35acbfb4bb779db6f0d80704c2cacfa2e39b601ef3e3f47d1ae4c7" +checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c" dependencies = [ - "libc", + "unicode-segmentation", ] [[package]] @@ -634,47 +886,69 @@ dependencies = [ "version_check", ] +[[package]] +name = "indexmap" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26" +dependencies = [ + "equivalent", + "hashbrown 0.14.5", +] + [[package]] name = "itertools" -version = "0.10.3" +version = "0.10.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9a9d19fa1e79b6215ff29b9d6880b706147f16e9b1dbb1e4e5947b5b02bc5e3" +checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.1" +version = "1.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "jobserver" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e" +dependencies = [ + "libc", +] [[package]] name = "js-sys" -version = "0.3.57" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" +checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d" dependencies = [ "wasm-bindgen", ] [[package]] name = "keccak" -version = "0.1.0" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" +checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +dependencies = [ + "cpufeatures", +] [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.121" +version = "0.2.155" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaa7b300f3b5fe8eb6bf21ce3895e1751d9665086af2d64b42f19701015ff4f" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" [[package]] name = "libsecp256k1" @@ -689,7 +963,7 @@ dependencies = [ "libsecp256k1-core", "libsecp256k1-gen-ecmult", "libsecp256k1-gen-genmult", - "rand", + "rand 0.7.3", "serde", "sha2 0.9.9", "typenum", @@ -724,11 +998,23 @@ dependencies = [ "libsecp256k1-core", ] +[[package]] +name = "light-poseidon" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" +dependencies = [ + "ark-bn254", + "ark-ff", + "num-bigint", + "thiserror", +] + [[package]] name = "lock_api" -version = "0.4.7" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "327fa5b6a6940e4699ec49a9beae1ea4845c6bab9314e4f84ac68742139d8c53" +checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17" dependencies = [ "autocfg", "scopeguard", @@ -736,37 +1022,44 @@ dependencies = [ [[package]] name = "log" -version = "0.4.16" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6389c490849ff5bc16be905ae24bc913a9c8892e19b2341dbc175e14c341c2b8" -dependencies = [ - "cfg-if", -] +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "memchr" -version = "2.4.1" +version = "2.7.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" [[package]] name = "memmap2" -version = "0.5.3" +version = "0.5.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "057a3db23999c867821a7a59feb06a578fcb03685e983dff90daf9e7d24ac08f" +checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327" dependencies = [ "libc", ] [[package]] name = "memoffset" -version = "0.8.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d61c719bcfbcf5d62b3a09efa6088de8c54bc0bfcd3ea7ae39fcc186108b8de1" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] +[[package]] +name = "num-bigint" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" +dependencies = [ + "num-integer", + "num-traits", +] + [[package]] name = "num-derive" version = "0.3.3" @@ -775,45 +1068,55 @@ checksum = "876a53fff98e03a936a674b29568b0e605f06b29372c2489ff4de23f1949743d" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 1.0.109", ] [[package]] -name = "num-traits" -version = "0.2.14" +name = "num-derive" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ - "autocfg", + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] -name = "num_cpus" -version = "1.15.0" +name = "num-integer" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fac9e2da13b5eb447a6ce3d392f23a29d8694bff781bf03a16cd9ac8697593b" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "hermit-abi", - "libc", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", ] [[package]] name = "once_cell" -version = "1.10.0" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9" +checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" [[package]] name = "opaque-debug" -version = "0.3.0" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27" dependencies = [ "lock_api", "parking_lot_core", @@ -821,22 +1124,37 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.7" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9069cbb9f99e3a5083476ccb29ceb1de18b9118cafa53e90c9551235de2b9521" +checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8" dependencies = [ "cfg-if", "libc", "redox_syscall", "smallvec", - "windows-sys", + "windows-targets", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "pbkdf2" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" +dependencies = [ + "crypto-mac", ] [[package]] name = "ppv-lite86" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb9f9e6e233e5c4a35559a617bf40a4ec447db2e84c20b55a6f83167b7e57872" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" [[package]] name = "proc-macro-crate" @@ -844,36 +1162,55 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "toml", + "toml 0.5.11", ] [[package]] -name = "proc-macro2" -version = "1.0.36" +name = "proc-macro-crate" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" dependencies = [ - "unicode-xid", + "toml_edit 0.21.1", ] [[package]] -name = "proc-macro2-diagnostics" -version = "0.9.1" +name = "proc-macro-error" +version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4bf29726d67464d49fa6224a1d07936a8c08bb3fba727c7493f6cf1616fdaada" +checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" dependencies = [ + "proc-macro-error-attr", "proc-macro2", "quote", - "syn", "version_check", - "yansi", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +dependencies = [ + "proc-macro2", + "quote", + "version_check", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", ] [[package]] name = "quote" -version = "1.0.16" +version = "1.0.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4af2ec4714533fcdf07e886f17025ace8b997b9ce51204ee69b6da831c3da57" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" dependencies = [ "proc-macro2", ] @@ -886,11 +1223,22 @@ checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ "getrandom 0.1.16", "libc", - "rand_chacha", + "rand_chacha 0.2.2", "rand_core 0.5.1", "rand_hc", ] +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -901,6 +1249,16 @@ dependencies = [ "rand_core 0.5.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_core" version = "0.5.1" @@ -915,6 +1273,9 @@ name = "rand_core" version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.15", +] [[package]] name = "rand_hc" @@ -936,9 +1297,9 @@ dependencies = [ [[package]] name = "rayon" -version = "1.6.1" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6db3a213adf02b3bcfd2d3846bb41cb22857d131789e01df434fb7e7bc0759b7" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -946,30 +1307,40 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.10.2" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356a0625f1954f730c0201cdab48611198dc6ce21f4acff55089b5a78e6e835b" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ - "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.2.13" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" +checksum = "2a908a6e00f1fdd0dfd9c0eb08ce85126f6d8bbda50017e74bc4a4b7d4a926a4" dependencies = [ "bitflags", ] [[package]] name = "regex" -version = "1.5.5" +version = "1.10.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" +checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df" dependencies = [ "aho-corasick", "memchr", @@ -978,9 +1349,15 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.6.25" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b" + +[[package]] +name = "rustc-hash" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" [[package]] name = "rustc_version" @@ -993,68 +1370,77 @@ dependencies = [ [[package]] name = "rustversion" -version = "1.0.6" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2cc38e8fa666e2de3c4aba7edeb5ffc5246c1c2ed0e3d17e560aeeba736b23f" +checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6" [[package]] name = "ryu" -version = "1.0.9" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73b4b750c782965c211b42f022f59af1fbceabdd026623714f104152f1ec149f" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" [[package]] name = "scopeguard" -version = "1.1.0" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "semver" -version = "1.0.7" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d65bd28f48be7196d222d95b9243287f48d27aca604e08497513019ff0502cc4" +checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" dependencies = [ "serde_derive", ] [[package]] name = "serde_bytes" -version = "0.11.5" +version = "0.11.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16ae07dd2f88a366f15bd0632ba725227018c69a1c8550a927324f8eb8368bb9" +checksum = "387cc504cb06bb40a96c8e04e951fe01854cf6bc921053c954e4a606d9675c6a" dependencies = [ "serde", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.204" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.72", ] [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.120" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "4e0d21c9a8cae1235ad58a00c11cb40d4b1e5c784f1ef2c537876ed6ffd8b7c5" dependencies = [ "itoa", "ryu", "serde", ] +[[package]] +name = "serde_spanned" +version = "0.6.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0" +dependencies = [ + "serde", +] + [[package]] name = "sha2" version = "0.9.9" @@ -1070,22 +1456,22 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82e6b795fe2e3b1e845bafcb27aa35405c4d47cdfc92af5fc8d3002f76cebdc0" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" dependencies = [ "cfg-if", "cpufeatures", - "digest 0.10.6", + "digest 0.10.7", ] [[package]] name = "sha3" -version = "0.10.6" +version = "0.10.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bdf0c33fae925bdc080598b84bc15c55e7b9a4a43b3c704da051f977469691c9" +checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" dependencies = [ - "digest 0.10.6", + "digest 0.10.7", "keccak", ] @@ -1101,18 +1487,20 @@ dependencies = [ [[package]] name = "smallvec" -version = "1.8.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f2dd574626839106c320a323308629dcb1acfc96e32a8cba364ddc61ac23ee83" +checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67" [[package]] name = "solana-frozen-abi" -version = "1.13.6" +version = "1.18.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16f845c62a8aee31ad250c08345818a7b0da10ebf7e1e5fdf5f5e735b6dee766" +checksum = "d836521fc3fe09fbc45ccf194c7524a73865e2fa4f2f3316c987e33ffad037ec" dependencies = [ + "block-buffer 0.10.4", "bs58 0.4.0", "bv", + "either", "generic-array", "im", "lazy_static", @@ -1122,76 +1510,90 @@ dependencies = [ "serde", "serde_bytes", "serde_derive", - "sha2 0.10.6", + "sha2 0.10.8", "solana-frozen-abi-macro", + "subtle", "thiserror", ] [[package]] name = "solana-frozen-abi-macro" -version = "1.13.6" +version = "1.18.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ebd2c533f11262885f1131e52ea6136e7c72fffb18c858ffee05964c5d2beb7" +checksum = "ce5a9e8a27bce6104994ca8b0fa16b496260fe9e093f76e68c4301fcf93de2d4" dependencies = [ "proc-macro2", "quote", "rustc_version", - "syn", + "syn 2.0.72", ] [[package]] name = "solana-program" -version = "1.13.6" +version = "1.18.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b218d6f58a793dfd2a7df80c5e9d289d1d78a22dc4975aa9962b9726f5c182ae" +checksum = "4b359778df37b366b137d51ba7cdd884ffb23df7d7602bf1a27f8593df19a290" dependencies = [ - "base64 0.13.0", + "ark-bn254", + "ark-ec", + "ark-ff", + "ark-serialize", + "base64 0.21.7", "bincode", "bitflags", "blake3", - "borsh", - "borsh-derive", + "borsh 0.10.3", + "borsh 0.9.3", + "borsh 1.5.1", "bs58 0.4.0", "bv", "bytemuck", + "cc", "console_error_panic_hook", "console_log", "curve25519-dalek", - "getrandom 0.1.16", + "getrandom 0.2.15", "itertools", "js-sys", "lazy_static", + "libc", "libsecp256k1", + "light-poseidon", "log", - "num-derive", + "memoffset", + "num-bigint", + "num-derive 0.4.2", "num-traits", "parking_lot", - "rand", + "rand 0.8.5", "rustc_version", "rustversion", "serde", "serde_bytes", "serde_derive", - "sha2 0.10.6", + "serde_json", + "sha2 0.10.8", "sha3", "solana-frozen-abi", "solana-frozen-abi-macro", "solana-sdk-macro", "thiserror", + "tiny-bip39", "wasm-bindgen", + "zeroize", ] [[package]] name = "solana-sdk-macro" -version = "1.13.6" +version = "1.18.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74ea5bf7eca00bc00e34453e11ee0f35cc15dab08c7167b5b01ef88623628246" +checksum = "91222f769514bbeb30af1cbe05e6904e8364286dc6253017b1630e7835855b41" dependencies = [ "bs58 0.4.0", "proc-macro2", "quote", "rustversion", - "syn", + "syn 2.0.72", ] [[package]] @@ -1202,33 +1604,56 @@ checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" [[package]] name = "syn" -version = "1.0.89" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.72" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" dependencies = [ "proc-macro2", "quote", - "unicode-xid", + "unicode-ident", +] + +[[package]] +name = "syn_derive" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn 2.0.72", ] [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "c0342370b38b6a11b6cc11d6a805569958d54cfa061a29969c3b5ce2ea405724" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.63" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "a4558b58466b9ad7ca0f102865eccc95938dca1a74a856f2b57b6629050da261" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.72", ] [[package]] @@ -1236,36 +1661,124 @@ name = "tic-tac-toe" version = "0.1.0" dependencies = [ "anchor-lang", - "num-derive", + "num-derive 0.3.3", "num-traits", ] +[[package]] +name = "tiny-bip39" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +dependencies = [ + "anyhow", + "hmac", + "once_cell", + "pbkdf2", + "rand 0.7.3", + "rustc-hash", + "sha2 0.9.9", + "thiserror", + "unicode-normalization", + "wasm-bindgen", + "zeroize", +] + +[[package]] +name = "tinyvec" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445e881f4f6d382d5f27c034e25eb92edd7c784ceab92a0937db7f2e9471b938" +dependencies = [ + "tinyvec_macros", +] + +[[package]] +name = "tinyvec_macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + [[package]] name = "toml" -version = "0.5.8" +version = "0.8.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac2caab0bf757388c6c0ae23b3293fdb463fee59434529014f85e3263b995c28" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit 0.22.16", +] + +[[package]] +name = "toml_datetime" +version = "0.6.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf" dependencies = [ "serde", ] +[[package]] +name = "toml_edit" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1" +dependencies = [ + "indexmap", + "toml_datetime", + "winnow 0.5.40", +] + +[[package]] +name = "toml_edit" +version = "0.22.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278f3d518e152219c994ce877758516bca5e118eaed6996192a774fb9fbf0788" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "winnow 0.6.15", +] + [[package]] name = "typenum" -version = "1.15.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] -name = "unicode-segmentation" -version = "1.9.0" +name = "unicode-ident" +version = "1.0.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e8820f5d777f6224dc4be3632222971ac30164d4a258d595640799554ebfd99" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" [[package]] -name = "unicode-xid" -version = "0.2.2" +name = "unicode-normalization" +version = "0.1.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5" +dependencies = [ + "tinyvec", +] + +[[package]] +name = "unicode-segmentation" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" [[package]] name = "version_check" @@ -1281,15 +1794,15 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.10.2+wasi-snapshot-preview1" +version = "0.11.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" [[package]] name = "wasm-bindgen" -version = "0.2.80" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" +checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1297,24 +1810,24 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.80" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" +checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da" dependencies = [ "bumpalo", - "lazy_static", "log", + "once_cell", "proc-macro2", "quote", - "syn", + "syn 2.0.72", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.80" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" +checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1322,51 +1835,43 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.80" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" +checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7" dependencies = [ "proc-macro2", "quote", - "syn", + "syn 2.0.72", "wasm-bindgen-backend", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.80" +version = "0.2.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" +checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96" [[package]] name = "web-sys" -version = "0.3.57" +version = "0.3.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" +checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef" dependencies = [ "js-sys", "wasm-bindgen", ] -[[package]] -name = "windows-sys" -version = "0.45.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" -dependencies = [ - "windows-targets", -] - [[package]] name = "windows-targets" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ "windows_aarch64_gnullvm", "windows_aarch64_msvc", "windows_i686_gnu", + "windows_i686_gnullvm", "windows_i686_msvc", "windows_x86_64_gnu", "windows_x86_64_gnullvm", @@ -1375,54 +1880,106 @@ dependencies = [ [[package]] name = "windows_aarch64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" [[package]] name = "windows_aarch64_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" [[package]] name = "windows_i686_gnu" -version = "0.42.1" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" [[package]] name = "windows_i686_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" [[package]] name = "windows_x86_64_gnu" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" [[package]] name = "windows_x86_64_gnullvm" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" [[package]] name = "windows_x86_64_msvc" -version = "0.42.1" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" [[package]] -name = "yansi" -version = "0.5.0" +name = "winnow" +version = "0.5.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fc79f4a1e39857fc00c3f662cbf2651c771f00e9c15fe2abc341806bd46bd71" +checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876" +dependencies = [ + "memchr", +] + +[[package]] +name = "winnow" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "557404e450152cd6795bb558bca69e43c585055f4606e3bcae5894fc6dac9ba0" +dependencies = [ + "memchr", +] + +[[package]] +name = "zerocopy" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9b4fd18abc82b8136838da5d50bae7bdea537c574d8dc1a34ed098d6c166f0" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.7.35" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4f8080344d4671fb4e831a13ad1e68092748387dfc4f55e356242fae12ce3e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] [[package]] name = "zeroize" version = "1.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +dependencies = [ + "zeroize_derive", +] + +[[package]] +name = "zeroize_derive" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.72", +] diff --git a/docs/programs/tic-tac-toe/Cargo.toml b/docs/programs/tic-tac-toe/Cargo.toml index a60de986d3..61ab23b005 100644 --- a/docs/programs/tic-tac-toe/Cargo.toml +++ b/docs/programs/tic-tac-toe/Cargo.toml @@ -2,3 +2,6 @@ members = [ "programs/*" ] + +[profile.release] +overflow-checks = true diff --git a/docs/programs/tic-tac-toe/package.json b/docs/programs/tic-tac-toe/package.json index 42c3eb5900..4998bf601e 100644 --- a/docs/programs/tic-tac-toe/package.json +++ b/docs/programs/tic-tac-toe/package.json @@ -1,14 +1,14 @@ { + "type": "module", "dependencies": { - "@project-serum/anchor": "0.24.1" + "@coral-xyz/anchor": "^0.30.1" }, "devDependencies": { "@types/chai": "^4.3.0", "@types/mocha": "^9.0.0", - "chai": "^4.3.4", - "chai-as-promised": "^7.1.1", - "mocha": "9.2.2", - "ts-mocha": "^8.0.0", + "chai": "^5.1.1", + "mocha": "^10.7.0", + "tsx": "^4.16.2", "typescript": "^4.3.5" } } diff --git a/docs/programs/tic-tac-toe/programs/tic-tac-toe/Cargo.toml b/docs/programs/tic-tac-toe/programs/tic-tac-toe/Cargo.toml index 3c5b40e723..a93bef1acf 100644 --- a/docs/programs/tic-tac-toe/programs/tic-tac-toe/Cargo.toml +++ b/docs/programs/tic-tac-toe/programs/tic-tac-toe/Cargo.toml @@ -9,13 +9,14 @@ crate-type = ["cdylib", "lib"] name = "tic_tac_toe" [features] +default = [] +cpi = ["no-entrypoint"] no-entrypoint = [] no-idl = [] no-log-ix-name = [] -cpi = ["no-entrypoint"] -default = [] +idl-build = ["anchor-lang/idl-build"] [dependencies] -anchor-lang = "=0.29.0" +anchor-lang = "=0.30.1" num-traits = "0.2" num-derive = "0.3" diff --git a/docs/programs/tic-tac-toe/tests/tic-tac-toe.ts b/docs/programs/tic-tac-toe/tests/tic-tac-toe.ts index 5d3c3791a1..6d1bcd6f1a 100644 --- a/docs/programs/tic-tac-toe/tests/tic-tac-toe.ts +++ b/docs/programs/tic-tac-toe/tests/tic-tac-toe.ts @@ -1,10 +1,7 @@ -import * as anchor from '@project-serum/anchor'; -import { AnchorError, Program } from '@project-serum/anchor'; +import * as anchor from "@coral-xyz/anchor"; +import { AnchorError, type Program } from "@coral-xyz/anchor"; import { TicTacToe } from '../target/types/tic_tac_toe'; -import chai from 'chai'; -import chaiAsPromised from 'chai-as-promised'; import { expect } from 'chai'; -chai.use(chaiAsPromised); async function play(program: Program, game, player, tile, expectedTurn, expectedGameState, expectedBoard) { await program.methods diff --git a/docs/programs/tic-tac-toe/tsconfig.json b/docs/programs/tic-tac-toe/tsconfig.json index cd5d2e3d06..569082957f 100644 --- a/docs/programs/tic-tac-toe/tsconfig.json +++ b/docs/programs/tic-tac-toe/tsconfig.json @@ -1,10 +1,11 @@ { "compilerOptions": { - "types": ["mocha", "chai"], - "typeRoots": ["./node_modules/@types"], - "lib": ["es2015"], - "module": "commonjs", - "target": "es6", - "esModuleInterop": true - } + "lib": ["ESNext"], + "module": "ESNext", + "target": "ESNext", + "moduleResolution": "Node", + "esModuleInterop": true, + }, + "include": ["**/*.ts"], + "exclude": ["node_modules"] } diff --git a/docs/programs/tic-tac-toe/yarn.lock b/docs/programs/tic-tac-toe/yarn.lock index b1b87b65e8..edd09b5fcb 100644 --- a/docs/programs/tic-tac-toe/yarn.lock +++ b/docs/programs/tic-tac-toe/yarn.lock @@ -2,95 +2,208 @@ # yarn lockfile v1 -"@babel/runtime@^7.11.2", "@babel/runtime@^7.12.5": - version "7.16.7" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.16.7.tgz#03ff99f64106588c9c403c6ecb8c3bafbbdff1fa" - integrity sha512-9E9FJowqAsytyOY6LG+1KuueckRL+aQW+mKvXRXnuFGyRAyepJPmEo9vgMfXUA6O9u3IeEdv9MAkppFcaQwogQ== - dependencies: - regenerator-runtime "^0.13.4" - -"@ethersproject/bytes@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/bytes/-/bytes-5.5.0.tgz#cb11c526de657e7b45d2e0f0246fb3b9d29a601c" - integrity sha512-ABvc7BHWhZU9PNM/tANm/Qx4ostPGadAuQzWTr3doklZOhDlmcBqclrQe/ZXUIj3K8wC28oYeuRa+A37tX9kog== - dependencies: - "@ethersproject/logger" "^5.5.0" - -"@ethersproject/logger@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/logger/-/logger-5.5.0.tgz#0c2caebeff98e10aefa5aef27d7441c7fd18cf5d" - integrity sha512-rIY/6WPm7T8n3qS2vuHTUBPdXHl+rGxWxW5okDfo9J4Z0+gRRZT0msvUdIJkE4/HS29GUMziwGaaKO2bWONBrg== - -"@ethersproject/sha2@^5.5.0": - version "5.5.0" - resolved "https://registry.yarnpkg.com/@ethersproject/sha2/-/sha2-5.5.0.tgz#a40a054c61f98fd9eee99af2c3cc6ff57ec24db7" - integrity sha512-B5UBoglbCiHamRVPLA110J+2uqsifpZaTmid2/7W5rbtYVz6gus6/hSDieIU/6gaKIDcOj12WnOdiymEUHIAOA== - dependencies: - "@ethersproject/bytes" "^5.5.0" - "@ethersproject/logger" "^5.5.0" - hash.js "1.1.7" - -"@project-serum/anchor@0.24.1": - version "0.24.1" - resolved "https://registry.yarnpkg.com/@project-serum/anchor/-/anchor-0.24.1.tgz#521c3d610d3db7e24f143736e9c945b54fb8ef85" - integrity sha512-Oab6rPKsoBKf7/m/AyZcx3ahzcRiOFbqYRoDX6Gnxiqeu2zLKS+LyV6v/2XEVnwhIhOtwETtsgSZAwbqjM5Ywg== - dependencies: - "@project-serum/borsh" "^0.2.5" - "@solana/web3.js" "^1.36.0" - base64-js "^1.5.1" +"@babel/runtime@^7.24.8": + version "7.24.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.24.8.tgz#5d958c3827b13cc6d05e038c07fb2e5e3420d82e" + integrity sha512-5F7SDGs1T72ZczbRwbGO9lQi0NLjQxzl6i4lJxLxfW9U5UluCSyEJeniWvnhl3/euNiqQVbo8zruhsDfid0esA== + dependencies: + regenerator-runtime "^0.14.0" + +"@coral-xyz/anchor-errors@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor-errors/-/anchor-errors-0.30.1.tgz#bdfd3a353131345244546876eb4afc0e125bec30" + integrity sha512-9Mkradf5yS5xiLWrl9WrpjqOrAV+/W2RQHDlbnAZBivoGpOs1ECjoDCkVk4aRG8ZdiFiB8zQEVlxf+8fKkmSfQ== + +"@coral-xyz/anchor@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/anchor/-/anchor-0.30.1.tgz#17f3e9134c28cd0ea83574c6bab4e410bcecec5d" + integrity sha512-gDXFoF5oHgpriXAaLpxyWBHdCs8Awgf/gLHIo6crv7Aqm937CNdY+x+6hoj7QR5vaJV7MxWSQ0NGFzL3kPbWEQ== + dependencies: + "@coral-xyz/anchor-errors" "^0.30.1" + "@coral-xyz/borsh" "^0.30.1" + "@noble/hashes" "^1.3.1" + "@solana/web3.js" "^1.68.0" bn.js "^5.1.2" bs58 "^4.0.1" buffer-layout "^1.2.2" - camelcase "^5.3.1" + camelcase "^6.3.0" cross-fetch "^3.1.5" crypto-hash "^1.3.0" eventemitter3 "^4.0.7" - js-sha256 "^0.9.0" pako "^2.0.3" snake-case "^3.0.4" + superstruct "^0.15.4" toml "^3.0.0" -"@project-serum/borsh@^0.2.5": - version "0.2.5" - resolved "https://registry.yarnpkg.com/@project-serum/borsh/-/borsh-0.2.5.tgz#6059287aa624ecebbfc0edd35e4c28ff987d8663" - integrity sha512-UmeUkUoKdQ7rhx6Leve1SssMR/Ghv8qrEiyywyxSWg7ooV7StdpPBhciiy5eB3T0qU1BXvdRNC8TdrkxK7WC5Q== +"@coral-xyz/borsh@^0.30.1": + version "0.30.1" + resolved "https://registry.yarnpkg.com/@coral-xyz/borsh/-/borsh-0.30.1.tgz#869d8833abe65685c72e9199b8688477a4f6b0e3" + integrity sha512-aaxswpPrCFKl8vZTbxLssA2RvwX2zmKLlRCIktJOwW+VpVwYtXRtlWiIP+c2pPRKneiTiWCN2GEMSH9j1zTlWQ== dependencies: bn.js "^5.1.2" buffer-layout "^1.2.0" -"@solana/buffer-layout@^3.0.0": - version "3.0.0" - resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-3.0.0.tgz#b9353caeb9a1589cb77a1b145bcb1a9a93114326" - integrity sha512-MVdgAKKL39tEs0l8je0hKaXLQFb7Rdfb0Xg2LjFZd8Lfdazkg6xiS98uAZrEKvaoF3i4M95ei9RydkGIDMeo3w== +"@esbuild/aix-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz#c7184a326533fcdf1b8ee0733e21c713b975575f" + integrity sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ== + +"@esbuild/android-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz#09d9b4357780da9ea3a7dfb833a1f1ff439b4052" + integrity sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A== + +"@esbuild/android-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-arm/-/android-arm-0.21.5.tgz#9b04384fb771926dfa6d7ad04324ecb2ab9b2e28" + integrity sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg== + +"@esbuild/android-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/android-x64/-/android-x64-0.21.5.tgz#29918ec2db754cedcb6c1b04de8cd6547af6461e" + integrity sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA== + +"@esbuild/darwin-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz#e495b539660e51690f3928af50a76fb0a6ccff2a" + integrity sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ== + +"@esbuild/darwin-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz#c13838fa57372839abdddc91d71542ceea2e1e22" + integrity sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw== + +"@esbuild/freebsd-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz#646b989aa20bf89fd071dd5dbfad69a3542e550e" + integrity sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g== + +"@esbuild/freebsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz#aa615cfc80af954d3458906e38ca22c18cf5c261" + integrity sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ== + +"@esbuild/linux-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz#70ac6fa14f5cb7e1f7f887bcffb680ad09922b5b" + integrity sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q== + +"@esbuild/linux-arm@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz#fc6fd11a8aca56c1f6f3894f2bea0479f8f626b9" + integrity sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA== + +"@esbuild/linux-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz#3271f53b3f93e3d093d518d1649d6d68d346ede2" + integrity sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg== + +"@esbuild/linux-loong64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz#ed62e04238c57026aea831c5a130b73c0f9f26df" + integrity sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg== + +"@esbuild/linux-mips64el@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz#e79b8eb48bf3b106fadec1ac8240fb97b4e64cbe" + integrity sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg== + +"@esbuild/linux-ppc64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz#5f2203860a143b9919d383ef7573521fb154c3e4" + integrity sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w== + +"@esbuild/linux-riscv64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz#07bcafd99322d5af62f618cb9e6a9b7f4bb825dc" + integrity sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA== + +"@esbuild/linux-s390x@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz#b7ccf686751d6a3e44b8627ababc8be3ef62d8de" + integrity sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A== + +"@esbuild/linux-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz#6d8f0c768e070e64309af8004bb94e68ab2bb3b0" + integrity sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ== + +"@esbuild/netbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz#bbe430f60d378ecb88decb219c602667387a6047" + integrity sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg== + +"@esbuild/openbsd-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz#99d1cf2937279560d2104821f5ccce220cb2af70" + integrity sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow== + +"@esbuild/sunos-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz#08741512c10d529566baba837b4fe052c8f3487b" + integrity sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg== + +"@esbuild/win32-arm64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz#675b7385398411240735016144ab2e99a60fc75d" + integrity sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A== + +"@esbuild/win32-ia32@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz#1bfc3ce98aa6ca9a0969e4d2af72144c59c1193b" + integrity sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA== + +"@esbuild/win32-x64@0.21.5": + version "0.21.5" + resolved "https://registry.yarnpkg.com/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz#acad351d582d157bb145535db2a6ff53dd514b5c" + integrity sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw== + +"@noble/curves@^1.4.2": + version "1.4.2" + resolved "https://registry.yarnpkg.com/@noble/curves/-/curves-1.4.2.tgz#40309198c76ed71bc6dbf7ba24e81ceb4d0d1fe9" + integrity sha512-TavHr8qycMChk8UwMld0ZDRvatedkzWfH8IiaeGCfymOP5i0hSCozz9vHOL0nkwk7HRMlFnAiKpS2jrUmSybcw== + dependencies: + "@noble/hashes" "1.4.0" + +"@noble/hashes@1.4.0", "@noble/hashes@^1.3.1", "@noble/hashes@^1.4.0": + version "1.4.0" + resolved "https://registry.yarnpkg.com/@noble/hashes/-/hashes-1.4.0.tgz#45814aa329f30e4fe0ba49426f49dfccdd066426" + integrity sha512-V1JJ1WTRUqHHrOSh597hURcMqVKVGL/ea3kv0gSnEdsEZ0/+VyPghM1lMNGc00z7CIQorSvbKpuJkxvuHbvdbg== + +"@solana/buffer-layout@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz#b996235eaec15b1e0b5092a8ed6028df77fa6c15" + integrity sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA== dependencies: buffer "~6.0.3" -"@solana/web3.js@^1.36.0": - version "1.36.0" - resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.36.0.tgz#79d7d5217b49b80139f4de68953adc5b9a9a264f" - integrity sha512-RNT1451iRR7TyW7EJKMCrH/0OXawIe4zVm0DWQASwXlR/u1jmW6FrmH0lujIh7cGTlfOVbH+2ZU9AVUPLBFzwA== - dependencies: - "@babel/runtime" "^7.12.5" - "@ethersproject/sha2" "^5.5.0" - "@solana/buffer-layout" "^3.0.0" - bn.js "^5.0.0" - borsh "^0.4.0" +"@solana/web3.js@^1.68.0": + version "1.95.1" + resolved "https://registry.yarnpkg.com/@solana/web3.js/-/web3.js-1.95.1.tgz#fcbbaf845309ff7ceb8d3726702799e8c27530e8" + integrity sha512-mRX/AjV6QbiOXpWcy5Rz1ZWEH2lVkwO7T0pcv9t97ACpv3/i3tPiqXwk0JIZgSR3wOSTiT26JfygnJH2ulS6dQ== + dependencies: + "@babel/runtime" "^7.24.8" + "@noble/curves" "^1.4.2" + "@noble/hashes" "^1.4.0" + "@solana/buffer-layout" "^4.0.1" + agentkeepalive "^4.5.0" + bigint-buffer "^1.1.5" + bn.js "^5.2.1" + borsh "^0.7.0" bs58 "^4.0.1" - buffer "6.0.1" - cross-fetch "^3.1.4" - jayson "^3.4.4" - js-sha3 "^0.8.0" - rpc-websockets "^7.4.2" - secp256k1 "^4.0.2" - superstruct "^0.14.2" - tweetnacl "^1.0.0" - -"@types/bn.js@^4.11.5": - version "4.11.6" - resolved "https://registry.yarnpkg.com/@types/bn.js/-/bn.js-4.11.6.tgz#c306c70d9358aaea33cd4eda092a742b9505967c" - integrity sha512-pqr857jrp2kPuO9uRjZ3PwnJTjoQy+fcdxvBTvHm6dkmEL9q+hDD/2j/0ELOBPtPnS8LjCX0gI9nbl8lVkadpg== + buffer "6.0.3" + fast-stable-stringify "^1.0.0" + jayson "^4.1.1" + node-fetch "^2.7.0" + rpc-websockets "^9.0.2" + superstruct "^2.0.2" + +"@swc/helpers@^0.5.11": + version "0.5.12" + resolved "https://registry.yarnpkg.com/@swc/helpers/-/helpers-0.5.12.tgz#37aaca95284019eb5d2207101249435659709f4b" + integrity sha512-KMZNXiGibsW9kvZAO1Pam2JPTDBm+KSHMMHWdsyI/1DbIZjT2A6Gy3hblVXUMEDvUAKq+e0vL0X0o54owWji7g== dependencies: - "@types/node" "*" + tslib "^2.4.0" "@types/chai@^4.3.0": version "4.3.0" @@ -104,25 +217,6 @@ dependencies: "@types/node" "*" -"@types/express-serve-static-core@^4.17.9": - version "4.17.27" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.27.tgz#7a776191e47295d2a05962ecbb3a4ce97e38b401" - integrity sha512-e/sVallzUTPdyOTiqi8O8pMdBBphscvI6E4JYaKlja4Lm+zh7UFSSdW5VMkRbhDtmrONqOUHOXRguPsDckzxNA== - dependencies: - "@types/node" "*" - "@types/qs" "*" - "@types/range-parser" "*" - -"@types/json5@^0.0.29": - version "0.0.29" - resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" - integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= - -"@types/lodash@^4.14.159": - version "4.14.178" - resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.178.tgz#341f6d2247db528d4a13ddbb374bcdc80406f4f8" - integrity sha512-0d5Wd09ItQWH1qFbEyQ7oTQ3GZrMfth5JkbN3EvTKLXcHLRDSXeLnlvlOn0wvxVIwK5o2M8JzP/OWz7T3NRsbw== - "@types/mocha@^9.0.0": version "9.0.0" resolved "https://registry.yarnpkg.com/@types/mocha/-/mocha-9.0.0.tgz#3205bcd15ada9bc681ac20bef64e9e6df88fd297" @@ -138,15 +232,10 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.41.tgz#81d7734c5257da9f04354bd9084a6ebbdd5198a5" integrity sha512-f6xOqucbDirG7LOzedpvzjP3UTmHttRou3Mosx3vL9wr9AIQGhcPgVnqa8ihpZYnxyM1rxeNCvTyukPKZtq10Q== -"@types/qs@*": - version "6.9.7" - resolved "https://registry.yarnpkg.com/@types/qs/-/qs-6.9.7.tgz#63bb7d067db107cc1e457c303bc25d511febf6cb" - integrity sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw== - -"@types/range-parser@*": - version "1.2.4" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" - integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== +"@types/uuid@^8.3.4": + version "8.3.4" + resolved "https://registry.yarnpkg.com/@types/uuid/-/uuid-8.3.4.tgz#bd86a43617df0594787d38b735f55c805becf1bc" + integrity sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw== "@types/ws@^7.4.4": version "7.4.7" @@ -155,10 +244,12 @@ dependencies: "@types/node" "*" -"@ungap/promise-all-settled@1.1.2": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@ungap/promise-all-settled/-/promise-all-settled-1.1.2.tgz#aa58042711d6e3275dd37dc597e5d31e8c290a44" - integrity sha512-sL/cEvJWAnClXw0wHk85/2L0G6Sj8UB0Ctc1TEMbKSsmpRosqhwj9gWgFRZSrBr2f9tiXISwNhCPmlfqUqyb9Q== +"@types/ws@^8.2.2": + version "8.5.11" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-8.5.11.tgz#90ad17b3df7719ce3e6bc32f83ff954d38656508" + integrity sha512-4+q7P5h3SpJxaBft0Dzpbr6lmMaqh0Jr2tbhJZ/luAwvD7ohSCniYkwz/pLxuT2h0EOa6QADgJj1Ko+TzRfZ+w== + dependencies: + "@types/node" "*" JSONStream@^1.3.5: version "1.3.5" @@ -168,10 +259,17 @@ JSONStream@^1.3.5: jsonparse "^1.2.0" through ">=2.2.7 <3" -ansi-colors@4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" - integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== +agentkeepalive@^4.5.0: + version "4.5.0" + resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.5.0.tgz#2673ad1389b3c418c5a20c5d7364f93ca04be923" + integrity sha512-5GG/5IbQQpC9FpkRGsSvZI5QYeSCzlJHdpBQntCsuTOxhKD8lqKhrleg2Yi7yvMIf82Ycmmqln9U8V9qwEiJew== + dependencies: + humanize-ms "^1.2.1" + +ansi-colors@^4.1.3: + version "4.1.3" + resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.3.tgz#37611340eb2243e70cc604cad35d63270d48781b" + integrity sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw== ansi-regex@^5.0.1: version "5.0.1" @@ -186,9 +284,9 @@ ansi-styles@^4.0.0, ansi-styles@^4.1.0: color-convert "^2.0.1" anymatch@~3.1.2: - version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" - integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== + version "3.1.3" + resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.3.tgz#790c58b19ba1720a84205b57c618d5ad8524973e" + integrity sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw== dependencies: normalize-path "^3.0.0" picomatch "^2.0.4" @@ -198,15 +296,10 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -arrify@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -assertion-error@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-1.1.0.tgz#e60b6b0e8f301bd97e5375215bda406c85118c0b" - integrity sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw== +assertion-error@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/assertion-error/-/assertion-error-2.0.1.tgz#f641a196b335690b1070bf00b6e7593fec190bf7" + integrity sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA== balanced-match@^1.0.0: version "1.0.2" @@ -220,57 +313,64 @@ base-x@^3.0.2: dependencies: safe-buffer "^5.0.1" -base64-js@^1.3.1, base64-js@^1.5.1: +base64-js@^1.3.1: version "1.5.1" resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== +bigint-buffer@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/bigint-buffer/-/bigint-buffer-1.1.5.tgz#d038f31c8e4534c1f8d0015209bf34b4fa6dd442" + integrity sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA== + dependencies: + bindings "^1.3.0" + binary-extensions@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d" - integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA== + version "2.3.0" + resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.3.0.tgz#f6e14a97858d327252200242d4ccfe522c445522" + integrity sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw== -bn.js@^4.11.9: - version "4.12.0" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.12.0.tgz#775b3f278efbb9718eec7361f483fb36fbbfea88" - integrity sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA== +bindings@^1.3.0: + version "1.5.0" + resolved "https://registry.yarnpkg.com/bindings/-/bindings-1.5.0.tgz#10353c9e945334bc0511a6d90b38fbc7c9c504df" + integrity sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ== + dependencies: + file-uri-to-path "1.0.0" -bn.js@^5.0.0, bn.js@^5.1.2: +bn.js@^5.1.2: version "5.2.0" resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.0.tgz#358860674396c6997771a9d051fcc1b57d4ae002" integrity sha512-D7iWRBvnZE8ecXiLj/9wbxH7Tk79fAh8IHaTNq1RWRixsS02W+5qS+iE9yq6RYl0asXx5tw0bLhmT5pIfbSquw== -borsh@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.4.0.tgz#9dd6defe741627f1315eac2a73df61421f6ddb9f" - integrity sha512-aX6qtLya3K0AkT66CmYWCCDr77qsE9arV05OmdFpmat9qu8Pg9J5tBUPDztAW5fNh/d/MyVG/OYziP52Ndzx1g== +bn.js@^5.2.0, bn.js@^5.2.1: + version "5.2.1" + resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-5.2.1.tgz#0bc527a6a0d18d0aa8d5b0538ce4a77dccfa7b70" + integrity sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ== + +borsh@^0.7.0: + version "0.7.0" + resolved "https://registry.yarnpkg.com/borsh/-/borsh-0.7.0.tgz#6e9560d719d86d90dc589bca60ffc8a6c51fec2a" + integrity sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA== dependencies: - "@types/bn.js" "^4.11.5" - bn.js "^5.0.0" + bn.js "^5.2.0" bs58 "^4.0.0" text-encoding-utf-8 "^1.0.2" -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== dependencies: balanced-match "^1.0.0" - concat-map "0.0.1" braces@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" - integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== dependencies: - fill-range "^7.0.1" - -brorand@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" - integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= + fill-range "^7.1.1" -browser-stdout@1.3.1: +browser-stdout@^1.3.1: version "1.3.1" resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== @@ -282,25 +382,12 @@ bs58@^4.0.0, bs58@^4.0.1: dependencies: base-x "^3.0.2" -buffer-from@^1.0.0, buffer-from@^1.1.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.2.tgz#2b146a6fd72e80b4f55d255f35ed59a3a9a41bd5" - integrity sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ== - buffer-layout@^1.2.0, buffer-layout@^1.2.2: version "1.2.2" resolved "https://registry.yarnpkg.com/buffer-layout/-/buffer-layout-1.2.2.tgz#b9814e7c7235783085f9ca4966a0cfff112259d5" integrity sha512-kWSuLN694+KTk8SrYvCqwP2WcgQjoRCiF5b4QDvkkz8EmgD+aWAIceGFKMIAdmF/pH+vpgNV3d3kAKorcdAmWA== -buffer@6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.1.tgz#3cbea8c1463e5a0779e30b66d4c88c6ffa182ac2" - integrity sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ== - dependencies: - base64-js "^1.3.1" - ieee754 "^1.2.1" - -buffer@~6.0.3: +buffer@6.0.3, buffer@^6.0.3, buffer@~6.0.3: version "6.0.3" resolved "https://registry.yarnpkg.com/buffer/-/buffer-6.0.3.tgz#2ace578459cc8fbe2a70aaa8f52ee63b6a74c6c6" integrity sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA== @@ -315,34 +402,21 @@ bufferutil@^4.0.1: dependencies: node-gyp-build "^4.3.0" -camelcase@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" - integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== - -camelcase@^6.0.0: +camelcase@^6.0.0, camelcase@^6.3.0: version "6.3.0" resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.3.0.tgz#5685b95eb209ac9c0c177467778c9c84df58ba9a" integrity sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA== -chai-as-promised@^7.1.1: - version "7.1.1" - resolved "https://registry.yarnpkg.com/chai-as-promised/-/chai-as-promised-7.1.1.tgz#08645d825deb8696ee61725dbf590c012eb00ca0" - integrity sha512-azL6xMoi+uxu6z4rhWQ1jbdUhOMhis2PvscD/xjLqNMkv3BPPp2JyyuTHOrf9BOosGpNQ11v6BKv/g57RXbiaA== +chai@^5.1.1: + version "5.1.1" + resolved "https://registry.yarnpkg.com/chai/-/chai-5.1.1.tgz#f035d9792a22b481ead1c65908d14bb62ec1c82c" + integrity sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA== dependencies: - check-error "^1.0.2" - -chai@^4.3.4: - version "4.3.4" - resolved "https://registry.yarnpkg.com/chai/-/chai-4.3.4.tgz#b55e655b31e1eac7099be4c08c21964fce2e6c49" - integrity sha512-yS5H68VYOCtN1cjfwumDSuzn/9c+yza4f3reKXlE5rUg7SFcCEy90gJvydNgOYtblyf4Zi6jIWRnXOgErta0KA== - dependencies: - assertion-error "^1.1.0" - check-error "^1.0.2" - deep-eql "^3.0.1" - get-func-name "^2.0.0" - pathval "^1.1.1" - type-detect "^4.0.5" + assertion-error "^2.0.1" + check-error "^2.1.1" + deep-eql "^5.0.1" + loupe "^3.1.0" + pathval "^2.0.0" chalk@^4.1.0: version "4.1.2" @@ -352,15 +426,15 @@ chalk@^4.1.0: ansi-styles "^4.1.0" supports-color "^7.1.0" -check-error@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/check-error/-/check-error-1.0.2.tgz#574d312edd88bb5dd8912e9286dd6c0aed4aac82" - integrity sha1-V00xLt2Iu13YkS6Sht1sCu1KrII= +check-error@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/check-error/-/check-error-2.1.1.tgz#87eb876ae71ee388fa0471fe423f494be1d96ccc" + integrity sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw== -chokidar@3.5.3: - version "3.5.3" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.3.tgz#1cf37c8707b932bd1af1ae22c0432e2acd1903bd" - integrity sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw== +chokidar@^3.5.3: + version "3.6.0" + resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.6.0.tgz#197c6cc669ef2a8dc5e7b4d97ee4e092c3eb0d5b" + integrity sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw== dependencies: anymatch "~3.1.2" braces "~3.0.2" @@ -372,11 +446,6 @@ chokidar@3.5.3: optionalDependencies: fsevents "~2.3.2" -circular-json@^0.5.9: - version "0.5.9" - resolved "https://registry.yarnpkg.com/circular-json/-/circular-json-0.5.9.tgz#932763ae88f4f7dead7a0d09c8a51a4743a53b1d" - integrity sha512-4ivwqHpIFJZBuhN3g/pEcdbnGUywkBblloGbkglyloVjjR3uT6tieI89MVOfbP2tHX5sgb01FuLgAOzebNlJNQ== - cliui@^7.0.2: version "7.0.4" resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" @@ -403,12 +472,7 @@ commander@^2.20.3: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -cross-fetch@^3.1.4, cross-fetch@^3.1.5: +cross-fetch@^3.1.5: version "3.1.5" resolved "https://registry.yarnpkg.com/cross-fetch/-/cross-fetch-3.1.5.tgz#e1389f44d9e7ba767907f7af8454787952ab534f" integrity sha512-lvb1SBsI0Z7GDwmuid+mU3kWVBwTVUbe7S0H52yaaAdQOXq2YktTCZdlAcNKFzE6QtRz0snpw9bNiPeOIkkQvw== @@ -420,10 +484,10 @@ crypto-hash@^1.3.0: resolved "https://registry.yarnpkg.com/crypto-hash/-/crypto-hash-1.3.0.tgz#b402cb08f4529e9f4f09346c3e275942f845e247" integrity sha512-lyAZ0EMyjDkVvz8WOeVnuCPvKVBXcMv1l5SVqO1yC7PzTwrD/pPje/BIRbWhMoPe436U+Y2nD7f5bFx0kt+Sbg== -debug@4.3.3: - version "4.3.3" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.3.tgz#04266e0b70a98d4462e6e288e38259213332b664" - integrity sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q== +debug@^4.3.5: + version "4.3.5" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.5.tgz#e83444eceb9fedd4a1da56d671ae2446a01a6e1e" + integrity sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg== dependencies: ms "2.1.2" @@ -432,27 +496,20 @@ decamelize@^4.0.0: resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-4.0.0.tgz#aa472d7bf660eb15f3494efd531cab7f2a709837" integrity sha512-9iE1PgSik9HeIIw2JO94IidnE3eBoQrFJ3w7sFuzSX4DpmZ3v5sZpUiV5Swcf6mQEF+Y0ru8Neo+p+nyh2J+hQ== -deep-eql@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-3.0.1.tgz#dfc9404400ad1c8fe023e7da1df1c147c4b444df" - integrity sha512-+QeIQyN5ZuO+3Uk5DYh6/1eKO0m0YmJFGNmFHGACpf1ClL1nmlV/p4gNgbl2pJGxgXb4faqo6UE+M5ACEMyVcw== - dependencies: - type-detect "^4.0.0" +deep-eql@^5.0.1: + version "5.0.2" + resolved "https://registry.yarnpkg.com/deep-eql/-/deep-eql-5.0.2.tgz#4b756d8d770a9257300825d52a2c2cff99c3a341" + integrity sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q== delay@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/delay/-/delay-5.0.0.tgz#137045ef1b96e5071060dd5be60bf9334436bd1d" integrity sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw== -diff@5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-5.0.0.tgz#7ed6ad76d859d030787ec35855f5b1daf31d852b" - integrity sha512-/VTCrvm5Z0JGty/BWHljh+BAiw3IK+2j87NGMu8Nwc/f48WoDAC395uomO9ZD117ZOBaHmkX1oyLvkVM/aIT3w== - -diff@^3.1.0: - version "3.5.0" - resolved "https://registry.yarnpkg.com/diff/-/diff-3.5.0.tgz#800c0dd1e0a8bfbc95835c202ad220fe317e5a12" - integrity sha512-A46qtFgd+g7pDZinpnwiRJtxbC1hpgf0uzP3iG89scHk0AUC7A1TGxf5OiiOUv/JMZR8GOt8hL900hV0bOy5xA== +diff@^5.2.0: + version "5.2.0" + resolved "https://registry.yarnpkg.com/diff/-/diff-5.2.0.tgz#26ded047cd1179b78b9537d5ef725503ce1ae531" + integrity sha512-uIFDxqpRZGZ6ThOk84hEfqWoHx2devRFvpTZcTHur85vImfaxUbTW9Ryh4CpCuDnToOP1CEtXKIgytHBPVff5A== dot-case@^3.0.4: version "3.0.4" @@ -462,19 +519,6 @@ dot-case@^3.0.4: no-case "^3.0.4" tslib "^2.0.3" -elliptic@^6.5.4: - version "6.5.4" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.4.tgz#da37cebd31e79a1367e941b592ed1fbebd58abbb" - integrity sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ== - dependencies: - bn.js "^4.11.9" - brorand "^1.1.0" - hash.js "^1.0.0" - hmac-drbg "^1.0.1" - inherits "^2.0.4" - minimalistic-assert "^1.0.1" - minimalistic-crypto-utils "^1.0.1" - emoji-regex@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" @@ -492,12 +536,41 @@ es6-promisify@^5.0.0: dependencies: es6-promise "^4.0.3" +esbuild@~0.21.5: + version "0.21.5" + resolved "https://registry.yarnpkg.com/esbuild/-/esbuild-0.21.5.tgz#9ca301b120922959b766360d8ac830da0d02997d" + integrity sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw== + optionalDependencies: + "@esbuild/aix-ppc64" "0.21.5" + "@esbuild/android-arm" "0.21.5" + "@esbuild/android-arm64" "0.21.5" + "@esbuild/android-x64" "0.21.5" + "@esbuild/darwin-arm64" "0.21.5" + "@esbuild/darwin-x64" "0.21.5" + "@esbuild/freebsd-arm64" "0.21.5" + "@esbuild/freebsd-x64" "0.21.5" + "@esbuild/linux-arm" "0.21.5" + "@esbuild/linux-arm64" "0.21.5" + "@esbuild/linux-ia32" "0.21.5" + "@esbuild/linux-loong64" "0.21.5" + "@esbuild/linux-mips64el" "0.21.5" + "@esbuild/linux-ppc64" "0.21.5" + "@esbuild/linux-riscv64" "0.21.5" + "@esbuild/linux-s390x" "0.21.5" + "@esbuild/linux-x64" "0.21.5" + "@esbuild/netbsd-x64" "0.21.5" + "@esbuild/openbsd-x64" "0.21.5" + "@esbuild/sunos-x64" "0.21.5" + "@esbuild/win32-arm64" "0.21.5" + "@esbuild/win32-ia32" "0.21.5" + "@esbuild/win32-x64" "0.21.5" + escalade@^3.1.1: - version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" - integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== + version "3.1.2" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.2.tgz#54076e9ab29ea5bf3d8f1ed62acffbb88272df27" + integrity sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA== -escape-string-regexp@4.0.0: +escape-string-regexp@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== @@ -507,19 +580,34 @@ eventemitter3@^4.0.7: resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== +eventemitter3@^5.0.1: + version "5.0.1" + resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-5.0.1.tgz#53f5ffd0a492ac800721bb42c66b841de96423c4" + integrity sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA== + eyes@^0.1.8: version "0.1.8" resolved "https://registry.yarnpkg.com/eyes/-/eyes-0.1.8.tgz#62cf120234c683785d902348a800ef3e0cc20bc0" integrity sha1-Ys8SAjTGg3hdkCNIqADvPgzCC8A= -fill-range@^7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" - integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== +fast-stable-stringify@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz#5c5543462b22aeeefd36d05b34e51c78cb86d313" + integrity sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag== + +file-uri-to-path@1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/file-uri-to-path/-/file-uri-to-path-1.0.0.tgz#553a7b8446ff6f684359c445f1e37a05dacc33dd" + integrity sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw== + +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== dependencies: to-regex-range "^5.0.1" -find-up@5.0.0: +find-up@^5.0.0: version "5.0.0" resolved "https://registry.yarnpkg.com/find-up/-/find-up-5.0.0.tgz#4c92819ecb7083561e4f4a240a86be5198f536fc" integrity sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng== @@ -535,22 +623,29 @@ flat@^5.0.2: fs.realpath@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= + integrity sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw== -fsevents@~2.3.2: - version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" - integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== +fsevents@~2.3.2, fsevents@~2.3.3: + version "2.3.3" + resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.3.tgz#cac6407785d03675a2a5e1a5305c697b347d90d6" + integrity sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw== get-caller-file@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== -get-func-name@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.0.tgz#ead774abee72e20409433a066366023dd6887a41" - integrity sha1-6td0q+5y4gQJQzoGY2YCPdaIekE= +get-func-name@^2.0.1: + version "2.0.2" + resolved "https://registry.yarnpkg.com/get-func-name/-/get-func-name-2.0.2.tgz#0d7cf20cd13fda808669ffa88f4ffc7a3943fc41" + integrity sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ== + +get-tsconfig@^4.7.5: + version "4.7.6" + resolved "https://registry.yarnpkg.com/get-tsconfig/-/get-tsconfig-4.7.6.tgz#118fd5b7b9bae234cc7705a00cd771d7eb65d62a" + integrity sha512-ZAqrLlu18NbDdRaHq+AKXzAmqIUPswPWKUchfytdAjiRFnCe5ojG2bstg6mRiZabkKfCoL/e98pbBELIV/YCeA== + dependencies: + resolve-pkg-maps "^1.0.0" glob-parent@~5.1.2: version "5.1.2" @@ -559,49 +654,33 @@ glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" -glob@7.2.0: - version "7.2.0" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.0.tgz#d15535af7732e02e948f4c41628bd910293f6023" - integrity sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q== +glob@^8.1.0: + version "8.1.0" + resolved "https://registry.yarnpkg.com/glob/-/glob-8.1.0.tgz#d388f656593ef708ee3e34640fdfb99a9fd1c33e" + integrity sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" inherits "2" - minimatch "^3.0.4" + minimatch "^5.0.1" once "^1.3.0" - path-is-absolute "^1.0.0" - -growl@1.10.5: - version "1.10.5" - resolved "https://registry.yarnpkg.com/growl/-/growl-1.10.5.tgz#f2735dc2283674fa67478b10181059355c369e5e" - integrity sha512-qBr4OuELkhPenW6goKVXiv47US3clb3/IbuWF9KNKEijAy9oeHxU9IgzjvJhHkUzhaj7rOUD7+YGWqUjLp5oSA== has-flag@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -hash.js@1.1.7, hash.js@^1.0.0, hash.js@^1.0.3: - version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" - integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== - dependencies: - inherits "^2.0.3" - minimalistic-assert "^1.0.1" - -he@1.2.0: +he@^1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/he/-/he-1.2.0.tgz#84ae65fa7eafb165fddb61566ae14baf05664f0f" integrity sha512-F/1DnUGPopORZi0ni+CvrCgHQ5FyEAHRLSApuYWMmrbSwoN2Mn/7k+Gl38gJnR7yyDZk6WLXwiGod1JOWNDKGw== -hmac-drbg@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" - integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= +humanize-ms@^1.2.1: + version "1.2.1" + resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + integrity sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ== dependencies: - hash.js "^1.0.3" - minimalistic-assert "^1.0.0" - minimalistic-crypto-utils "^1.0.1" + ms "^2.0.0" ieee754@^1.2.1: version "1.2.1" @@ -611,12 +690,12 @@ ieee754@^1.2.1: inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= + integrity sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA== dependencies: once "^1.3.0" wrappy "1" -inherits@2, inherits@^2.0.3, inherits@^2.0.4: +inherits@2: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -631,7 +710,7 @@ is-binary-path@~2.1.0: is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" - integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= + integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== is-fullwidth-code-point@^3.0.0: version "3.0.0" @@ -660,24 +739,17 @@ is-unicode-supported@^0.1.0: resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -isexe@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" - integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= - isomorphic-ws@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz#55fd4cd6c5e6491e76dc125938dd863f5cd4f2dc" integrity sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w== -jayson@^3.4.4: - version "3.6.6" - resolved "https://registry.yarnpkg.com/jayson/-/jayson-3.6.6.tgz#189984f624e398f831bd2be8e8c80eb3abf764a1" - integrity sha512-f71uvrAWTtrwoww6MKcl9phQTC+56AopLyEenWvKVAIMz+q0oVGj6tenLZ7Z6UiPBkJtKLj4kt0tACllFQruGQ== +jayson@^4.1.1: + version "4.1.1" + resolved "https://registry.yarnpkg.com/jayson/-/jayson-4.1.1.tgz#282ff13d3cea09776db684b7eeca98c47b2fa99a" + integrity sha512-5ZWm4Q/0DHPyeMfAsrwViwUS2DMVsQgWh8bEEIVTkfb3DzHZ2L3G5WUnF+AKmGjjM9r1uAv73SaqC1/U4RL45w== dependencies: "@types/connect" "^3.4.33" - "@types/express-serve-static-core" "^4.17.9" - "@types/lodash" "^4.14.159" "@types/node" "^12.12.54" "@types/ws" "^7.4.4" JSONStream "^1.3.5" @@ -687,21 +759,10 @@ jayson@^3.4.4: eyes "^0.1.8" isomorphic-ws "^4.0.1" json-stringify-safe "^5.0.1" - lodash "^4.17.20" uuid "^8.3.2" - ws "^7.4.5" - -js-sha256@^0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/js-sha256/-/js-sha256-0.9.0.tgz#0b89ac166583e91ef9123644bd3c5334ce9d0966" - integrity sha512-sga3MHh9sgQN2+pJ9VYZ+1LPwXOxuBJBA5nrR5/ofPfuiJBE2hnjsaN8se8JznOmGLN2p49Pe5U/ttafcs/apA== + ws "^7.5.10" -js-sha3@^0.8.0: - version "0.8.0" - resolved "https://registry.yarnpkg.com/js-sha3/-/js-sha3-0.8.0.tgz#b9b7a5da73afad7dedd0f8c463954cbde6818840" - integrity sha512-gF1cRrHhIzNfToc802P800N8PpXS+evLLXfsVpowqmAFR9uwbi89WvXg2QspOmXL8QL86J4T1EpFu+yUkwJY3Q== - -js-yaml@4.1.0: +js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -713,13 +774,6 @@ json-stringify-safe@^5.0.1: resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= -json5@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.2.tgz#63d98d60f21b313b77c4d6da18bfa69d80e1d593" - integrity sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA== - dependencies: - minimist "^1.2.0" - jsonparse@^1.2.0: version "1.3.1" resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" @@ -732,12 +786,7 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" -lodash@^4.17.20: - version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" - integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== - -log-symbols@4.1.0: +log-symbols@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== @@ -745,6 +794,13 @@ log-symbols@4.1.0: chalk "^4.1.0" is-unicode-supported "^0.1.0" +loupe@^3.1.0: + version "3.1.1" + resolved "https://registry.yarnpkg.com/loupe/-/loupe-3.1.1.tgz#71d038d59007d890e3247c5db97c1ec5a92edc54" + integrity sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw== + dependencies: + get-func-name "^2.0.1" + lower-case@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/lower-case/-/lower-case-2.0.2.tgz#6fa237c63dbdc4a82ca0fd882e4722dc5e634e28" @@ -752,92 +808,49 @@ lower-case@^2.0.2: dependencies: tslib "^2.0.3" -make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" - integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== - -minimalistic-crypto-utils@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" - integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= - -minimatch@4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-4.2.1.tgz#40d9d511a46bdc4e563c22c3080cde9c0d8299b4" - integrity sha512-9Uq1ChtSZO+Mxa/CL1eGizn2vRn3MlLgzhT0Iz8zaY8NdvxvB0d5QdPFmCKf7JKA9Lerx5vRrnwO03jsSfGG9g== - dependencies: - brace-expansion "^1.1.7" - -minimatch@^3.0.4: - version "3.1.2" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" - integrity sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw== - dependencies: - brace-expansion "^1.1.7" - -minimist@^1.2.0, minimist@^1.2.5: - version "1.2.6" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.6.tgz#8637a5b759ea0d6e98702cfb3a9283323c93af44" - integrity sha512-Jsjnk4bw3YJqYzbdyBiNsPWHPfO++UGG749Cxs6peCu5Xg4nrena6OVxOYxrQTqww0Jmwt+Ref8rggumkTLz9Q== - -mkdirp@^0.5.1: - version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" - integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== - dependencies: - minimist "^1.2.5" - -mocha@9.2.2: - version "9.2.2" - resolved "https://registry.yarnpkg.com/mocha/-/mocha-9.2.2.tgz#d70db46bdb93ca57402c809333e5a84977a88fb9" - integrity sha512-L6XC3EdwT6YrIk0yXpavvLkn8h+EU+Y5UcCHKECyMbdUIxyMuZj4bX4U9e1nvnvUUvQVsV2VHQr5zLdcUkhW/g== - dependencies: - "@ungap/promise-all-settled" "1.1.2" - ansi-colors "4.1.1" - browser-stdout "1.3.1" - chokidar "3.5.3" - debug "4.3.3" - diff "5.0.0" - escape-string-regexp "4.0.0" - find-up "5.0.0" - glob "7.2.0" - growl "1.10.5" - he "1.2.0" - js-yaml "4.1.0" - log-symbols "4.1.0" - minimatch "4.2.1" - ms "2.1.3" - nanoid "3.3.1" - serialize-javascript "6.0.0" - strip-json-comments "3.1.1" - supports-color "8.1.1" - which "2.0.2" - workerpool "6.2.0" - yargs "16.2.0" - yargs-parser "20.2.4" - yargs-unparser "2.0.0" +minimatch@^5.0.1, minimatch@^5.1.6: + version "5.1.6" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-5.1.6.tgz#1cfcb8cf5522ea69952cd2af95ae09477f122a96" + integrity sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g== + dependencies: + brace-expansion "^2.0.1" + +mocha@^10.7.0: + version "10.7.0" + resolved "https://registry.yarnpkg.com/mocha/-/mocha-10.7.0.tgz#9e5cbed8fa9b37537a25bd1f7fb4f6fc45458b9a" + integrity sha512-v8/rBWr2VO5YkspYINnvu81inSz2y3ODJrhO175/Exzor1RcEZZkizgE2A+w/CAXXoESS8Kys5E62dOHGHzULA== + dependencies: + ansi-colors "^4.1.3" + browser-stdout "^1.3.1" + chokidar "^3.5.3" + debug "^4.3.5" + diff "^5.2.0" + escape-string-regexp "^4.0.0" + find-up "^5.0.0" + glob "^8.1.0" + he "^1.2.0" + js-yaml "^4.1.0" + log-symbols "^4.1.0" + minimatch "^5.1.6" + ms "^2.1.3" + serialize-javascript "^6.0.2" + strip-json-comments "^3.1.1" + supports-color "^8.1.1" + workerpool "^6.5.1" + yargs "^16.2.0" + yargs-parser "^20.2.9" + yargs-unparser "^2.0.0" ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@^2.0.0, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== -nanoid@3.3.1: - version "3.3.1" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.3.1.tgz#6347a18cac88af88f58af0b3594b723d5e99bb35" - integrity sha512-n6Vs/3KGyxPQd6uO0eH4Bv0ojGSUvuLlIHtC3Y0kEO23YRge8H9x1GCzLn28YX0H66pMkxuaeESFq4tKISKwdw== - no-case@^3.0.4: version "3.0.4" resolved "https://registry.yarnpkg.com/no-case/-/no-case-3.0.4.tgz#d361fd5c9800f558551a8369fc0dcd4662b6124d" @@ -846,11 +859,6 @@ no-case@^3.0.4: lower-case "^2.0.2" tslib "^2.0.3" -node-addon-api@^2.0.0: - version "2.0.2" - resolved "https://registry.yarnpkg.com/node-addon-api/-/node-addon-api-2.0.2.tgz#432cfa82962ce494b132e9d72a15b29f71ff5d32" - integrity sha512-Ntyt4AIXyaLIuMHF6IOoTakB3K+RWxwtsHNRxllEoA6vPwP9o4866g6YWDLUdnucilZhmkxiHwHr11gAENw+QA== - node-fetch@2.6.7: version "2.6.7" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.7.tgz#24de9fba827e3b4ae44dc8b20256a379160052ad" @@ -858,7 +866,14 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-gyp-build@^4.2.0, node-gyp-build@^4.3.0: +node-fetch@^2.7.0: + version "2.7.0" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" + integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== + dependencies: + whatwg-url "^5.0.0" + +node-gyp-build@^4.3.0: version "4.3.0" resolved "https://registry.yarnpkg.com/node-gyp-build/-/node-gyp-build-4.3.0.tgz#9f256b03e5826150be39c764bf51e993946d71a3" integrity sha512-iWjXZvmboq0ja1pUGULQBexmxq8CV4xBhX7VDOTbL7ZR4FOowwY/VOtRxBN/yKxmdGoIp4j5ysNT4u3S2pDQ3Q== @@ -871,7 +886,7 @@ normalize-path@^3.0.0, normalize-path@~3.0.0: once@^1.3.0: version "1.4.0" resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= + integrity sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w== dependencies: wrappy "1" @@ -899,15 +914,10 @@ path-exists@^4.0.0: resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -pathval@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/pathval/-/pathval-1.1.1.tgz#8534e77a77ce7ac5a2512ea21e0fdb8fcf6c3d8d" - integrity sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ== +pathval@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/pathval/-/pathval-2.0.0.tgz#7e2550b422601d4f6b8e26f1301bc8f15a741a25" + integrity sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA== picomatch@^2.0.4, picomatch@^2.2.1: version "2.3.1" @@ -928,26 +938,33 @@ readdirp@~3.6.0: dependencies: picomatch "^2.2.1" -regenerator-runtime@^0.13.4: - version "0.13.9" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz#8925742a98ffd90814988d7566ad30ca3b263b52" - integrity sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA== +regenerator-runtime@^0.14.0: + version "0.14.1" + resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f" + integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw== require-directory@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" - integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= + integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== -rpc-websockets@^7.4.2: - version "7.4.16" - resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-7.4.16.tgz#eb701cdef577d4357ba5f526d50e25f370396fac" - integrity sha512-0b7OVhutzwRIaYAtJo5tqtaQTWKfwAsKnaThOSOy+VkhVdleNUgb8eZnWSdWITRZZEigV5uPEIDr5KZe4DBrdQ== - dependencies: - "@babel/runtime" "^7.11.2" - circular-json "^0.5.9" - eventemitter3 "^4.0.7" - uuid "^8.3.0" - ws "^7.4.5" +resolve-pkg-maps@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg-maps/-/resolve-pkg-maps-1.0.0.tgz#616b3dc2c57056b5588c31cdf4b3d64db133720f" + integrity sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw== + +rpc-websockets@^9.0.2: + version "9.0.2" + resolved "https://registry.yarnpkg.com/rpc-websockets/-/rpc-websockets-9.0.2.tgz#4c1568d00b8100f997379a363478f41f8f4b242c" + integrity sha512-YzggvfItxMY3Lwuax5rC18inhbjJv9Py7JXRHxTIi94JOLrqBsSsUUc5bbl5W6c11tXhdfpDPK0KzBhoGe8jjw== + dependencies: + "@swc/helpers" "^0.5.11" + "@types/uuid" "^8.3.4" + "@types/ws" "^8.2.2" + buffer "^6.0.3" + eventemitter3 "^5.0.1" + uuid "^8.3.2" + ws "^8.5.0" optionalDependencies: bufferutil "^4.0.1" utf-8-validate "^5.0.2" @@ -957,19 +974,10 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.0: resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -secp256k1@^4.0.2: - version "4.0.3" - resolved "https://registry.yarnpkg.com/secp256k1/-/secp256k1-4.0.3.tgz#c4559ecd1b8d3c1827ed2d1b94190d69ce267303" - integrity sha512-NLZVf+ROMxwtEj3Xa562qgv2BK5e2WNmXPiOdVIPLgs6lyTzMvBq0aWTYMI5XCP9jZMVKOcqZLw/Wc4vDkuxhA== - dependencies: - elliptic "^6.5.4" - node-addon-api "^2.0.0" - node-gyp-build "^4.2.0" - -serialize-javascript@6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.0.tgz#efae5d88f45d7924141da8b5c3a7a7e663fefeb8" - integrity sha512-Qr3TosvguFt8ePWqsvRfrKyQXIiW+nGbYpy8XK24NQHE83caxWt+mIymTT19DGFbNWNLfEwsrkSmN64lVWB9ag== +serialize-javascript@^6.0.2: + version "6.0.2" + resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-6.0.2.tgz#defa1e055c83bf6d59ea805d8da862254eb6a6c2" + integrity sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g== dependencies: randombytes "^2.1.0" @@ -981,19 +989,6 @@ snake-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" -source-map-support@^0.5.6: - version "0.5.21" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" - integrity sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w== - dependencies: - buffer-from "^1.0.0" - source-map "^0.6.0" - -source-map@^0.6.0: - version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" - integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== - string-width@^4.1.0, string-width@^4.2.0: version "4.2.3" resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.3.tgz#269c7117d27b05ad2e536830a8ec895ef9c6d010" @@ -1010,27 +1005,20 @@ strip-ansi@^6.0.0, strip-ansi@^6.0.1: dependencies: ansi-regex "^5.0.1" -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - -strip-json-comments@3.1.1: +strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" integrity sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig== -superstruct@^0.14.2: - version "0.14.2" - resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.14.2.tgz#0dbcdf3d83676588828f1cf5ed35cda02f59025b" - integrity sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ== +superstruct@^0.15.4: + version "0.15.5" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-0.15.5.tgz#0f0a8d3ce31313f0d84c6096cd4fa1bfdedc9dab" + integrity sha512-4AOeU+P5UuE/4nOUkmcQdW5y7i9ndt1cQd/3iUe+LTz3RxESf/W/5lg4B74HbDMMv8PHnPnGCQFH45kBcrQYoQ== -supports-color@8.1.1: - version "8.1.1" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" - integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== - dependencies: - has-flag "^4.0.0" +superstruct@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/superstruct/-/superstruct-2.0.2.tgz#3f6d32fbdc11c357deff127d591a39b996300c54" + integrity sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A== supports-color@^7.1.0: version "7.2.0" @@ -1039,6 +1027,13 @@ supports-color@^7.1.0: dependencies: has-flag "^4.0.0" +supports-color@^8.1.1: + version "8.1.1" + resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-8.1.1.tgz#cd6fc17e28500cff56c1b86c0a7fd4a54a73005c" + integrity sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q== + dependencies: + has-flag "^4.0.0" + text-encoding-utf-8@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz#585b62197b0ae437e3c7b5d0af27ac1021e10d13" @@ -1066,53 +1061,25 @@ tr46@~0.0.3: resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a" integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw== -ts-mocha@^8.0.0: - version "8.0.0" - resolved "https://registry.yarnpkg.com/ts-mocha/-/ts-mocha-8.0.0.tgz#962d0fa12eeb6468aa1a6b594bb3bbc818da3ef0" - integrity sha512-Kou1yxTlubLnD5C3unlCVO7nh0HERTezjoVhVw/M5S1SqoUec0WgllQvPk3vzPMc6by8m6xD1uR1yRf8lnVUbA== - dependencies: - ts-node "7.0.1" - optionalDependencies: - tsconfig-paths "^3.5.0" - -ts-node@7.0.1: - version "7.0.1" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-7.0.1.tgz#9562dc2d1e6d248d24bc55f773e3f614337d9baf" - integrity sha512-BVwVbPJRspzNh2yfslyT1PSbl5uIk03EZlb493RKHN4qej/D06n1cEhjlOJG69oFsE7OT8XjpTUcYf6pKTLMhw== - dependencies: - arrify "^1.0.0" - buffer-from "^1.1.0" - diff "^3.1.0" - make-error "^1.1.1" - minimist "^1.2.0" - mkdirp "^0.5.1" - source-map-support "^0.5.6" - yn "^2.0.0" - -tsconfig-paths@^3.5.0: - version "3.12.0" - resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz#19769aca6ee8f6a1a341e38c8fa45dd9fb18899b" - integrity sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg== - dependencies: - "@types/json5" "^0.0.29" - json5 "^1.0.1" - minimist "^1.2.0" - strip-bom "^3.0.0" - tslib@^2.0.3: version "2.3.1" resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== -tweetnacl@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-1.0.3.tgz#ac0af71680458d8a6378d0d0d050ab1407d35596" - integrity sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw== +tslib@^2.4.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.3.tgz#0438f810ad7a9edcde7a241c3d80db693c8cbfe0" + integrity sha512-xNvxJEOUiWPGhUuUdQgAJPKOOJfGnIyKySOc09XkKsgdUV/3E2zvwZYdejjmRgPCgcym1juLH3226yA7sEFJKQ== -type-detect@^4.0.0, type-detect@^4.0.5: - version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" - integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== +tsx@^4.16.2: + version "4.16.2" + resolved "https://registry.yarnpkg.com/tsx/-/tsx-4.16.2.tgz#8722be119ae226ef0b4c6210d5ee90f3ba823f19" + integrity sha512-C1uWweJDgdtX2x600HjaFaucXTilT7tgUZHbOE4+ypskZ1OP8CRCSDkCxG6Vya9EwaFIVagWwpaVAn5wzypaqQ== + dependencies: + esbuild "~0.21.5" + get-tsconfig "^4.7.5" + optionalDependencies: + fsevents "~2.3.3" typescript@^4.3.5: version "4.5.4" @@ -1126,7 +1093,7 @@ utf-8-validate@^5.0.2: dependencies: node-gyp-build "^4.3.0" -uuid@^8.3.0, uuid@^8.3.2: +uuid@^8.3.2: version "8.3.2" resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== @@ -1144,17 +1111,10 @@ whatwg-url@^5.0.0: tr46 "~0.0.3" webidl-conversions "^3.0.0" -which@2.0.2: - version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" - integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== - dependencies: - isexe "^2.0.0" - -workerpool@6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.2.0.tgz#827d93c9ba23ee2019c3ffaff5c27fccea289e8b" - integrity sha512-Rsk5qQHJ9eowMH28Jwhe8HEbmdYDX4lwoMWshiCXugjtHqMD9ZbiqSDLxcsfdqsETPzVUtX5s1Z5kStiIM6l4A== +workerpool@^6.5.1: + version "6.5.1" + resolved "https://registry.yarnpkg.com/workerpool/-/workerpool-6.5.1.tgz#060f73b39d0caf97c6db64da004cd01b4c099544" + integrity sha512-Fs4dNYcsdpYSAfVxhnl1L5zTksjvOJxtC5hzMNl+1t9B8hTJTdKDyZ5ju7ztgPy+ft9tBFXoOlDNiOT9WUXZlA== wrap-ansi@^7.0.0: version "7.0.0" @@ -1168,29 +1128,29 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= + integrity sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ== -ws@^7.4.5: - version "7.5.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.6.tgz#e59fc509fb15ddfb65487ee9765c5a51dec5fe7b" - integrity sha512-6GLgCqo2cy2A2rjCNFlxQS6ZljG/coZfZXclldI8FB/1G3CCI36Zd8xy2HrFVACi8tfk5XrgLQEk+P0Tnz9UcA== +ws@^7.5.10: + version "7.5.10" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.5.10.tgz#58b5c20dc281633f6c19113f39b349bd8bd558d9" + integrity sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ== + +ws@^8.5.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ws/-/ws-8.18.0.tgz#0d7505a6eafe2b0e712d232b42279f53bc289bbc" + integrity sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw== y18n@^5.0.5: version "5.0.8" resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yargs-parser@20.2.4: - version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" - integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== - -yargs-parser@^20.2.2: +yargs-parser@^20.2.2, yargs-parser@^20.2.9: version "20.2.9" resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.9.tgz#2eb7dc3b0289718fc295f362753845c41a0c94ee" integrity sha512-y11nGElTIV+CT3Zv9t7VKl+Q3hTQoT9a1Qzezhhl6Rp21gJ/IVTW7Z3y9EWXhuUBC2Shnf+DX0antecpAwSP8w== -yargs-unparser@2.0.0: +yargs-unparser@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/yargs-unparser/-/yargs-unparser-2.0.0.tgz#f131f9226911ae5d9ad38c432fe809366c2325eb" integrity sha512-7pRTIA9Qc1caZ0bZ6RYRGbHJthJWuakf+WmHK0rVeLkNrrGhfoabBNdue6kdINI6r4if7ocq9aD/n7xwKOdzOA== @@ -1200,7 +1160,7 @@ yargs-unparser@2.0.0: flat "^5.0.2" is-plain-obj "^2.1.0" -yargs@16.2.0: +yargs@^16.2.0: version "16.2.0" resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== @@ -1213,11 +1173,6 @@ yargs@16.2.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yn@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/yn/-/yn-2.0.0.tgz#e5adabc8acf408f6385fc76495684c88e6af689a" - integrity sha1-5a2ryKz0CPY4X8dklWhMiOavaJo= - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" diff --git a/docs/src/components/Hero.jsx b/docs/src/components/Hero.jsx index a3b0ac79dc..5066107f71 100644 --- a/docs/src/components/Hero.jsx +++ b/docs/src/components/Hero.jsx @@ -43,7 +43,7 @@ export function Hero() { Anchor

- Solana's Sealevel runtime framework + Solana's most popular smart contract framework.

Get started diff --git a/docs/src/pages/_app.jsx b/docs/src/pages/_app.jsx index 57c831ac5d..12a155c361 100644 --- a/docs/src/pages/_app.jsx +++ b/docs/src/pages/_app.jsx @@ -14,14 +14,6 @@ import 'focus-visible' import '@/styles/tailwind.css' const navigation = [ - { - title: 'Prologue', - links: [ - { title: 'Release Notes', href: '/docs/release-notes' }, - { title: 'CHANGELOG', href: '/docs/changelog' }, - { title: 'Contribution Guide', href: '/docs/contribution-guide' }, - ], - }, { title: 'Getting Started', links: [ @@ -32,6 +24,15 @@ const navigation = [ { title: 'Intro to Solana', href: '/docs/intro-to-solana' }, ], }, + { + title: 'Release Notes', + links: [ + { title: '0.30.1', href: '/release-notes/0.30.1' }, + { title: '0.30.0', href: '/release-notes/0.30.0' }, + { title: '0.29.0', href: '/release-notes/0.29.0' }, + { title: 'CHANGELOG', href: '/release-notes/changelog' }, + ], + }, { title: 'Core concepts', links: [ @@ -58,6 +59,7 @@ const navigation = [ { title: 'Guides', links: [ + { title: 'Contribution Guide', href: '/docs/contribution-guide' }, { title: 'Publishing Source', href: '/docs/publishing-source' }, { title: 'Verifiable Builds', diff --git a/docs/src/pages/docs/installation.md b/docs/src/pages/docs/installation.md index f2d119acfb..4dcd4079e8 100644 --- a/docs/src/pages/docs/installation.md +++ b/docs/src/pages/docs/installation.md @@ -63,7 +63,7 @@ Anchor binaries are available via an NPM package [`@coral-xyz/anchor-cli`](https We can also use Cargo to install the CLI directly. Make sure that the `--tag` argument uses the version you want (the version here is just an example). ```shell -cargo install --git https://github.com/coral-xyz/anchor --tag v0.29.0 anchor-cli --locked +cargo install --git https://github.com/coral-xyz/anchor --tag v0.30.1 anchor-cli --locked ``` On Linux systems you may need to install additional dependencies if cargo install fails. On Ubuntu, diff --git a/docs/src/pages/docs/manifest.md b/docs/src/pages/docs/manifest.md index 672029a18d..b224f827b3 100644 --- a/docs/src/pages/docs/manifest.md +++ b/docs/src/pages/docs/manifest.md @@ -200,6 +200,6 @@ Override toolchain data in the workspace similar to [`rust-toolchain.toml`](http ```toml [toolchain] -anchor_version = "0.29.0" # `anchor-cli` version to use(requires `avm`) -solana_version = "1.17.0" # Solana version to use(applies to all Solana tools) +anchor_version = "0.30.1" # `anchor-cli` version to use(requires `avm`) +solana_version = "1.18.17" # Solana version to use(applies to all Solana tools) ``` diff --git a/docs/src/pages/docs/publishing-source.md b/docs/src/pages/docs/publishing-source.md index ad1a309c05..dc69723cca 100644 --- a/docs/src/pages/docs/publishing-source.md +++ b/docs/src/pages/docs/publishing-source.md @@ -35,8 +35,8 @@ An example `Anchor.toml` config looks as follows, ```toml [toolchain] -anchor_version = "0.29.0" -solana_version = "1.17.0" +anchor_version = "0.30.1" +solana_version = "1.18.17" [workspace] members = ["programs/multisig"] @@ -62,7 +62,7 @@ Here there are four sections. standard Anchor workflow, this can be omitted. For programs not written in Anchor but still want to publish, this should be added. 3. `[provider]` - configures the wallet and cluster settings. Here, `mainnet` is used because the registry only supports `mainnet` binary verification at the moment. -4. `[programs.mainnet]` - configures each program in the workpace, providing +4. `[programs.mainnet]` - configures each program in the workspace, providing the `address` of the program to verify. {% callout title="Note" %} diff --git a/docs/src/pages/docs/the-accounts-struct.md b/docs/src/pages/docs/the-accounts-struct.md index a8c6865ced..460663ef6a 100644 --- a/docs/src/pages/docs/the-accounts-struct.md +++ b/docs/src/pages/docs/the-accounts-struct.md @@ -170,7 +170,7 @@ pub struct Initialize<'info> { ``` {% callout type="warning" title="Note" %} -The doc comment needs to be a [line or block doc comment](https://doc.rust-lang.org/reference/comments.html#doc-comments) (/// or /\*\*) to be interepreted as doc attribute by Rust. Double slash comments (//) are not interpreted as such. +The doc comment needs to be a [line or block doc comment](https://doc.rust-lang.org/reference/comments.html#doc-comments) (/// or /\*\*) to be interpreted as doc attribute by Rust. Double slash comments (//) are not interpreted as such. {% /callout %} ## Other Resources diff --git a/docs/src/pages/docs/verifiable-builds.md b/docs/src/pages/docs/verifiable-builds.md index 1275fe5183..12e8832756 100644 --- a/docs/src/pages/docs/verifiable-builds.md +++ b/docs/src/pages/docs/verifiable-builds.md @@ -3,7 +3,7 @@ title: Verifiable Builds description: Anchor - Verifiable Builds --- -Building programs with the Solana CLI may embed machine specfic +Building programs with the Solana CLI may embed machine specific code into the resulting binary. As a result, building the same program on different machines may produce different executables. To get around this problem, one can build inside a docker image with pinned dependencies to produce @@ -37,10 +37,10 @@ If the program has an IDL, it will also check the IDL deployed on chain matches. ## Images -A docker image for each version of Anchor is published on [Docker Hub](https://hub.docker.com/r/backpackapp/build). They are tagged in the form `backpackapp/build:`. For example, to get the image for Anchor `v0.29.0` one can run +A docker image for each version of Anchor is published on [Docker Hub](https://hub.docker.com/r/backpackapp/build). They are tagged in the form `backpackapp/build:`. For example, to get the image for Anchor `v0.30.1` one can run ```shell -docker pull backpackapp/build:v0.29.0 +docker pull backpackapp/build:v0.30.1 ``` ## Removing an Image diff --git a/docs/src/pages/index.md b/docs/src/pages/index.md index d3021f23f1..ff6544efa6 100644 --- a/docs/src/pages/index.md +++ b/docs/src/pages/index.md @@ -1,10 +1,10 @@ --- title: Introduction pageTitle: Anchor - Introduction -description: Anchor is a framework for Solana's Sealevel runtime providing several convenient developer tools for writing smart contracts. +description: Anchor is a framework for building secure Solana programs, often called 'smart contracts'. --- -Anchor is a framework for Solana's Sealevel runtime providing several convenient developer tools for writing smart contracts. {% .lead %} +Anchor is a framework for quickly building secure Solana programs.{% .lead %} {% link-grid %} @@ -22,11 +22,10 @@ Anchor is a framework for Solana's Sealevel runtime providing several convenient ## What is Anchor -Anchor is a framework for quickly building secure Solana programs. +With Anchor you can quickly build secure Solana programs, sometimes called 'smart contracts', because: -With Anchor you can build programs quickly because it writes various boilerplate for you such as (de)serialization of accounts and instruction data. - -You can build secure programs more easily because Anchor handles certain security checks for you. On top of that, it allows you to succinctly define additional checks and keep them separate from your business logic. + - Anchor writes various boilerplate for you such as (de)serialization of accounts and instruction data. + - Anchor handles certain security checks for you, and allows you to succinctly define additional checks and keep them separate from your business logic. Both of these aspects mean that instead of working on the tedious parts of raw Solana programs, you can spend more time working on what matters most, your product. diff --git a/docs/src/pages/docs/release-notes.md b/docs/src/pages/release-notes/0.29.0.md similarity index 91% rename from docs/src/pages/docs/release-notes.md rename to docs/src/pages/release-notes/0.29.0.md index 1c62c9ef7f..90b5e748a7 100644 --- a/docs/src/pages/docs/release-notes.md +++ b/docs/src/pages/release-notes/0.29.0.md @@ -1,15 +1,13 @@ --- -title: Release Notes -description: Anchor - Release Notes +title: Release Notes 0.29.0 +description: Anchor - Release Notes 0.29.0 --- Anchor keeps a [CHANGELOG](https://github.com/coral-xyz/anchor/blob/master/CHANGELOG.md) but it's not easy to make sense what has changed, what effect does the change have and how to migrate. This is where release notes comes in, an easy to digest and actionable view for each release. --- -## [0.29.0] - -### How to update +## How to update 1. Update `avm`: @@ -27,7 +25,7 @@ Anchor keeps a [CHANGELOG](https://github.com/coral-xyz/anchor/blob/master/CHANG 4. Update TS package(s) to `0.29.0`. -### Solana `1.14` is no longer supported +## Solana `1.14` is no longer supported Minimum supported Solana version is now `1.16.0` because @@ -40,7 +38,7 @@ If you are still on Solana `1.14`, update by running: solana-install init 1.17.0 ``` -### Override toolchain for the workspace +## Override toolchain for the workspace `Anchor.toml` has a new section called `[toolchain]` that allows overriding the current toolchain versions inside the workspace. @@ -50,13 +48,13 @@ anchor_version = "0.29.0" # `anchor-cli` version to use solana_version = "1.17.0" # Solana version to use ``` -#### Notes +### Notes - Fields are optional. - `anchor_version` requires [`avm`](https://github.com/coral-xyz/anchor/tree/master/avm) to be installed. - Before this release, `anchor_version` and `solana_version` keys in `Anchor.toml` were being used for Docker verifiable builds only. Now, all commands work via the `[toolchain]` section. -### Install CLI from commit with `avm` +## Install CLI from commit with `avm` It is possible to install CLI from commit by running: @@ -94,7 +92,7 @@ Specify `toolchain.anchor_version` as `-`: anchor_version = "0.28.0-6cf200493a307c01487c7b492b4893e0d6f6cb23" ``` -### Multiple files template +## Multiple files template Programs created with `anchor init` or `anchor new` have a single `lib.rs` file but not everyone prefers a single file approach for programs. @@ -123,7 +121,7 @@ or if you have an existing workspace: anchor new --template multiple ``` -### Upgradeable programs in tests +## Upgradeable programs in tests You can now configure upgradability of the programs in `anchor test`. @@ -134,7 +132,7 @@ In `Anchor.toml`: upgradeable = true ``` -or for an individiual program: +or for an individual program: ```toml [[test.genesis]] @@ -143,9 +141,9 @@ program = "swap.so" upgradeable = true ``` -### Lamport utilities +## Lamport utilities -Transfering lamports from a PDA is quite complicated due to the types that are being used. +Transferring lamports from a PDA is quite complicated due to the types that are being used. Instead of @@ -175,7 +173,7 @@ let lamports = ctx.accounts.my_account.get_lamports(); **Note:** The new methods are not only more ergonomic but they are also more performant than the previous examples. This is because `to_account_info` method clones the data internally but the new methods use a reference to the underlying data. -### Type safe context bumps +## Type safe context bumps Before this release, `ctx.bumps` used to be a `BTreeMap` which doesn't provide type safety for the keys(account names). @@ -191,7 +189,7 @@ let bump = ctx.bumps.my_account; **Note**: The new way is not only more intuitive but also is more performant. This is mainly because `BTreeMap` is heap-allocated and it has to resize and grow occasionally. -### `idl-build` feature +## `idl-build` feature There is a new way to generate IDLs via compilation. @@ -208,7 +206,7 @@ The IDL will be built automatically when you run `anchor build` but if you'd lik anchor idl build ``` -#### Notes +### Notes - All crates that are being used for the IDL generation needs to be added to the `idl-build` feature list. @@ -227,7 +225,7 @@ idl-build = [ - Generation time is a lot slower compared to the default method(parsing) due to Rust compile times. - Even though most of it works great, some parts are still rough around the edges and you may encounter parts that are not fully ironed out. Please [create an issue](https://github.com/coral-xyz/anchor/issues) if you run into a problem. -### Type aliases +## Type aliases Anchor IDL now supports type aliases. @@ -284,7 +282,7 @@ Generates the following IDL: **Note:** This example only works with the default IDL generation method(parsing) for now because type aliases for default Rust types don't work properly with `idl-build`([#2640](https://github.com/coral-xyz/anchor/issues/2640)). -### Export `mpl-token-metadata` +## Export `mpl-token-metadata` `anchor-spl` with `metadata` feature enabled now exports the `mpl-token-metadata` crate. @@ -302,7 +300,7 @@ and use the exported crate from `anchor-spl`: use anchor_spl::metadata::mpl_token_metadata; ``` -### TypeScript SDK improvements +## TypeScript SDK improvements 1. `Program.addEventListener` method is now strongly typed -- correct types for the event names and the event returned from the callback instead of `any`. @@ -317,7 +315,7 @@ use anchor_spl::metadata::mpl_token_metadata; 4. Removed `assert` and `base64-js` dependency. -### New docker image +## New docker image The previous image([projectserum/build](https://hub.docker.com/r/projectserum/build)) is now deprecated, new image is [backpackapp/build](https://hub.docker.com/r/backpackapp/build). @@ -329,9 +327,9 @@ docker pull backpackapp/build:v0.29.0 **Note:** `anchor build --verifiable` now works with the latest image. -### Enhanced performance +## Enhanced performance -`0.29.0` performance is noticably improved in all areas, the biggest one being [binary size](https://github.com/coral-xyz/anchor/blob/master/bench/BINARY_SIZE.md#0290) which is reduced ~36% compared to `0.28.0`! +`0.29.0` performance is noticeably improved in all areas, the biggest one being [binary size](https://github.com/coral-xyz/anchor/blob/master/bench/BINARY_SIZE.md#0290) which is reduced ~36% compared to `0.28.0`! Similar benchmarks can be found for [compute units](https://github.com/coral-xyz/anchor/blob/master/bench/COMPUTE_UNITS.md#0290) and [stack memory](https://github.com/coral-xyz/anchor/blob/master/bench/STACK_MEMORY.md#0290). diff --git a/docs/src/pages/release-notes/0.30.0.md b/docs/src/pages/release-notes/0.30.0.md new file mode 100644 index 0000000000..4f402daf1a --- /dev/null +++ b/docs/src/pages/release-notes/0.30.0.md @@ -0,0 +1,327 @@ +--- +title: Release Notes 0.30.0 +description: Anchor - Release Notes 0.30.0 +--- + +The long-awaited v0.30.0 release is finally here! + +We'll go over the main changes, but if you'd like to see all notable changes, check out the [CHANGELOG](https://github.com/coral-xyz/anchor/blob/v0.30.0/CHANGELOG.md#0300---2024-04-15). + +--- + +## How to upgrade + +1. Update `avm`: + + ```sh + cargo install --git https://github.com/coral-xyz/anchor --tag v0.30.0 avm --locked + ``` + +2. Update `anchor-cli`: + + ```sh + avm install latest + ``` + +3. Update Anchor crate(s) to `0.30.0`. Optionally, run `cargo update` to update other dependencies to the latest compatible versions. + +4. Update TS package(s) to `0.30.0`. + +## Recommended Solana Version + +While this release supports anything above `1.16`, the recommended Solana version is `1.18.8`. You can upgrade Solana tools by running: + +``` +solana-install init 1.18.8 +``` + +## IDL + +The IDL type specification and generation has been rewritten. To keep the release notes short, we won't go over the changes here, but see [this](https://github.com/coral-xyz/anchor/pull/2824) if you'd like to learn more. + +### `idl-build` feature + +`idl-build` feature is now required in your program's `Cargo.toml` definition in order for the IDL generation to work. + +Without this feature, `anchor build` outputs: + +``` +Error: `idl-build` feature is missing. To solve, add + +[features] +idl-build = ["anchor-lang/idl-build"] + +in ``. +``` + +Note that all crates that you use to generate type definitions for the IDL need to be specified in the list of `idl-build`, e.g. `anchor-spl/idl-build`, `some-program/idl-build`... + +## Lang + +### Dependency free program declaration + +Depending on other crates who used different versions of Anchor is not the best experience, to say the least. To solve this problem, program clients can now be generated from their IDL using the new `declare_program!` macro: + +```rs +declare_program!(program_name); +``` + +`program_name` is based on the file name of the IDL in `idls` directory, e.g. `idls/program_name.json` is required to exist in order for the above example to work. + +This works for both on-chain (CPI) and off-chain (RPC) usage, allowing program interactions without creating a [dependency hell](https://en.wikipedia.org/wiki/Dependency_hell). Check out [this](https://github.com/coral-xyz/anchor/blob/v0.30.0/tests/declare-program/programs/declare-program/src/lib.rs) example for on-chain CPI usage. + +For more information, see the macro's [documentation](https://docs.rs/anchor-lang/0.30.0/anchor_lang/macro.declare_program.html). + +### Token extensions + +#### Constraints + +There are new account constraints for [Token Extensions (Token 2022)](https://solana.com/solutions/token-extensions): + +- `group_pointer`: + - `authority` + - `group_address` +- `group_member_pointer`: + - `authority` + - `member_address` +- `metadata_pointer`: + - `authority` + - `metadata_address` +- `close_authority` + - `authority` +- `permanent_delegate`: + - `delegate` +- `transfer_hook`: + - `authority` + - `program_id` + +**Note:** Above values are concatinated with `::` (similar to other Anchor constraints) and have `extensions` prefix e.g. `extensions::group_pointer::authority = `. + +These constraints can be used both with or without the `init` constraint. + +[Here](https://github.com/coral-xyz/anchor/blob/v0.30.0/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs) is an example program that uses these constraints. + +#### CPI wrappers + +`anchor-spl` now includes CPI wrappers for Token Extensions which can be accessed from `anchor_spl::token_2022_extensions`. + +### `#[interface]` attribute + +Transfer hooks can now be used with the new `#[interface]` macro. This argument overrides the Anchor's default instruction discriminator to use the interface instruction's discriminator. + +Current supported values are: + +- `spl_transfer_hook_interface::initialize_extra_account_meta_list` +- `spl_transfer_hook_interface::execute` + +```rs +mod my_hook_program { + #[interface(spl_transfer_hook_interface::initialize_extra_account_meta_list)] + pub fn initialize(ctx: Context, metas: Vec) -> Result<()> { + /* ... */ + } + + #[interface(spl_transfer_hook_interface::execute)] + pub fn execute(ctx: Context, amount: u64) -> Result<()> { + /* ... */ + } +} +``` + +### Optional bumps + +When an optional account is not specified, instead of defaulting it to `u8::MAX`, this release changes the optional bump type to be `Option` and sets the bump field to `None`. + +### Less heap allocations + +[`BorshSerialize::try_to_vec`](https://github.com/near/borsh-rs/blob/79097e3c71ae469a101b4828457792bcf8be7f5f/borsh/src/ser/mod.rs#L47-L51) implementation, which is used in events, CPI, and return data, heap allocates [1024](https://github.com/near/borsh-rs/blob/79097e3c71ae469a101b4828457792bcf8be7f5f/borsh/src/ser/mod.rs#L19) bytes each time it's used, even if your data is much smaller. In this release, the default allocation is set to 256 bytes. + +There is also a new method `InstructionData::write_to()` to write to an existing allocation rather than creating a new allocation with `InstructionData::data()`. + +## CLI + +### Priority fees in CLI + +IDL commands take in `--priority-fee` argument +As it's getting harder and harder to land transactions in mainnet-beta without using priority fees, this release supports setting `--priority-fee` argument for the IDL commands. For example: + +``` +anchor idl erase-authority --program-id --priority-fee 9000 +``` + +When the `--priortiy-fee` argument is not specified, the median fee of the last 150 confirmed slots is used. + +### `--no-idl` flag on builds + +IDL generation requires building of the program, but this is unnecessary if your program API doesn't change. In that case, you can use `--no-idl` flag to build your program but skip the IDL generation: + +``` +anchor build --no-idl +``` + +### IDL buffer is closed after `idl upgrade` + +After an IDL upgrade, the buffer account is now closed and the lamports are returned back to the IDL authority. + +### Pass deploy arguments to `solana-cli` + +You can now pass arguments to `solana program deploy` from `anchor deploy`: + +``` +anchor deploy -- --final +``` + +### Verifiable deployments + +Similar to verifiable builds, you can now deploy the verified build instead of the default build: + +``` +anchor deploy --verifiable +``` + +### Accept package name as program name + +`--program-name` (`-p`) argument of various commands also works with package name of the program rather than lib name which is snake_case. For example: + +``` +anchor build -p my-program +``` + +### Deactivate test-validator features + +You can now deactivate test-validator features from `Anchor.toml`: + +```toml +[test.validator] +deactivate_feature = ["GDH5TVdbTPUpRnXaRyQqiKUa7uZAbZ28Q2N9bhbKoMLm", "zkiTNuzBKxrCLMKehzuQeKZyLtX2yvFcEKMML8nExU8"] +``` + +### Crate and package compatibility + +Using non-matching versions of `anchor-cli`, `anchor-lang`, and `@coral-xyz/anchor` can result in unexpected behavior. In this release, you'll get a warning if any of them don't match. + +### Explicit `overflow-checks` flag + +[`overflow-checks`](https://doc.rust-lang.org/cargo/reference/profiles.html#overflow-checks) flag is implicitly disabled by default. Anchor workspaces that are crated with `anchor init` have this flag enabled, however, Anchor doesn't do any checks for it after the initial workspace creation. + +With this release, `overflow-checks` in the workspace `Cargo.toml` need to be specified. Note that "specified" does not mean enabled, as you can also disable it, but you need to be explicit in doing so. + +### Wildcard pattern in `Anchor.toml` + +`workspace.members` and `workspace.exclude` now supports simple wildcard pattern: + +```toml +[workspace] +members = ["programs/*"] +``` + +Note that the support is limited to this simple wildcard pattern, and more complex globs are not currently supported. + +### `cargo build-sbf` is now the default + +Before this release, `anchor build` used `cargo build-bpf` to build programs, however, because it is deprecated, `anchor build` now defaults to `cargo build-sbf`. + +To preserve the old behavior, you can use: + +``` +anchor build --arch bpf +``` + +### Run multiple commands in scripts + +Scripts in `Anchor.toml` now supports running multiple commands: + +```toml +[scripts] +test-all = "cargo test && yarn run ts-mocha tests/**/*.ts" +``` + +This script would run both `cargo` and `yarn` commands: + +``` +anchor run test-all +``` + +### Test only a specified program + +A single program can be tested in a multi program workspace with the `--program-name` (`-p`) argument: + +``` +anchor test --program-name example +``` + +This builds and tests only the specified program. + +### Rust test template + +A wild TypeScript test won't appear if you initialize your workspace with the new Rust test template: + +``` +anchor init --test-template rust +``` + +## TypeScript + +### Account resolution + +Account resolution refers to the ability of clients to resolve accounts without having to manually specify them when sending transactions. + +There are too many changes to the account resolution logic in the TS library, however, we can skip a good chunk of them since they're mostly internal. + +One change that affects everyone is the change in the `accounts` method. Even though the TS library had some support for account resolution, it had no type-level support for it — all accounts were essentially typed as partial, and there was no way to know which accounts were resolvable and which were not. + +There are now 3 methods to specify accounts with the transaction builder: + +- `accounts`: This method is now fully type-safe based on the resolution fields in the IDL, making it much easier to only specify the accounts that are actually needed. +- `accountsPartial`: This method keeps the old behavior and let's you specify all accounts including the resolvable ones. +- `accountsStrict`: If you don't want to use account resolution and specify all accounts manually (unchanged). + +This change is likely to result in errors in your existing `.accounts()` calls. To fix, either change `accounts` to `accountsPartial`, or remove all accounts that can be resolved from the IDL. For example: + +```diff +- await program.methods +- .init() +- .accounts({ +- pda: ..., +- signer: ..., +- systemProgram: ..., +- }) +- .rpc(); ++ await program.methods.init().rpc(); +``` + +### Magic account names + +Another change that affects most projects is the removal of "magic" account names. The TS library used to autofill common program and sysvar accounts based on their name, e.g. `systemProgram`, however, this is no longer necessary with the introduction of the `address` field (in the IDL) which is used to resolve all program and sysvars by default. + +### Case conversion + +The internals of the TS library are filled with case conversion logic before making string comparison and this also forces other libraries who build on top of Anchor to do the same. + +Along with making the IDL have consistent casing, TS library also has consistent casing (camelCase) in this release. + +### No more Program ID + +`programId` parameter of `Program` is removed since the new IDL requires to store the program id in its `address` field: + +```diff +- new Program(idl, programId); ++ new Program(idl); +``` + +### Optional provider options + +`opts` parameter of `AnchorProvider` is now optional: + +```diff +- new AnchorProvider(connection, wallet, {}); ++ new AnchorProvider(connection, wallet); +``` + +### Type changes + +There are too many type changes to list here, especially the types that are related to the IDL. The new IDL types can be found [here](https://github.com/coral-xyz/anchor/blob/v0.30.0/ts/packages/anchor/src/idl.ts). + +--- + +See the full list of notable changes in the [CHANGELOG](https://github.com/coral-xyz/anchor/blob/v0.30.0/CHANGELOG.md#0300---2024-04-15). diff --git a/docs/src/pages/release-notes/0.30.1.md b/docs/src/pages/release-notes/0.30.1.md new file mode 100644 index 0000000000..c0f0c9cd73 --- /dev/null +++ b/docs/src/pages/release-notes/0.30.1.md @@ -0,0 +1,282 @@ +--- +title: Release Notes 0.30.1 +description: Anchor - Release Notes 0.30.1 +--- + +There are a good number of quality of life improvements in this patch release. You can upgrade to this version from `0.30.0` with ease since there are no major breaking changes. + +--- + +## How to upgrade + +1. Update `anchor-cli`: + + ```sh + avm install 0.30.1 + ``` + +2. Update Anchor crate(s) to `0.30.1`. + +3. Update TS package(s) to `0.30.1`. + +## Recommended Solana Version + +While this release supports anything above `1.17.3`, the recommended Solana version is `1.18.17`. You can upgrade Solana tools by running: + +``` +solana-install init 1.18.17 +``` + +## IDL + +### Convert legacy IDLs + +A new feature has been added to the IDL crate in order to convert legacy IDLs (pre Anchor v0.30) to new IDLs. + +To programmatically convert legacy IDLs, add: + +``` +anchor-lang-idl = { version = "0.1.1", features = ["convert"] } +``` + +and use the [`convert_idl`](https://docs.rs/anchor-lang-idl/0.1.1/anchor_lang_idl/convert/fn.convert_idl.html) function. + +**NOTE:** This functionality has also been implemented as a CLI command for convenience, see [`idl convert` command](#idl-convert-command). + +### Unsupported seed expressions + +Some seed expressions such as `&(my_account.data + 1).to_le_bytes()`: + +```rs +#[derive(Accounts)] +pub struct SeedMathExpr<'info> { + #[account(seeds = [&(my_account.data + 1).to_le_bytes()], bump)] + pub math_expr_account: UncheckedAccount<'info>, + pub my_account: Account<'info, MyAccount>, +} + +#[account] +pub struct MyAccount { + data: u64, +} +``` + +cannot currently get stored in the IDL, but there was a regression in the IDL generation that resulted in compile errors when using these or similar unsupported expressions. + +They no longer cause compile errors, but this also means that they also cannot get automatically resolved by clients. + +### Fields with `address` constraint + +Using field expressions as an address constraint e.g. + +```rs +#[derive(Accounts)] +pub struct Initialize<'info> { + #[account(address = my_account.authority)] + pub authority: UncheckedAccount<'info>, + pub my_account: Account<'info, MyAccount>, +} + +#[account] +pub struct MyAccount { + authority: u64, +} +``` + +no longer result in a compile error when generating the IDL. + +However, accounts that use the `address` constraint with non-constant values do not currently resolve automatically. For this reason, you might want to consider using the `has_one` constraint instead: + +```rs +#[derive(Accounts)] +pub struct Initialize<'info> { + pub authority: UncheckedAccount<'info>, + #[account(has_one = authority)] + pub my_account: Account<'info, MyAccount>, +} +``` + +### Override `nightly` version on builds + +IDL generation currently uses the `nightly` compiler to build the IDL, and this can potentially result in compile errors on certain `nightly` versions. + +In this release, you can now override the nightly version with `RUSTUP_TOOLCHAIN` env variable. + +### Recursive generation + +There was a compile error during generation with recursive external type resolution, which is now fixed. See [this](https://github.com/coral-xyz/anchor/pull/2946) if you'd like to see the problem in more detail. + +### New spec crate + +Making changes to the IDL crate, e.g. adding features such as the [`convert`](https://github.com/coral-xyz/anchor/pull/2986) feature, would require bumping the version to get the changes even if the spec itself doesn't change. + +To fix this problem, a new [crate](https://docs.rs/anchor-lang-idl-spec) that only includes the IDL spec has been introduced. The new crate's version will be used in the `idl.metadata.spec` field to differentiate between various IDLs. + +**NOTE:** This crate is accesible via the main IDL crate from [`anchor_lang_idl::types`](https://docs.rs/anchor-lang-idl/0.1.1/anchor_lang_idl/types/index.html). + +## CLI + +### `idl convert` command + +This command allows you to convert legacy IDLs with the new `anchor idl convert` command: + +``` +anchor idl convert +``` + +### `idl type` command + +This command creates TypeScript IDL type (with camelCase fields) from an existing IDL file: + +``` +anchor idl type +``` + +### `idl build` toolchain override + +See the [explanation](#override-nightly-version-on-builds) in the IDL section. Example usage with the CLI: + +```sh +RUSTUP_TOOLCHAIN="nightly-2024-05-09" anchor idl build +``` + +### Automatic program id updates + +When building a program for the first time ever, the program id declarations will get automatically updated if there is not a `[programs.localnet]` entry in `Anchor.toml`. + +Note that this is essentially the same as running `anchor keys sync`, only difference being that this will only run once automatically. + +### Upgradeable program clones + +Cloning upgradeable programs with + +```toml +[test.validator] +url = "https://api.mainnet-beta.solana.com" + +[[test.validator.clone]] +address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb" +``` + +would result in unusable programs due to a breaking change in Solana `1.17.12`. + +This problem has been fixed from both Anchor and Solana's side. However, it requires using `solana-cli >=1.18.10`. + +### File system error improvements + +Default Rust error when a file is not found in the file system does not log the file path, which makes it difficult to debug. + +In this release, file system related errors also include the path of the file. + +## Lang + +### Using legacy IDLs with `declare_program!` + +[`declare_program!`](https://www.anchor-lang.com/release-notes/0.30.0#dependency-free-program-declaration) macro can now be used with legacy IDLs (pre Anchor v0.30). + +This works great as long as the program can be described correctly with the legacy IDL spec. However, if a program uses non-default features such as zero copy, or `repr` modifications, the declaration of the program either won't compile, or will be invalid. There are two main solutions in this scenerio: + +- Use the `idl convert` command, and manually fix the invalid parts +- Generate the program's IDL by upgrading the program to Anchor v0.30 + +The latter option is preferred as it's less error-prone. If you have dependency issues while upgrading, simply remove them when generating the IDL since the IDL generation only cares about the signatures, and all program logic, including all dependencies (except Anchor), can be removed when generating the IDL. [Here](https://github.com/coral-xyz/anchor/blob/cc43e67399ad50cf7d33466f7bcd7e6dcee88ae2/ts/packages/spl-token/program/lib.rs) is an example program that you can generate an IDL from. + +In short, IDLs should be preferably generated with v0.30 rather than the conversion method, as a new IDL spec wouldn't be necessary if the old one was sufficient to reliably describe programs. + +### `declare_program!` fixes + +There were a number of cases where the new `declare_program!` would cause a compile error. + +Using the following would result in a compile error: + +- Defined types (e.g. `struct`s) in instruction parameters +- Types with `const` generics +- `Vec` type +- Instruction with a non-unit return type +- Optional accounts (in clients) +- `bytemuckunsafe` account serialization + +Another issue was tuple struct fields were private (Rust default), they are now public. + +### `pubkey!` macro + +[`solana-program`](https://docs.rs/solana-program/1.18.17/solana_program/index.html) has [`pubkey!`](https://docs.rs/solana-program/1.18.17/solana_program/macro.pubkey.html) to easily declare public keys: + +```rs +let key = pubkey!("11111111111111111111111111111111"); +``` + +which is more convenient than `Pubkey::from_str`: + +```rs +use std::str::FromStr; +let key = Pubkey::from_str("11111111111111111111111111111111").unwrap(); +``` + +However, because of how the macro is implemented, it wasn't possible to use it from Anchor without also including `solana-program` to your dependency list as the macro was specifically using `::solana_program`. + +You can now directly use `pubkey!` as it's exported from `anchor_lang::prelude`. + +Note that because `solana_program` is exported from `anchor_lang`, you can also remove `solana-program` dependency from your `Cargo.toml` if `pubkey!` was the reason for adding it. + +### `ID_CONST` constant + +Program ids declared from [`declare_id!`](https://docs.rs/anchor-lang/0.30.1/anchor_lang/macro.declare_id.html) and [`declare_program!`](https://docs.rs/anchor-lang/0.30.1/anchor_lang/macro.declare_program.html) have `ID` declared as `static` which doesn't allow compile time checks. + +Both of these macros now have a new constant (`ID_CONST`), which is essentially the same as `ID`, but is declared as `const` instead of `static`. + +### Stack usage of token extensions + +Stack usage of the new [token extensions constraints](https://www.anchor-lang.com/release-notes/0.30.0#token-extensions) has been improved. + +### Error propagation from integer conversion errors + +You can now propagate integer conversion errors with `?`: + +```rs +let n: i32 = u32::MAX.try_into()?; +``` + +## SPL + +### Export ATA crate + +[`spl-associated-token-account](https://crates.io/crates/spl-associated-token-account) crate is now re-exported from `anchor_spl::associated_token`. + +Similar to how you can [remove](https://www.anchor-lang.com/release-notes/0.29.0#export-mpl-token-metadata) the `mpl-token-metadata` crate from your dependency list, you can also remove `spl-associated-token-accounts` crate. + +```toml +[dependencies] +anchor-spl = "0.30.1" +- spl-associated-token-account = "3.0.2" +``` + +## TypeScript + +### ATA resolution + +The [account resolution](https://www.anchor-lang.com/release-notes/0.30.0#account-resolution) support has been extended to support associated token accounts in this release. + +If you use ATAs in your instruction, you'll get a type error if you call the `accounts` method with those account specified. To solve, simply remove all ATAs from your `accounts` call. + +### Defined types in generics + +Using defined types (structs, enums, or type aliases) as a generic argument e.g. + +```rs +param: GenericStruct, +``` + +no longer results in an error. + +### Versioned transactions + +A problem where `maxSupportedTransactionVersion` was needed, but not being set from `AnchorProvider` has been fixed. + +### New errors package + +Anchor errors have been separated into a new package [`@coral-xyz/anchor-errors`](https://www.npmjs.com/package/@coral-xyz/anchor-errors). + +--- + +See the full list of notable changes in the [CHANGELOG](https://github.com/coral-xyz/anchor/blob/v0.30.1/CHANGELOG.md#0301---2024-06-20). diff --git a/docs/src/pages/docs/changelog.md b/docs/src/pages/release-notes/changelog.md similarity index 82% rename from docs/src/pages/docs/changelog.md rename to docs/src/pages/release-notes/changelog.md index 88b653a96c..de055fa54c 100644 --- a/docs/src/pages/docs/changelog.md +++ b/docs/src/pages/release-notes/changelog.md @@ -8,6 +8,145 @@ The minor version will be incremented upon a breaking change and the patch versi --- +## [0.30.1] - 2024-06-20 + +### Features + +- idl: Allow overriding the idl build toolchain with the `RUSTUP_TOOLCHAIN` environment variable ([#2941](https://github.com/coral-xyz/anchor/pull/2941])). +- avm: Support customizing the installation location using `AVM_HOME` environment variable ([#2917](https://github.com/coral-xyz/anchor/pull/2917)). +- avm: Optimize `avm list` when GitHub API rate limits are reached ([#2962](https://github.com/coral-xyz/anchor/pull/2962)) +- idl, ts: Add accounts resolution for associated token accounts ([#2927](https://github.com/coral-xyz/anchor/pull/2927)). +- cli: Add `--no-install` option to the `init` command ([#2945](https://github.com/coral-xyz/anchor/pull/2945)). +- lang: Implement `TryFromIntError` for `Error` to be able to propagate integer conversion errors ([#2950](https://github.com/coral-xyz/anchor/pull/2950)). +- idl: Add ability to convert legacy IDLs ([#2986](https://github.com/coral-xyz/anchor/pull/2986)). +- ts: Extract Anchor error codes into their own package ([#2983](https://github.com/coral-xyz/anchor/pull/2983)). +- cli: Add additional solana arguments to the `upgrade` command ([#2998](https://github.com/coral-xyz/anchor/pull/2998)). +- spl: Export `spl-associated-token-account` crate ([#2999](https://github.com/coral-xyz/anchor/pull/2999)). +- lang: Support legacy IDLs with `declare_program!` ([#2997](https://github.com/coral-xyz/anchor/pull/2997)). +- cli: Add `idl convert` command ([#3009](https://github.com/coral-xyz/anchor/pull/3009)). +- cli: Add `idl type` command ([#3017](https://github.com/coral-xyz/anchor/pull/3017)). +- lang: Add `anchor_lang::pubkey` macro for declaring `Pubkey` const values ([#3021](https://github.com/coral-xyz/anchor/pull/3021)). +- cli: Sync program ids on the initial build ([#3023](https://github.com/coral-xyz/anchor/pull/3023)). +- idl: Remove `anchor-syn` dependency ([#3030](https://github.com/coral-xyz/anchor/pull/3030)). +- lang: Add `const` of program ID to `declare_id!` and `declare_program!` ([#3019](https://github.com/coral-xyz/anchor/pull/3019)). +- idl: Add separate spec crate ([#3036](https://github.com/coral-xyz/anchor/pull/3036)). + +### Fixes + +- lang: Eliminate variable allocations that build up stack space for token extension code generation ([#2913](https://github.com/coral-xyz/anchor/pull/2913)). +- ts: Fix incorrect `maxSupportedTransactionVersion` in `AnchorProvider.send*()` methods ([#2922](https://github.com/coral-xyz/anchor/pull/2922)). +- cli: Use npm's configured default license for new projects made with `anchor init` ([#2929](https://github.com/coral-xyz/anchor/pull/2929)). +- cli: add filename to 'Unable to read keypair file' errors ([#2932](https://github.com/coral-xyz/anchor/pull/2932)). +- idl: Fix path resolution of the `Cargo.lock` of the project when generating idls for external types ([#2946](https://github.com/coral-xyz/anchor/pull/2946)). +- idl: Fix potential panic on external type resolution ([#2954](https://github.com/coral-xyz/anchor/pull/2954)). +- lang: Fix using defined types in instruction parameters with `declare_program!` ([#2959](https://github.com/coral-xyz/anchor/pull/2959)). +- lang: Fix using const generics with `declare_program!` ([#2965](https://github.com/coral-xyz/anchor/pull/2965)). +- lang: Fix using `Vec` type with `declare_program!` ([#2966](https://github.com/coral-xyz/anchor/pull/2966)). +- lang: Fix `ProgramError::ArithmeticOverflow` not found error ([#2975](https://github.com/coral-xyz/anchor/pull/2975)). +- lang: Fix using optional accounts with `declare_program!` ([#2967](https://github.com/coral-xyz/anchor/pull/2967)). +- lang: Fix instruction return type generation with `declare_program!` ([#2977](https://github.com/coral-xyz/anchor/pull/2977)). +- cli: Fix IDL write getting corrupted from retries ([#2964](https://github.com/coral-xyz/anchor/pull/2964)). +- idl: Fix `unexpected_cfgs` build warning ([#2992](https://github.com/coral-xyz/anchor/pull/2992)). +- lang: Make tuple struct fields public in `declare_program!` ([#2994](https://github.com/coral-xyz/anchor/pull/2994)). +- Remove `rust-version` from crate manifests ([#3000](https://github.com/coral-xyz/anchor/pull/3000)). +- cli: Fix upgradeable program clones ([#3010](https://github.com/coral-xyz/anchor/pull/3010)). +- ts: Fix using IDLs that have defined types as generic arguments ([#3016](https://github.com/coral-xyz/anchor/pull/3016)). +- idl: Fix generation with unsupported expressions ([#3033](https://github.com/coral-xyz/anchor/pull/3033)). +- idl: Fix using `address` constraint with field expressions ([#3034](https://github.com/coral-xyz/anchor/pull/3034)). +- lang: Fix using `bytemuckunsafe` account serialization with `declare_program!` ([#3037](https://github.com/coral-xyz/anchor/pull/3037)). + +### Breaking + +## [0.30.0] - 2024-04-15 + +### Features + +- cli: Allow force `init` and `new` ([#2698](https://github.com/coral-xyz/anchor/pull/2698)). +- cli: Add verifiable option when `deploy` ([#2705](https://github.com/coral-xyz/anchor/pull/2705)). +- cli: Add support for passing arguments to the underlying `solana program deploy` command with `anchor deploy` ([#2709](https://github.com/coral-xyz/anchor/pull/2709)). +- lang: Add `InstructionData::write_to` implementation ([#2733](https://github.com/coral-xyz/anchor/pull/2733)). +- lang: Add `#[interface(..)]` attribute for instruction discriminator overrides ([#2728](https://github.com/coral-xyz/anchor/pull/2728)). +- ts: Add `.interface(..)` method for instruction discriminator overrides ([#2728](https://github.com/coral-xyz/anchor/pull/2728)). +- cli: Check `anchor-lang` and CLI version compatibility ([#2753](https://github.com/coral-xyz/anchor/pull/2753)). +- ts: Add missing IDL PDA seed types ([#2752](https://github.com/coral-xyz/anchor/pull/2752)). +- cli: `idl close` accepts optional `--idl-address` parameter ([#2760](https://github.com/coral-xyz/anchor/pull/2760)). +- cli: Add support for simple wildcard patterns in Anchor.toml's `workspace.members` and `workspace.exclude`. ([#2785](https://github.com/coral-xyz/anchor/pull/2785)). +- cli: Add `--test-template` option for `init` command ([#2805](https://github.com/coral-xyz/anchor/pull/2805)). +- cli: `anchor test` is able to run multiple commands ([#2799](https://github.com/coral-xyz/anchor/pull/2799)). +- cli: Check `@coral-xyz/anchor` package and CLI version compatibility ([#2813](https://github.com/coral-xyz/anchor/pull/2813)). +- cli: Accept package name as program name ([#2816](https://github.com/coral-xyz/anchor/pull/2816)). +- cli: Add ability to build and test only a specified program ([#2823](https://github.com/coral-xyz/anchor/pull/2823)). +- idl: Add new IDL spec ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Add support for `repr`s ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Add support for expression evaluation ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Add support for using external types when generating the IDL ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl, ts: Add unit and tuple struct support ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl, ts: Add generics support ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Add `accountsPartial` method to keep the old `accounts` method behavior ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Make `opts` parameter of `AnchorProvider` constructor optional ([#2843](https://github.com/coral-xyz/anchor/pull/2843)). +- cli: Add `--no-idl` flag to the `build` command ([#2847](https://github.com/coral-xyz/anchor/pull/2847)). +- cli: Add priority fees to idl commands ([#2845](https://github.com/coral-xyz/anchor/pull/2845)). +- ts: Add `prepend` option to MethodBuilder `preInstructions` method ([#2863](https://github.com/coral-xyz/anchor/pull/2863)). +- lang: Add `declare_program!` macro ([#2857](https://github.com/coral-xyz/anchor/pull/2857)). +- cli: Add `deactivate_feature` flag to `solana-test-validator` config in Anchor.toml ([#2872](https://github.com/coral-xyz/anchor/pull/2872)). +- idl: Add `docs` field for constants ([#2887](https://github.com/coral-xyz/anchor/pull/2887)). +- idl: Store deployment addresses for other clusters ([#2892](https://github.com/coral-xyz/anchor/pull/2892)). +- lang: Add `Event` utility type to get events from bytes ([#2897](https://github.com/coral-xyz/anchor/pull/2897)). +- lang, spl: Add support for [token extensions](https://solana.com/solutions/token-extensions) ([#2789](https://github.com/coral-xyz/anchor/pull/2789)). +- lang: Return overflow error from `Lamports` trait operations ([#2907](https://github.com/coral-xyz/anchor/pull/2907)). + +### Fixes + +- syn: Add missing `new_from_array` method to `Hash` ([#2682](https://github.com/coral-xyz/anchor/pull/2682)). +- cli: Switch to Cargo feature resolver(`resolver = "2"`) ([#2676](https://github.com/coral-xyz/anchor/pull/2676)). +- cli: Fix using user specific path for `provider.wallet` in `Anchor.toml` ([#2696](https://github.com/coral-xyz/anchor/pull/2696)). +- syn: Fix IDL constant seeds parsing ([#2699](https://github.com/coral-xyz/anchor/pull/2699)). +- cli: Display errors if toolchain override restoration fails ([#2700](https://github.com/coral-xyz/anchor/pull/2700)). +- cli: Fix commit based `anchor_version` override ([#2704](https://github.com/coral-xyz/anchor/pull/2704)). +- spl: Fix compilation with `shmem` feature enabled ([#2722](https://github.com/coral-xyz/anchor/pull/2722)). +- cli: Localhost default test validator address changes from `localhost` to `127.0.0.1`, NodeJS 17 IP resolution changes for IPv6 ([#2725](https://github.com/coral-xyz/anchor/pull/2725)). +- lang: Eliminate temporary Vec allocations when serializing data with discriminant and set the default capacity to 256 bytes ([#2691](https://github.com/coral-xyz/anchor/pull/2691)). +- lang: Allow custom lifetime in Accounts structure ([#2741](https://github.com/coral-xyz/anchor/pull/2741)). +- lang: Remove `try_to_vec` usage while setting the return data in order to reduce heap memory usage ([#2744](https://github.com/coral-xyz/anchor/pull/2744)) +- cli: Show installation progress if Solana tools are not installed when using toolchain overrides ([#2757](https://github.com/coral-xyz/anchor/pull/2757)). +- ts: Fix formatting enums ([#2763](https://github.com/coral-xyz/anchor/pull/2763)). +- cli: Fix `migrate` command not working without global `ts-node` installation ([#2767](https://github.com/coral-xyz/anchor/pull/2767)). +- client, lang, spl, syn: Enable all features for docs.rs build ([#2774](https://github.com/coral-xyz/anchor/pull/2774)). +- ts: Fix construction of field layouts for type aliased instruction arguments ([#2821](https://github.com/coral-xyz/anchor/pull/2821)) +- idl: Fix IDL ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl, ts: Make casing consistent ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Fix not being able to use numbers in instruction, account, or event names in some cases due to case conversion ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- cli: Fix excessive test validator requests ([#2828](https://github.com/coral-xyz/anchor/pull/2828)). +- client: Fix `parse_logs_response` to prevent panics when more than 1 outer instruction exists in logs ([#2856](https://github.com/coral-xyz/anchor/pull/2856)). +- avm, cli: Fix `stdsimd` feature compilation error from `ahash` when installing the CLI using newer Rust versions ([#2867](https://github.com/coral-xyz/anchor/pull/2867)). +- spl: Fix not being able to deserialize newer token 2022 extensions ([#2876](https://github.com/coral-xyz/anchor/pull/2876)). +- spl: Remove `solana-program` dependency ([#2900](https://github.com/coral-xyz/anchor/pull/2900)). +- spl: Make `TokenAccount` and ` Mint` `Copy` ([#2904](https://github.com/coral-xyz/anchor/pull/2904)). +- ts: Add missing errors ([#2906](https://github.com/coral-xyz/anchor/pull/2906)). + +### Breaking + +- cli: Make `cargo build-sbf` the default build command ([#2694](https://github.com/coral-xyz/anchor/pull/2694)). +- cli: Require explicit `overflow-checks` flag ([#2716](https://github.com/coral-xyz/anchor/pull/2716)). +- ts: Remove `anchor-deprecated-state` feature ([#2717](https://github.com/coral-xyz/anchor/pull/2717)). +- lang: Remove `CLOSED_ACCOUNT_DISCRIMINATOR` ([#2726](https://github.com/coral-xyz/anchor/pull/2726)). +- lang: Make bumps of optional accounts `Option` rather than `u8` ([#2730](https://github.com/coral-xyz/anchor/pull/2730)). +- spl: Remove `shared-memory` program ([#2747](https://github.com/coral-xyz/anchor/pull/2747)). +- ts: Remove `associated`, `account.associated` and `account.associatedAddress` methods ([#2749](https://github.com/coral-xyz/anchor/pull/2749)). +- cli: `idl upgrade` command closes the IDL buffer account ([#2760](https://github.com/coral-xyz/anchor/pull/2760)). +- cli: Remove `--jest` option from the `init` command ([#2805](https://github.com/coral-xyz/anchor/pull/2805)). +- cli: Require `idl-build` feature in program `Cargo.toml` ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- cli: Rename `seeds` feature to `resolution` and make it enabled by default ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- cli: Remove `idl parse` command ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- idl: Change IDL spec ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- syn: Remove `idl-parse` and `seeds` features ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Change `accounts` method to no longer accept resolvable accounts ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: `Program` instances use camelCase for everything ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Remove discriminator functions ([#2824](https://github.com/coral-xyz/anchor/pull/2824)). +- ts: Remove `programId` parameter of the `Program` constructor ([#2864](https://github.com/coral-xyz/anchor/pull/2864)). +- idl, syn: Move IDL types from the `anchor-syn` crate to the new IDL crate ([#2882](https://github.com/coral-xyz/anchor/pull/2882)). +- idl: Add `#[non_exhaustive]` to IDL enums ([#2890](https://github.com/coral-xyz/anchor/pull/2890)). + ## [0.29.0] - 2023-10-16 ### Features diff --git a/examples/tutorial/basic-0/client.js b/examples/tutorial/basic-0/client.js index a3ce423473..9bfc6c63ec 100644 --- a/examples/tutorial/basic-0/client.js +++ b/examples/tutorial/basic-0/client.js @@ -10,15 +10,10 @@ anchor.setProvider(anchor.AnchorProvider.local()); async function main() { // #region main // Read the generated IDL. - const idl = JSON.parse( - require("fs").readFileSync("./target/idl/basic_0.json", "utf8") - ); - - // Address of the deployed program. - const programId = new anchor.web3.PublicKey(""); + const idl = require("./target/idl/basic_0.json"); // Generate the program client from IDL. - const program = new anchor.Program(idl, programId); + const program = new anchor.Program(idl); // Execute the RPC. await program.rpc.initialize(); diff --git a/examples/tutorial/basic-0/package.json b/examples/tutorial/basic-0/package.json index f41d21f8c7..57b13033bf 100644 --- a/examples/tutorial/basic-0/package.json +++ b/examples/tutorial/basic-0/package.json @@ -1,6 +1,6 @@ { "name": "basic-0", - "version": "0.29.0", + "version": "0.30.1", "license": "(MIT OR Apache-2.0)", "homepage": "https://github.com/coral-xyz/anchor#readme", "bugs": { @@ -14,6 +14,6 @@ "node": ">=11" }, "scripts": { - "test": "anchor test --skip-lint" + "test": "anchor test --skip-lint && anchor clean" } } diff --git a/examples/tutorial/basic-0/programs/basic-0/Cargo.toml b/examples/tutorial/basic-0/programs/basic-0/Cargo.toml index c980c51854..d0351ecab3 100644 --- a/examples/tutorial/basic-0/programs/basic-0/Cargo.toml +++ b/examples/tutorial/basic-0/programs/basic-0/Cargo.toml @@ -2,7 +2,6 @@ name = "basic-0" version = "0.1.0" description = "Created with Anchor" -rust-version = "1.60" edition = "2021" [lib] @@ -12,6 +11,7 @@ name = "basic_0" [features] no-entrypoint = [] cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = { path = "../../../../../lang" } diff --git a/examples/tutorial/basic-1/package.json b/examples/tutorial/basic-1/package.json index 1161d3e672..349ee92fa2 100644 --- a/examples/tutorial/basic-1/package.json +++ b/examples/tutorial/basic-1/package.json @@ -1,6 +1,6 @@ { "name": "basic-1", - "version": "0.29.0", + "version": "0.30.1", "license": "(MIT OR Apache-2.0)", "homepage": "https://github.com/coral-xyz/anchor#readme", "bugs": { @@ -14,6 +14,6 @@ "node": ">=11" }, "scripts": { - "test": "anchor test --skip-lint" + "test": "anchor test --skip-lint && anchor clean" } } diff --git a/examples/tutorial/basic-1/programs/basic-1/Cargo.toml b/examples/tutorial/basic-1/programs/basic-1/Cargo.toml index e207669643..ffa64c0088 100644 --- a/examples/tutorial/basic-1/programs/basic-1/Cargo.toml +++ b/examples/tutorial/basic-1/programs/basic-1/Cargo.toml @@ -2,7 +2,6 @@ name = "basic-1" version = "0.1.0" description = "Created with Anchor" -rust-version = "1.60" edition = "2021" [lib] @@ -12,6 +11,7 @@ name = "basic_1" [features] no-entrypoint = [] cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = { path = "../../../../../lang" } diff --git a/examples/tutorial/basic-2/package.json b/examples/tutorial/basic-2/package.json index 9bd7cdcc0e..7e63322454 100644 --- a/examples/tutorial/basic-2/package.json +++ b/examples/tutorial/basic-2/package.json @@ -1,6 +1,6 @@ { "name": "basic-2", - "version": "0.29.0", + "version": "0.30.1", "license": "(MIT OR Apache-2.0)", "homepage": "https://github.com/coral-xyz/anchor#readme", "bugs": { @@ -14,6 +14,6 @@ "node": ">=11" }, "scripts": { - "test": "anchor test --skip-lint" + "test": "anchor test --skip-lint && anchor clean" } } diff --git a/examples/tutorial/basic-2/programs/basic-2/Cargo.toml b/examples/tutorial/basic-2/programs/basic-2/Cargo.toml index dae5ea4345..0f6c4be4ef 100644 --- a/examples/tutorial/basic-2/programs/basic-2/Cargo.toml +++ b/examples/tutorial/basic-2/programs/basic-2/Cargo.toml @@ -2,7 +2,6 @@ name = "basic-2" version = "0.1.0" description = "Created with Anchor" -rust-version = "1.60" edition = "2021" [lib] @@ -12,6 +11,7 @@ name = "basic_2" [features] no-entrypoint = [] cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = { path = "../../../../../lang" } diff --git a/examples/tutorial/basic-3/package.json b/examples/tutorial/basic-3/package.json index b0f7f320bb..2f4763adf5 100644 --- a/examples/tutorial/basic-3/package.json +++ b/examples/tutorial/basic-3/package.json @@ -1,6 +1,6 @@ { "name": "basic-3", - "version": "0.29.0", + "version": "0.30.1", "license": "(MIT OR Apache-2.0)", "homepage": "https://github.com/coral-xyz/anchor#readme", "bugs": { @@ -14,6 +14,6 @@ "node": ">=11" }, "scripts": { - "test": "anchor test --skip-lint" + "test": "anchor test --skip-lint && anchor clean" } } diff --git a/examples/tutorial/basic-3/programs/puppet-master/Cargo.toml b/examples/tutorial/basic-3/programs/puppet-master/Cargo.toml index 04b3e044d3..11e7a27def 100644 --- a/examples/tutorial/basic-3/programs/puppet-master/Cargo.toml +++ b/examples/tutorial/basic-3/programs/puppet-master/Cargo.toml @@ -2,7 +2,6 @@ name = "puppet-master" version = "0.1.0" description = "Created with Anchor" -rust-version = "1.60" edition = "2021" [lib] @@ -12,6 +11,7 @@ name = "puppet_master" [features] no-entrypoint = [] cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = { path = "../../../../../lang" } diff --git a/examples/tutorial/basic-3/programs/puppet/Cargo.toml b/examples/tutorial/basic-3/programs/puppet/Cargo.toml index 862457316a..59a21b092f 100644 --- a/examples/tutorial/basic-3/programs/puppet/Cargo.toml +++ b/examples/tutorial/basic-3/programs/puppet/Cargo.toml @@ -2,7 +2,6 @@ name = "puppet" version = "0.1.0" description = "Created with Anchor" -rust-version = "1.60" edition = "2021" [lib] @@ -12,6 +11,7 @@ name = "puppet" [features] no-entrypoint = [] cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = { path = "../../../../../lang" } diff --git a/examples/tutorial/basic-4/package.json b/examples/tutorial/basic-4/package.json index 26f322cb6f..e162df60a2 100644 --- a/examples/tutorial/basic-4/package.json +++ b/examples/tutorial/basic-4/package.json @@ -1,6 +1,6 @@ { "name": "basic-4", - "version": "0.29.0", + "version": "0.30.1", "license": "(MIT OR Apache-2.0)", "homepage": "https://github.com/coral-xyz/anchor#readme", "bugs": { @@ -14,6 +14,6 @@ "node": ">=11" }, "scripts": { - "test": "anchor test --skip-lint" + "test": "anchor test --skip-lint && anchor clean" } } diff --git a/examples/tutorial/basic-4/programs/basic-4/Cargo.toml b/examples/tutorial/basic-4/programs/basic-4/Cargo.toml index 3a143035cc..f53edb8083 100644 --- a/examples/tutorial/basic-4/programs/basic-4/Cargo.toml +++ b/examples/tutorial/basic-4/programs/basic-4/Cargo.toml @@ -2,7 +2,6 @@ name = "basic-4" version = "0.1.0" description = "Created with Anchor" -rust-version = "1.60" edition = "2021" [lib] @@ -12,6 +11,7 @@ name = "basic_4" [features] no-entrypoint = [] cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = { path = "../../../../../lang" } diff --git a/examples/tutorial/basic-5/package.json b/examples/tutorial/basic-5/package.json index f1c4511fee..4455561c29 100644 --- a/examples/tutorial/basic-5/package.json +++ b/examples/tutorial/basic-5/package.json @@ -1,19 +1,19 @@ { - "name": "basic-5", - "version": "0.29.0", - "license": "(MIT OR Apache-2.0)", - "homepage": "https://github.com/coral-xyz/anchor#readme", - "bugs": { - "url": "https://github.com/coral-xyz/anchor/issues" - }, - "repository": { - "type": "git", - "url": "https://github.com/coral-xyz/anchor.git" - }, - "engines": { - "node": ">=11" - }, - "scripts": { - "test": "anchor test --skip-lint" - } - } \ No newline at end of file + "name": "basic-5", + "version": "0.30.1", + "license": "(MIT OR Apache-2.0)", + "homepage": "https://github.com/coral-xyz/anchor#readme", + "bugs": { + "url": "https://github.com/coral-xyz/anchor/issues" + }, + "repository": { + "type": "git", + "url": "https://github.com/coral-xyz/anchor.git" + }, + "engines": { + "node": ">=11" + }, + "scripts": { + "test": "anchor test --skip-lint && anchor clean" + } +} diff --git a/examples/tutorial/basic-5/programs/basic-5/Cargo.toml b/examples/tutorial/basic-5/programs/basic-5/Cargo.toml index 8b5ee1f8e3..8b3b32d01b 100644 --- a/examples/tutorial/basic-5/programs/basic-5/Cargo.toml +++ b/examples/tutorial/basic-5/programs/basic-5/Cargo.toml @@ -2,7 +2,6 @@ name = "basic-5" version = "0.1.0" description = "Created with Anchor" -rust-version = "1.60" edition = "2021" [lib] @@ -12,6 +11,7 @@ name = "basic_5" [features] no-entrypoint = [] cpi = ["no-entrypoint"] +idl-build = ["anchor-lang/idl-build"] [dependencies] anchor-lang = { path = "../../../../../lang" } \ No newline at end of file diff --git a/examples/tutorial/basic-5/programs/basic-5/src/lib.rs b/examples/tutorial/basic-5/programs/basic-5/src/lib.rs index 03542a69c3..a8a4147fda 100644 --- a/examples/tutorial/basic-5/programs/basic-5/src/lib.rs +++ b/examples/tutorial/basic-5/programs/basic-5/src/lib.rs @@ -61,7 +61,7 @@ pub struct Create<'info> { bump )] pub action_state: Account<'info, ActionState>, - // mut makes it changeble (mutable) + // mut makes it changeable (mutable) #[account(mut)] pub user: Signer<'info>, pub system_program: Program<'info, System>, @@ -72,7 +72,7 @@ pub struct Walk<'info> { // Only the user on account action_state, should be able to change state #[account(mut, has_one = user)] pub action_state: Account<'info, ActionState>, - // mut makes it changeble (mutable) + // mut makes it changeable (mutable) #[account(mut)] pub user: Signer<'info>, } @@ -82,7 +82,7 @@ pub struct Run<'info> { // Only the user on account action_state, should be able to change state #[account(mut, has_one = user)] pub action_state: Account<'info, ActionState>, - // mut makes it changeble (mutable) + // mut makes it changeable (mutable) #[account(mut)] pub user: Signer<'info>, } @@ -92,7 +92,7 @@ pub struct Jump<'info> { // Only the user on account action_state, should be able to change state #[account(mut, has_one = user)] pub action_state: Account<'info, ActionState>, - // mut makes it changeble (mutable) + // mut makes it changeable (mutable) #[account(mut)] pub user: Signer<'info>, } @@ -102,7 +102,7 @@ pub struct Reset<'info> { // Only the user on account action_state, should be able to change state #[account(mut, has_one = user)] pub action_state: Account<'info, ActionState>, - // mut makes it changeble (mutable) + // mut makes it changeable (mutable) #[account(mut)] pub user: Signer<'info>, } diff --git a/examples/tutorial/basic-5/tests/basic-5.ts b/examples/tutorial/basic-5/tests/basic-5.ts index 4433f420ae..b19f6da7ea 100644 --- a/examples/tutorial/basic-5/tests/basic-5.ts +++ b/examples/tutorial/basic-5/tests/basic-5.ts @@ -113,7 +113,7 @@ describe("basic-5", () => { ); } - console.log("🎉 Transaction Succesfully Confirmed!"); + console.log("🎉 Transaction Successfully Confirmed!"); let result = await program.account.actionState.fetch(actionState); console.log("Robot action state details: ", result); } diff --git a/idl/Cargo.toml b/idl/Cargo.toml new file mode 100644 index 0000000000..82f218f148 --- /dev/null +++ b/idl/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "anchor-lang-idl" +version = "0.1.1" +authors = ["Anchor Maintainers "] +repository = "https://github.com/coral-xyz/anchor" +edition = "2021" +license = "Apache-2.0" +description = "Anchor framework IDL" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[features] +build = ["regex"] +convert = ["heck", "sha2"] + +[dependencies] +anchor-lang-idl-spec = { path = "./spec", version = "0.1.0" } +anyhow = "1" +serde = { version = "1", features = ["derive"] } +serde_json = "1" + +# `build` feature only +regex = { version = "1", optional = true } + +# `convert` feature only +heck = { version = "0.3", optional = true } +sha2 = { version = "0.10", optional = true } diff --git a/idl/spec/Cargo.toml b/idl/spec/Cargo.toml new file mode 100644 index 0000000000..db7966683f --- /dev/null +++ b/idl/spec/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "anchor-lang-idl-spec" +version = "0.1.0" +authors = ["Anchor Maintainers "] +repository = "https://github.com/coral-xyz/anchor" +edition = "2021" +license = "Apache-2.0" +description = "Anchor framework IDL spec" + +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[dependencies] +anyhow = "1" +serde = { version = "1", features = ["derive"] } diff --git a/idl/spec/src/lib.rs b/idl/spec/src/lib.rs new file mode 100644 index 0000000000..d1fb0b0e65 --- /dev/null +++ b/idl/spec/src/lib.rs @@ -0,0 +1,502 @@ +use std::str::FromStr; + +use anyhow::anyhow; +use serde::{Deserialize, Serialize}; + +/// IDL specification Semantic Version +pub const IDL_SPEC: &str = env!("CARGO_PKG_VERSION"); + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct Idl { + pub address: String, + pub metadata: IdlMetadata, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + pub instructions: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub accounts: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub events: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub errors: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub types: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub constants: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlMetadata { + pub name: String, + pub version: String, + pub spec: String, + #[serde(skip_serializing_if = "is_default")] + pub description: Option, + #[serde(skip_serializing_if = "is_default")] + pub repository: Option, + #[serde(default, skip_serializing_if = "is_default")] + pub dependencies: Vec, + #[serde(skip_serializing_if = "is_default")] + pub contact: Option, + #[serde(skip_serializing_if = "is_default")] + pub deployments: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlDependency { + pub name: String, + pub version: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlDeployments { + pub mainnet: Option, + pub testnet: Option, + pub devnet: Option, + pub localnet: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlInstruction { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + pub discriminator: IdlDiscriminator, + pub accounts: Vec, + pub args: Vec, + #[serde(skip_serializing_if = "is_default")] + pub returns: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum IdlInstructionAccountItem { + Composite(IdlInstructionAccounts), + Single(IdlInstructionAccount), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlInstructionAccount { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub writable: bool, + #[serde(default, skip_serializing_if = "is_default")] + pub signer: bool, + #[serde(default, skip_serializing_if = "is_default")] + pub optional: bool, + #[serde(skip_serializing_if = "is_default")] + pub address: Option, + #[serde(skip_serializing_if = "is_default")] + pub pda: Option, + #[serde(default, skip_serializing_if = "is_default")] + pub relations: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlInstructionAccounts { + pub name: String, + pub accounts: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlPda { + pub seeds: Vec, + #[serde(skip_serializing_if = "is_default")] + pub program: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlSeed { + Const(IdlSeedConst), + Arg(IdlSeedArg), + Account(IdlSeedAccount), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlSeedConst { + pub value: Vec, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlSeedArg { + pub path: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlSeedAccount { + pub path: String, + #[serde(skip_serializing_if = "is_default")] + pub account: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlAccount { + pub name: String, + pub discriminator: IdlDiscriminator, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlEvent { + pub name: String, + pub discriminator: IdlDiscriminator, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlConst { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + #[serde(rename = "type")] + pub ty: IdlType, + pub value: String, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] +pub struct IdlErrorCode { + pub code: u32, + pub name: String, + #[serde(skip_serializing_if = "is_default")] + pub msg: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlField { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + #[serde(rename = "type")] + pub ty: IdlType, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlTypeDef { + pub name: String, + #[serde(default, skip_serializing_if = "is_default")] + pub docs: Vec, + #[serde(default, skip_serializing_if = "is_default")] + pub serialization: IdlSerialization, + #[serde(skip_serializing_if = "is_default")] + pub repr: Option, + #[serde(default, skip_serializing_if = "is_default")] + pub generics: Vec, + #[serde(rename = "type")] + pub ty: IdlTypeDefTy, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Default)] +#[serde(rename_all = "lowercase")] +#[non_exhaustive] +pub enum IdlSerialization { + #[default] + Borsh, + Bytemuck, + BytemuckUnsafe, + Custom(String), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +#[non_exhaustive] +pub enum IdlRepr { + Rust(IdlReprModifier), + C(IdlReprModifier), + Transparent, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlReprModifier { + #[serde(default, skip_serializing_if = "is_default")] + pub packed: bool, + #[serde(skip_serializing_if = "is_default")] + pub align: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlTypeDefGeneric { + Type { + name: String, + }, + Const { + name: String, + #[serde(rename = "type")] + ty: String, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlTypeDefTy { + Struct { + #[serde(skip_serializing_if = "is_default")] + fields: Option, + }, + Enum { + variants: Vec, + }, + Type { + alias: IdlType, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +pub struct IdlEnumVariant { + pub name: String, + #[serde(skip_serializing_if = "is_default")] + pub fields: Option, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(untagged)] +pub enum IdlDefinedFields { + Named(Vec), + Tuple(Vec), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +pub enum IdlArrayLen { + Generic(String), + #[serde(untagged)] + Value(usize), +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum IdlGenericArg { + Type { + #[serde(rename = "type")] + ty: IdlType, + }, + Const { + value: String, + }, +} + +#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] +#[serde(rename_all = "lowercase")] +#[non_exhaustive] +pub enum IdlType { + Bool, + U8, + I8, + U16, + I16, + U32, + I32, + F32, + U64, + I64, + F64, + U128, + I128, + U256, + I256, + Bytes, + String, + Pubkey, + Option(Box), + Vec(Box), + Array(Box, IdlArrayLen), + Defined { + name: String, + #[serde(default, skip_serializing_if = "is_default")] + generics: Vec, + }, + Generic(String), +} + +// TODO: Move to utils crate +impl FromStr for IdlType { + type Err = anyhow::Error; + + fn from_str(s: &str) -> Result { + let mut s = s.to_owned(); + s.retain(|c| !c.is_whitespace()); + + let r = match s.as_str() { + "bool" => IdlType::Bool, + "u8" => IdlType::U8, + "i8" => IdlType::I8, + "u16" => IdlType::U16, + "i16" => IdlType::I16, + "u32" => IdlType::U32, + "i32" => IdlType::I32, + "f32" => IdlType::F32, + "u64" => IdlType::U64, + "i64" => IdlType::I64, + "f64" => IdlType::F64, + "u128" => IdlType::U128, + "i128" => IdlType::I128, + "u256" => IdlType::U256, + "i256" => IdlType::I256, + "Vec" => IdlType::Bytes, + "String" | "&str" | "&'staticstr" => IdlType::String, + "Pubkey" => IdlType::Pubkey, + _ => { + if let Some(inner) = s.strip_prefix("Option<") { + let inner_ty = Self::from_str( + inner + .strip_suffix('>') + .ok_or_else(|| anyhow!("Invalid Option"))?, + )?; + return Ok(IdlType::Option(Box::new(inner_ty))); + } + + if let Some(inner) = s.strip_prefix("Vec<") { + let inner_ty = Self::from_str( + inner + .strip_suffix('>') + .ok_or_else(|| anyhow!("Invalid Vec"))?, + )?; + return Ok(IdlType::Vec(Box::new(inner_ty))); + } + + if s.starts_with('[') { + fn array_from_str(inner: &str) -> IdlType { + match inner.strip_suffix(']') { + Some(nested_inner) => array_from_str(&nested_inner[1..]), + None => { + let (raw_type, raw_length) = inner.rsplit_once(';').unwrap(); + let ty = IdlType::from_str(raw_type).unwrap(); + let len = match raw_length.replace('_', "").parse::() { + Ok(len) => IdlArrayLen::Value(len), + Err(_) => IdlArrayLen::Generic(raw_length.to_owned()), + }; + IdlType::Array(Box::new(ty), len) + } + } + } + return Ok(array_from_str(&s)); + } + + // Defined + let (name, generics) = if let Some(i) = s.find('<') { + ( + s.get(..i).unwrap().to_owned(), + s.get(i + 1..) + .unwrap() + .strip_suffix('>') + .unwrap() + .split(',') + .map(|g| g.trim().to_owned()) + .map(|g| { + if g.parse::().is_ok() + || g.parse::().is_ok() + || g.parse::().is_ok() + || g.parse::().is_ok() + { + Ok(IdlGenericArg::Const { value: g }) + } else { + Self::from_str(&g).map(|ty| IdlGenericArg::Type { ty }) + } + }) + .collect::, _>>()?, + ) + } else { + (s.to_owned(), vec![]) + }; + + IdlType::Defined { name, generics } + } + }; + Ok(r) + } +} + +pub type IdlDiscriminator = Vec; + +/// Get whether the given data is the default of its type. +fn is_default(it: &T) -> bool { + *it == T::default() +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn option() { + assert_eq!( + IdlType::from_str("Option").unwrap(), + IdlType::Option(Box::new(IdlType::Bool)) + ) + } + + #[test] + fn vector() { + assert_eq!( + IdlType::from_str("Vec").unwrap(), + IdlType::Vec(Box::new(IdlType::Bool)) + ) + } + + #[test] + fn array() { + assert_eq!( + IdlType::from_str("[Pubkey; 16]").unwrap(), + IdlType::Array(Box::new(IdlType::Pubkey), IdlArrayLen::Value(16)) + ); + } + + #[test] + fn array_with_underscored_length() { + assert_eq!( + IdlType::from_str("[u8; 50_000]").unwrap(), + IdlType::Array(Box::new(IdlType::U8), IdlArrayLen::Value(50000)) + ); + } + + #[test] + fn multidimensional_array() { + assert_eq!( + IdlType::from_str("[[u8; 16]; 32]").unwrap(), + IdlType::Array( + Box::new(IdlType::Array( + Box::new(IdlType::U8), + IdlArrayLen::Value(16) + )), + IdlArrayLen::Value(32) + ) + ); + } + + #[test] + fn generic_array() { + assert_eq!( + IdlType::from_str("[u64; T]").unwrap(), + IdlType::Array(Box::new(IdlType::U64), IdlArrayLen::Generic("T".into())) + ); + } + + #[test] + fn defined() { + assert_eq!( + IdlType::from_str("MyStruct").unwrap(), + IdlType::Defined { + name: "MyStruct".into(), + generics: vec![] + } + ) + } + + #[test] + fn defined_with_generics() { + assert_eq!( + IdlType::from_str("MyStruct").unwrap(), + IdlType::Defined { + name: "MyStruct".into(), + generics: vec![ + IdlGenericArg::Type { + ty: IdlType::Pubkey + }, + IdlGenericArg::Type { ty: IdlType::U64 }, + IdlGenericArg::Const { value: "8".into() }, + ], + } + ) + } +} diff --git a/idl/src/build.rs b/idl/src/build.rs new file mode 100644 index 0000000000..0dcc18c0bb --- /dev/null +++ b/idl/src/build.rs @@ -0,0 +1,348 @@ +use std::{ + collections::BTreeMap, + env, mem, + path::Path, + process::{Command, Stdio}, +}; + +use anyhow::{anyhow, Result}; +use regex::Regex; +use serde::Deserialize; + +use crate::types::{Idl, IdlEvent, IdlTypeDef}; + +/// A trait that types must implement in order to include the type in the IDL definition. +/// +/// This trait is automatically implemented for Anchor all types that use the `AnchorSerialize` +/// proc macro. Note that manually implementing the `AnchorSerialize` trait does **NOT** have the +/// same effect. +/// +/// Types that don't implement this trait will cause a compile error during the IDL generation. +/// +/// The default implementation of the trait allows the program to compile but the type does **NOT** +/// get included in the IDL. +pub trait IdlBuild { + /// Create an IDL type definition for the type. + /// + /// The type is only included in the IDL if this method returns `Some`. + fn create_type() -> Option { + None + } + + /// Insert all types that are included in the current type definition to the given map. + fn insert_types(_types: &mut BTreeMap) {} + + /// Get the full module path of the type. + /// + /// The full path will be used in the case of a conflicting type definition, e.g. when there + /// are multiple structs with the same name. + /// + /// The default implementation covers most cases. + fn get_full_path() -> String { + std::any::type_name::().into() + } +} + +/// Generate IDL via compilation. +pub fn build_idl( + program_path: impl AsRef, + resolution: bool, + skip_lint: bool, + no_docs: bool, +) -> Result { + build_idl_with_cargo_args(program_path, resolution, skip_lint, no_docs, &[]) +} + +/// Generate IDL via compilation with passing cargo arguments. +pub fn build_idl_with_cargo_args( + program_path: impl AsRef, + resolution: bool, + skip_lint: bool, + no_docs: bool, + cargo_args: &[String], +) -> Result { + let idl = build( + program_path.as_ref(), + resolution, + skip_lint, + no_docs, + cargo_args, + )?; + let idl = convert_module_paths(idl); + let idl = sort(idl); + verify(&idl)?; + + Ok(idl) +} + +/// Build IDL. +fn build( + program_path: &Path, + resolution: bool, + skip_lint: bool, + no_docs: bool, + cargo_args: &[String], +) -> Result { + // `nightly` toolchain is currently required for building the IDL. + let toolchain = std::env::var("RUSTUP_TOOLCHAIN") + .map(|toolchain| format!("+{}", toolchain)) + .unwrap_or_else(|_| "+nightly".to_string()); + + install_toolchain_if_needed(&toolchain)?; + let output = Command::new("cargo") + .args([ + &toolchain, + "test", + "__anchor_private_print_idl", + "--features", + "idl-build", + ]) + .args(cargo_args) + .args(["--", "--show-output", "--quiet"]) + .env( + "ANCHOR_IDL_BUILD_NO_DOCS", + if no_docs { "TRUE" } else { "FALSE" }, + ) + .env( + "ANCHOR_IDL_BUILD_RESOLUTION", + if resolution { "TRUE" } else { "FALSE" }, + ) + .env( + "ANCHOR_IDL_BUILD_SKIP_LINT", + if skip_lint { "TRUE" } else { "FALSE" }, + ) + .env("ANCHOR_IDL_BUILD_PROGRAM_PATH", program_path) + .env("RUSTFLAGS", "--cfg procmacro2_semver_exempt") + .current_dir(program_path) + .stderr(Stdio::inherit()) + .output()?; + if !output.status.success() { + return Err(anyhow!("Building IDL failed")); + } + + enum State { + Pass, + Address, + Constants(Vec), + Events(Vec), + Errors(Vec), + Program(Vec), + } + + let mut address = String::new(); + let mut events = vec![]; + let mut error_codes = vec![]; + let mut constants = vec![]; + let mut types = BTreeMap::new(); + let mut idl: Option = None; + + let output = String::from_utf8_lossy(&output.stdout); + if env::var("ANCHOR_LOG").is_ok() { + println!("{}", output); + } + + let mut state = State::Pass; + for line in output.lines() { + match &mut state { + State::Pass => match line { + "--- IDL begin address ---" => state = State::Address, + "--- IDL begin const ---" => state = State::Constants(vec![]), + "--- IDL begin event ---" => state = State::Events(vec![]), + "--- IDL begin errors ---" => state = State::Errors(vec![]), + "--- IDL begin program ---" => state = State::Program(vec![]), + _ => { + if line.starts_with("test result: ok") + && !line.starts_with("test result: ok. 0 passed; 0 failed; 0") + { + if let Some(idl) = idl.as_mut() { + idl.address = mem::take(&mut address); + idl.constants = mem::take(&mut constants); + idl.events = mem::take(&mut events); + idl.errors = mem::take(&mut error_codes); + idl.types = { + let prog_ty = mem::take(&mut idl.types); + let mut types = mem::take(&mut types); + types.extend(prog_ty.into_iter().map(|ty| (ty.name.clone(), ty))); + types.into_values().collect() + }; + } + } + } + }, + State::Address => { + address = line.replace(|c: char| !c.is_alphanumeric(), ""); + state = State::Pass; + continue; + } + State::Constants(lines) => { + if line == "--- IDL end const ---" { + let constant = serde_json::from_str(&lines.join("\n"))?; + constants.push(constant); + state = State::Pass; + continue; + } + + lines.push(line.to_owned()); + } + State::Events(lines) => { + if line == "--- IDL end event ---" { + #[derive(Deserialize)] + struct IdlBuildEventPrint { + event: IdlEvent, + types: Vec, + } + + let event = serde_json::from_str::(&lines.join("\n"))?; + events.push(event.event); + types.extend(event.types.into_iter().map(|ty| (ty.name.clone(), ty))); + state = State::Pass; + continue; + } + + lines.push(line.to_owned()); + } + State::Errors(lines) => { + if line == "--- IDL end errors ---" { + error_codes = serde_json::from_str(&lines.join("\n"))?; + state = State::Pass; + continue; + } + + lines.push(line.to_owned()); + } + State::Program(lines) => { + if line == "--- IDL end program ---" { + idl = Some(serde_json::from_str(&lines.join("\n"))?); + state = State::Pass; + continue; + } + + lines.push(line.to_owned()); + } + } + } + + idl.ok_or_else(|| anyhow!("IDL doesn't exist")) +} + +/// Install the given toolchain if it's not already installed. +fn install_toolchain_if_needed(toolchain: &str) -> Result<()> { + let is_installed = Command::new("cargo") + .arg(toolchain) + .output()? + .status + .success(); + if !is_installed { + Command::new("rustup") + .args(["toolchain", "install", toolchain.trim_start_matches('+')]) + .spawn()? + .wait()?; + } + + Ok(()) +} + +/// Convert paths to name if there are no conflicts. +fn convert_module_paths(idl: Idl) -> Idl { + let idl = serde_json::to_string(&idl).unwrap(); + let idl = Regex::new(r#""((\w+::)+)(\w+)""#) + .unwrap() + .captures_iter(&idl.clone()) + .fold(idl, |acc, cur| { + let path = cur.get(0).unwrap().as_str(); + let name = cur.get(3).unwrap().as_str(); + + // Replace path with name + let replaced_idl = acc.replace(path, &format!(r#""{name}""#)); + + // Check whether there is a conflict + let has_conflict = replaced_idl.contains(&format!(r#"::{name}""#)); + if has_conflict { + acc + } else { + replaced_idl + } + }); + + serde_json::from_str(&idl).expect("Invalid IDL") +} + +/// Alphabetically sort fields for consistency. +fn sort(mut idl: Idl) -> Idl { + idl.accounts.sort_by(|a, b| a.name.cmp(&b.name)); + idl.constants.sort_by(|a, b| a.name.cmp(&b.name)); + idl.events.sort_by(|a, b| a.name.cmp(&b.name)); + idl.instructions.sort_by(|a, b| a.name.cmp(&b.name)); + idl.types.sort_by(|a, b| a.name.cmp(&b.name)); + + idl +} + +/// Verify IDL is valid. +fn verify(idl: &Idl) -> Result<()> { + // Check full path accounts + if let Some(account) = idl + .accounts + .iter() + .find(|account| account.name.contains("::")) + { + return Err(anyhow!( + "Conflicting accounts names are not allowed.\nProgram: `{}`\nAccount: `{}`", + idl.metadata.name, + account.name + )); + } + + // Check empty discriminators + macro_rules! check_empty_discriminators { + ($field:ident) => { + if let Some(item) = idl.$field.iter().find(|it| it.discriminator.is_empty()) { + return Err(anyhow!( + "Empty discriminators are not allowed for {}: `{}`", + stringify!($field), + item.name + )); + } + }; + } + check_empty_discriminators!(accounts); + check_empty_discriminators!(events); + check_empty_discriminators!(instructions); + + // Check potential discriminator collisions + macro_rules! check_discriminator_collision { + ($field:ident) => { + if let Some((outer, inner)) = idl.$field.iter().find_map(|outer| { + idl.$field + .iter() + .filter(|inner| inner.name != outer.name) + .find(|inner| outer.discriminator.starts_with(&inner.discriminator)) + .map(|inner| (outer, inner)) + }) { + return Err(anyhow!( + "Ambiguous discriminators for {} `{}` and `{}`", + stringify!($field), + outer.name, + inner.name + )); + } + }; + } + check_discriminator_collision!(accounts); + check_discriminator_collision!(events); + check_discriminator_collision!(instructions); + + // Disallow all zero account discriminators + if let Some(account) = idl + .accounts + .iter() + .find(|acc| acc.discriminator.iter().all(|b| *b == 0)) + { + return Err(anyhow!( + "All zero account discriminators are not allowed (account: `{}`)", + account.name + )); + } + + Ok(()) +} diff --git a/idl/src/convert.rs b/idl/src/convert.rs new file mode 100644 index 0000000000..0aeef4c795 --- /dev/null +++ b/idl/src/convert.rs @@ -0,0 +1,558 @@ +use anyhow::{anyhow, Result}; + +use crate::types::Idl; + +/// Create an [`Idl`] value with additional support for older specs based on the +/// `idl.metadata.spec` field. +/// +/// If `spec` field is not specified, the conversion will fallback to the legacy IDL spec +/// (pre Anchor v0.30). +/// +/// **Note:** For legacy IDLs, `idl.metadata.address` field is required to be populated with +/// program's address otherwise an error will be returned. +pub fn convert_idl(idl: &[u8]) -> Result { + let value = serde_json::from_slice::(idl)?; + let spec = value + .get("metadata") + .and_then(|m| m.get("spec")) + .and_then(|spec| spec.as_str()); + match spec { + // New standard + Some(spec) => match spec { + "0.1.0" => serde_json::from_value(value).map_err(Into::into), + _ => Err(anyhow!("IDL spec not supported: `{spec}`")), + }, + // Legacy + None => serde_json::from_value::(value).map(TryInto::try_into)?, + } +} + +/// Legacy IDL spec (pre Anchor v0.30) +mod legacy { + use crate::types as t; + use anyhow::{anyhow, Result}; + use heck::SnakeCase; + use serde::{Deserialize, Serialize}; + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct Idl { + pub version: String, + pub name: String, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub docs: Option>, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub constants: Vec, + pub instructions: Vec, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub accounts: Vec, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub types: Vec, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub events: Option>, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub errors: Option>, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub metadata: Option, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlConst { + pub name: String, + #[serde(rename = "type")] + pub ty: IdlType, + pub value: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlState { + #[serde(rename = "struct")] + pub strct: IdlTypeDefinition, + pub methods: Vec, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlInstruction { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub docs: Option>, + pub accounts: Vec, + pub args: Vec, + #[serde(skip_serializing_if = "Option::is_none")] + pub returns: Option, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub struct IdlAccounts { + pub name: String, + pub accounts: Vec, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(untagged)] + pub enum IdlAccountItem { + IdlAccount(IdlAccount), + IdlAccounts(IdlAccounts), + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub struct IdlAccount { + pub name: String, + pub is_mut: bool, + pub is_signer: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub is_optional: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub docs: Option>, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub pda: Option, + #[serde(skip_serializing_if = "Vec::is_empty", default)] + pub relations: Vec, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub struct IdlPda { + pub seeds: Vec, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub program_id: Option, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase", tag = "kind")] + pub enum IdlSeed { + Const(IdlSeedConst), + Arg(IdlSeedArg), + Account(IdlSeedAccount), + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub struct IdlSeedAccount { + #[serde(rename = "type")] + pub ty: IdlType, + // account_ty points to the entry in the "accounts" section. + // Some only if the `Account` type is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub account: Option, + pub path: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub struct IdlSeedArg { + #[serde(rename = "type")] + pub ty: IdlType, + pub path: String, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub struct IdlSeedConst { + #[serde(rename = "type")] + pub ty: IdlType, + pub value: serde_json::Value, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlField { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none")] + pub docs: Option>, + #[serde(rename = "type")] + pub ty: IdlType, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlEvent { + pub name: String, + pub fields: Vec, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlEventField { + pub name: String, + #[serde(rename = "type")] + pub ty: IdlType, + pub index: bool, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlTypeDefinition { + /// - `idl-parse`: always the name of the type + /// - `idl-build`: full path if there is a name conflict, otherwise the name of the type + pub name: String, + /// Documentation comments + #[serde(skip_serializing_if = "Option::is_none")] + pub docs: Option>, + /// Generics, only supported with `idl-build` + #[serde(skip_serializing_if = "Option::is_none")] + pub generics: Option>, + /// Type definition, `struct` or `enum` + #[serde(rename = "type")] + pub ty: IdlTypeDefinitionTy, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "lowercase", tag = "kind")] + pub enum IdlTypeDefinitionTy { + Struct { fields: Vec }, + Enum { variants: Vec }, + Alias { value: IdlType }, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + pub struct IdlEnumVariant { + pub name: String, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub fields: Option, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(untagged)] + pub enum EnumFields { + Named(Vec), + Tuple(Vec), + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub enum IdlType { + Bool, + U8, + I8, + U16, + I16, + U32, + I32, + F32, + U64, + I64, + F64, + U128, + I128, + U256, + I256, + Bytes, + String, + PublicKey, + Defined(String), + Option(Box), + Vec(Box), + Array(Box, usize), + GenericLenArray(Box, String), + Generic(String), + DefinedWithTypeArgs { + name: String, + args: Vec, + }, + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq)] + #[serde(rename_all = "camelCase")] + pub enum IdlDefinedTypeArg { + Generic(String), + Value(String), + Type(IdlType), + } + + #[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)] + pub struct IdlErrorCode { + pub code: u32, + pub name: String, + #[serde(skip_serializing_if = "Option::is_none", default)] + pub msg: Option, + } + + impl TryFrom for t::Idl { + type Error = anyhow::Error; + + fn try_from(idl: Idl) -> Result { + Ok(Self { + address: idl + .metadata + .as_ref() + .and_then(|m| m.get("address")) + .and_then(|a| a.as_str()) + .ok_or_else(|| anyhow!("Program id missing in `idl.metadata.address` field"))? + .into(), + metadata: t::IdlMetadata { + name: idl.name, + version: idl.version, + spec: t::IDL_SPEC.into(), + description: Default::default(), + repository: Default::default(), + dependencies: Default::default(), + contact: Default::default(), + deployments: Default::default(), + }, + docs: idl.docs.unwrap_or_default(), + instructions: idl.instructions.into_iter().map(Into::into).collect(), + accounts: idl.accounts.clone().into_iter().map(Into::into).collect(), + events: idl + .events + .clone() + .unwrap_or_default() + .into_iter() + .map(Into::into) + .collect(), + errors: idl + .errors + .unwrap_or_default() + .into_iter() + .map(Into::into) + .collect(), + types: idl + .types + .into_iter() + .map(Into::into) + .chain(idl.accounts.into_iter().map(Into::into)) + .chain(idl.events.unwrap_or_default().into_iter().map(Into::into)) + .collect(), + constants: idl.constants.into_iter().map(Into::into).collect(), + }) + } + } + + fn get_disc(prefix: &str, name: &str) -> Vec { + use sha2::{Digest, Sha256}; + let mut hasher = Sha256::new(); + hasher.update(prefix); + hasher.update(b":"); + hasher.update(name); + hasher.finalize()[..8].into() + } + + impl From for t::IdlInstruction { + fn from(value: IdlInstruction) -> Self { + let name = value.name.to_snake_case(); + Self { + discriminator: get_disc("global", &name), + name, + docs: value.docs.unwrap_or_default(), + accounts: value.accounts.into_iter().map(Into::into).collect(), + args: value.args.into_iter().map(Into::into).collect(), + returns: value.returns.map(|r| r.into()), + } + } + } + + impl From for t::IdlAccount { + fn from(value: IdlTypeDefinition) -> Self { + Self { + discriminator: get_disc("account", &value.name), + name: value.name, + } + } + } + + impl From for t::IdlEvent { + fn from(value: IdlEvent) -> Self { + Self { + discriminator: get_disc("event", &value.name), + name: value.name, + } + } + } + + impl From for t::IdlErrorCode { + fn from(value: IdlErrorCode) -> Self { + Self { + name: value.name, + code: value.code, + msg: value.msg, + } + } + } + + impl From for t::IdlConst { + fn from(value: IdlConst) -> Self { + Self { + name: value.name, + docs: Default::default(), + ty: value.ty.into(), + value: value.value, + } + } + } + + impl From for t::IdlGenericArg { + fn from(value: IdlDefinedTypeArg) -> Self { + match value { + IdlDefinedTypeArg::Type(ty) => Self::Type { ty: ty.into() }, + IdlDefinedTypeArg::Value(value) => Self::Const { value }, + IdlDefinedTypeArg::Generic(generic) => Self::Type { + ty: t::IdlType::Generic(generic), + }, + } + } + } + + impl From for t::IdlTypeDef { + fn from(value: IdlTypeDefinition) -> Self { + Self { + name: value.name, + docs: value.docs.unwrap_or_default(), + serialization: Default::default(), + repr: Default::default(), + generics: Default::default(), + ty: value.ty.into(), + } + } + } + + impl From for t::IdlTypeDef { + fn from(value: IdlEvent) -> Self { + Self { + name: value.name, + docs: Default::default(), + serialization: Default::default(), + repr: Default::default(), + generics: Default::default(), + ty: t::IdlTypeDefTy::Struct { + fields: Some(t::IdlDefinedFields::Named( + value + .fields + .into_iter() + .map(|f| t::IdlField { + name: f.name.to_snake_case(), + docs: Default::default(), + ty: f.ty.into(), + }) + .collect(), + )), + }, + } + } + } + + impl From for t::IdlTypeDefTy { + fn from(value: IdlTypeDefinitionTy) -> Self { + match value { + IdlTypeDefinitionTy::Struct { fields } => Self::Struct { + fields: fields.is_empty().then(|| None).unwrap_or_else(|| { + Some(t::IdlDefinedFields::Named( + fields.into_iter().map(Into::into).collect(), + )) + }), + }, + IdlTypeDefinitionTy::Enum { variants } => Self::Enum { + variants: variants + .into_iter() + .map(|variant| t::IdlEnumVariant { + name: variant.name, + fields: variant.fields.map(|fields| match fields { + EnumFields::Named(fields) => t::IdlDefinedFields::Named( + fields.into_iter().map(Into::into).collect(), + ), + EnumFields::Tuple(tys) => t::IdlDefinedFields::Tuple( + tys.into_iter().map(Into::into).collect(), + ), + }), + }) + .collect(), + }, + IdlTypeDefinitionTy::Alias { value } => Self::Type { + alias: value.into(), + }, + } + } + } + + impl From for t::IdlField { + fn from(value: IdlField) -> Self { + Self { + name: value.name.to_snake_case(), + docs: value.docs.unwrap_or_default(), + ty: value.ty.into(), + } + } + } + + impl From for t::IdlType { + fn from(value: IdlType) -> Self { + match value { + IdlType::PublicKey => t::IdlType::Pubkey, + IdlType::Defined(name) => t::IdlType::Defined { + name, + generics: Default::default(), + }, + IdlType::DefinedWithTypeArgs { name, args } => t::IdlType::Defined { + name, + generics: args.into_iter().map(Into::into).collect(), + }, + IdlType::Option(ty) => t::IdlType::Option(ty.into()), + IdlType::Vec(ty) => t::IdlType::Vec(ty.into()), + IdlType::Array(ty, len) => t::IdlType::Array(ty.into(), t::IdlArrayLen::Value(len)), + IdlType::GenericLenArray(ty, generic) => { + t::IdlType::Array(ty.into(), t::IdlArrayLen::Generic(generic)) + } + _ => serde_json::to_value(value) + .and_then(serde_json::from_value) + .unwrap(), + } + } + } + + impl From> for Box { + fn from(value: Box) -> Self { + Box::new((*value).into()) + } + } + + impl From for t::IdlInstructionAccountItem { + fn from(value: IdlAccountItem) -> Self { + match value { + IdlAccountItem::IdlAccount(acc) => Self::Single(t::IdlInstructionAccount { + name: acc.name.to_snake_case(), + docs: acc.docs.unwrap_or_default(), + writable: acc.is_mut, + signer: acc.is_signer, + optional: acc.is_optional.unwrap_or_default(), + address: Default::default(), + pda: acc + .pda + .map(|pda| -> Result { + Ok(t::IdlPda { + seeds: pda + .seeds + .into_iter() + .map(TryInto::try_into) + .collect::>()?, + program: pda.program_id.map(TryInto::try_into).transpose()?, + }) + }) + .transpose() + .unwrap_or_default(), + relations: acc.relations, + }), + IdlAccountItem::IdlAccounts(accs) => Self::Composite(t::IdlInstructionAccounts { + name: accs.name.to_snake_case(), + accounts: accs.accounts.into_iter().map(Into::into).collect(), + }), + } + } + } + + impl TryFrom for t::IdlSeed { + type Error = anyhow::Error; + + fn try_from(value: IdlSeed) -> Result { + let seed = match value { + IdlSeed::Account(seed) => Self::Account(t::IdlSeedAccount { + account: seed.account, + path: seed.path, + }), + IdlSeed::Arg(seed) => Self::Arg(t::IdlSeedArg { path: seed.path }), + IdlSeed::Const(seed) => Self::Const(t::IdlSeedConst { + value: match seed.ty { + IdlType::String => seed.value.to_string().as_bytes().into(), + _ => return Err(anyhow!("Const seed conversion not supported")), + }, + }), + }; + Ok(seed) + } + } +} diff --git a/idl/src/lib.rs b/idl/src/lib.rs new file mode 100644 index 0000000000..de9ac56087 --- /dev/null +++ b/idl/src/lib.rs @@ -0,0 +1,12 @@ +//! Anchor IDL. + +#[cfg(feature = "build")] +pub mod build; + +#[cfg(feature = "convert")] +pub mod convert; + +pub use anchor_lang_idl_spec as types; + +#[cfg(feature = "build")] +pub use serde_json; diff --git a/lang/Cargo.toml b/lang/Cargo.toml index d1c96bd2a0..986c483ea4 100644 --- a/lang/Cargo.toml +++ b/lang/Cargo.toml @@ -1,9 +1,8 @@ [package] name = "anchor-lang" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" -rust-version = "1.60" edition = "2021" license = "Apache-2.0" description = "Solana Sealevel eDSL" @@ -33,35 +32,29 @@ idl-build = [ "anchor-attribute-program/idl-build", "anchor-derive-accounts/idl-build", "anchor-derive-serde/idl-build", - "anchor-syn/idl-build", + "anchor-lang-idl/build", ] init-if-needed = ["anchor-derive-accounts/init-if-needed"] interface-instructions = ["anchor-attribute-program/interface-instructions"] [dependencies] -anchor-attribute-access-control = { path = "./attribute/access-control", version = "0.29.0" } -anchor-attribute-account = { path = "./attribute/account", version = "0.29.0" } -anchor-attribute-constant = { path = "./attribute/constant", version = "0.29.0" } -anchor-attribute-error = { path = "./attribute/error", version = "0.29.0" } -anchor-attribute-event = { path = "./attribute/event", version = "0.29.0" } -anchor-attribute-program = { path = "./attribute/program", version = "0.29.0" } -anchor-derive-accounts = { path = "./derive/accounts", version = "0.29.0" } -anchor-derive-serde = { path = "./derive/serde", version = "0.29.0" } -anchor-derive-space = { path = "./derive/space", version = "0.29.0" } +anchor-attribute-access-control = { path = "./attribute/access-control", version = "0.30.1" } +anchor-attribute-account = { path = "./attribute/account", version = "0.30.1" } +anchor-attribute-constant = { path = "./attribute/constant", version = "0.30.1" } +anchor-attribute-error = { path = "./attribute/error", version = "0.30.1" } +anchor-attribute-event = { path = "./attribute/event", version = "0.30.1" } +anchor-attribute-program = { path = "./attribute/program", version = "0.30.1" } +anchor-derive-accounts = { path = "./derive/accounts", version = "0.30.1" } +anchor-derive-serde = { path = "./derive/serde", version = "0.30.1" } +anchor-derive-space = { path = "./derive/space", version = "0.30.1" } -# `anchor-syn` should only be included with `idl-build` feature -anchor-syn = { path = "./syn", version = "0.29.0", optional = true } +# `anchor-lang-idl` should only be included with `idl-build` feature +anchor-lang-idl = { path = "../idl", version = "0.1.1", optional = true } arrayref = "0.3" base64 = "0.21" bincode = "1" borsh = ">=0.9, <0.11" bytemuck = "1" -solana-program = ">=1.16, <1.18" +solana-program = "1.17.3" thiserror = "1" - -# TODO: Remove. This crate has been added to fix a build error with the 1.16.0 release. -getrandom = { version = "0.2", features = ["custom"] } - -# TODO: Remove once https://github.com/solana-labs/solana/issues/33504 is resolved. -ahash = "=0.8.6" diff --git a/lang/attribute/access-control/Cargo.toml b/lang/attribute/access-control/Cargo.toml index 87a7572069..d375cb2ac1 100644 --- a/lang/attribute/access-control/Cargo.toml +++ b/lang/attribute/access-control/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "anchor-attribute-access-control" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" license = "Apache-2.0" description = "Anchor attribute macro for instruction access control" -rust-version = "1.60" edition = "2021" [lib] @@ -15,7 +14,7 @@ proc-macro = true anchor-debug = ["anchor-syn/anchor-debug"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0" } +anchor-syn = { path = "../../syn", version = "0.30.1" } proc-macro2 = "1" quote = "1" syn = { version = "1", features = ["full"] } diff --git a/lang/attribute/account/Cargo.toml b/lang/attribute/account/Cargo.toml index 15af399b99..28b9104d97 100644 --- a/lang/attribute/account/Cargo.toml +++ b/lang/attribute/account/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "anchor-attribute-account" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" license = "Apache-2.0" description = "Anchor attribute macro for defining an account" -rust-version = "1.60" edition = "2021" [lib] @@ -16,7 +15,7 @@ anchor-debug = ["anchor-syn/anchor-debug"] idl-build = ["anchor-syn/idl-build"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0", features = ["hash"] } +anchor-syn = { path = "../../syn", version = "0.30.1", features = ["hash"] } bs58 = "0.5" proc-macro2 = "1" quote = "1" diff --git a/lang/attribute/account/src/id.rs b/lang/attribute/account/src/id.rs index 993591bf0a..74c9ac8858 100644 --- a/lang/attribute/account/src/id.rs +++ b/lang/attribute/account/src/id.rs @@ -10,7 +10,6 @@ extern crate proc_macro; use proc_macro2::{Delimiter, Span, TokenTree}; use quote::{quote, ToTokens}; -use std::convert::TryFrom; use syn::{ bracketed, parse::{Parse, ParseStream, Result}, @@ -47,6 +46,9 @@ fn id_to_tokens( /// The static program ID pub static ID: #pubkey_type = #id; + /// Const version of `ID` + pub const ID_CONST: #pubkey_type = #id; + /// Confirms that a given pubkey is equivalent to the program ID pub fn check_id(id: &#pubkey_type) -> bool { id == &ID @@ -57,6 +59,11 @@ fn id_to_tokens( ID } + /// Const version of `ID` + pub const fn id_const() -> #pubkey_type { + ID_CONST + } + #[cfg(test)] #[test] fn test_id() { @@ -95,6 +102,25 @@ fn deprecated_id_to_tokens( }); } +pub struct Pubkey(proc_macro2::TokenStream); + +impl Parse for Pubkey { + fn parse(input: ParseStream) -> Result { + parse_id( + input, + quote! { anchor_lang::solana_program::pubkey::Pubkey }, + ) + .map(Self) + } +} + +impl ToTokens for Pubkey { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let id = &self.0; + tokens.extend(quote! {#id}) + } +} + pub struct Id(proc_macro2::TokenStream); impl Parse for Id { diff --git a/lang/attribute/account/src/lib.rs b/lang/attribute/account/src/lib.rs index 125b208d20..efd6953475 100644 --- a/lang/attribute/account/src/lib.rs +++ b/lang/attribute/account/src/lib.rs @@ -1,9 +1,14 @@ extern crate proc_macro; -#[cfg(feature = "idl-build")] -use anchor_syn::idl::build::*; -use quote::quote; -use syn::parse_macro_input; +use anchor_syn::Overrides; +use quote::{quote, ToTokens}; +use syn::{ + parenthesized, + parse::{Parse, ParseStream}, + parse_macro_input, + token::{Comma, Paren}, + Ident, LitStr, +}; mod id; @@ -27,6 +32,22 @@ mod id; /// check this discriminator. If it doesn't match, an invalid account was given, /// and the account deserialization will exit with an error. /// +/// # Args +/// +/// - `discriminator`: Override the default 8-byte discriminator +/// +/// **Usage:** `discriminator = ` +/// +/// All constant expressions are supported. +/// +/// **Examples:** +/// +/// - `discriminator = 1` (shortcut for `[1]`) +/// - `discriminator = [1, 2, 3, 4]` +/// - `discriminator = b"hi"` +/// - `discriminator = MY_DISC` +/// - `discriminator = get_disc(...)` +/// /// # Zero Copy Deserialization /// /// **WARNING**: Zero copy deserialization is an experimental feature. It's @@ -69,53 +90,39 @@ pub fn account( args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { - let mut namespace = "".to_string(); - let mut is_zero_copy = false; - let mut unsafe_bytemuck = false; - let args_str = args.to_string(); - let args: Vec<&str> = args_str.split(',').collect(); - if args.len() > 2 { - panic!("Only two args are allowed to the account attribute.") - } - for arg in args { - let ns = arg - .to_string() - .replace('\"', "") - .chars() - .filter(|c| !c.is_whitespace()) - .collect(); - if ns == "zero_copy" { - is_zero_copy = true; - unsafe_bytemuck = false; - } else if ns == "zero_copy(unsafe)" { - is_zero_copy = true; - unsafe_bytemuck = true; - } else { - namespace = ns; - } - } + let args = parse_macro_input!(args as AccountArgs); + let namespace = args.namespace.unwrap_or_default(); + let is_zero_copy = args.zero_copy.is_some(); + let unsafe_bytemuck = args.zero_copy.unwrap_or_default(); let account_strct = parse_macro_input!(input as syn::ItemStruct); let account_name = &account_strct.ident; let account_name_str = account_name.to_string(); let (impl_gen, type_gen, where_clause) = account_strct.generics.split_for_impl(); - let discriminator: proc_macro2::TokenStream = { - // Namespace the discriminator to prevent collisions. - let discriminator_preimage = { - // For now, zero copy accounts can't be namespaced. - if namespace.is_empty() { + let discriminator = args + .overrides + .and_then(|ov| ov.discriminator) + .unwrap_or_else(|| { + // Namespace the discriminator to prevent collisions. + let discriminator_preimage = if namespace.is_empty() { format!("account:{account_name}") } else { format!("{namespace}:{account_name}") - } - }; - - let mut discriminator = [0u8; 8]; - discriminator.copy_from_slice( - &anchor_syn::hash::hash(discriminator_preimage.as_bytes()).to_bytes()[..8], - ); - format!("{discriminator:?}").parse().unwrap() + }; + + let mut discriminator = [0u8; 8]; + discriminator.copy_from_slice( + &anchor_syn::hash::hash(discriminator_preimage.as_bytes()).to_bytes()[..8], + ); + let discriminator: proc_macro2::TokenStream = + format!("{discriminator:?}").parse().unwrap(); + quote! { &#discriminator } + }); + let disc = if account_strct.generics.lt_token.is_some() { + quote! { #account_name::#type_gen::DISCRIMINATOR } + } else { + quote! { #account_name::DISCRIMINATOR } }; let owner_impl = { @@ -171,7 +178,7 @@ pub fn account( #[automatically_derived] impl #impl_gen anchor_lang::Discriminator for #account_name #type_gen #where_clause { - const DISCRIMINATOR: [u8; 8] = #discriminator; + const DISCRIMINATOR: &'static [u8] = #discriminator; } // This trait is useful for clients deserializing accounts. @@ -179,18 +186,18 @@ pub fn account( #[automatically_derived] impl #impl_gen anchor_lang::AccountDeserialize for #account_name #type_gen #where_clause { fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { - if buf.len() < #discriminator.len() { + if buf.len() < #disc.len() { return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into()); } - let given_disc = &buf[..8]; - if &#discriminator != given_disc { + let given_disc = &buf[..#disc.len()]; + if #disc != given_disc { return Err(anchor_lang::error!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch).with_account_name(#account_name_str)); } Self::try_deserialize_unchecked(buf) } fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { - let data: &[u8] = &buf[8..]; + let data: &[u8] = &buf[#disc.len()..]; // Re-interpret raw bytes into the POD data structure. let account = anchor_lang::__private::bytemuck::from_bytes(data); // Copy out the bytes into a new, owned data structure. @@ -208,7 +215,7 @@ pub fn account( #[automatically_derived] impl #impl_gen anchor_lang::AccountSerialize for #account_name #type_gen #where_clause { fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { - if writer.write_all(&#discriminator).is_err() { + if writer.write_all(#disc).is_err() { return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); } @@ -222,18 +229,18 @@ pub fn account( #[automatically_derived] impl #impl_gen anchor_lang::AccountDeserialize for #account_name #type_gen #where_clause { fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { - if buf.len() < #discriminator.len() { + if buf.len() < #disc.len() { return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into()); } - let given_disc = &buf[..8]; - if &#discriminator != given_disc { + let given_disc = &buf[..#disc.len()]; + if #disc != given_disc { return Err(anchor_lang::error!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch).with_account_name(#account_name_str)); } Self::try_deserialize_unchecked(buf) } fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { - let mut data: &[u8] = &buf[8..]; + let mut data: &[u8] = &buf[#disc.len()..]; AnchorDeserialize::deserialize(&mut data) .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()) } @@ -241,7 +248,7 @@ pub fn account( #[automatically_derived] impl #impl_gen anchor_lang::Discriminator for #account_name #type_gen #where_clause { - const DISCRIMINATOR: [u8; 8] = #discriminator; + const DISCRIMINATOR: &'static [u8] = #discriminator; } #owner_impl @@ -250,6 +257,80 @@ pub fn account( }) } +#[derive(Debug, Default)] +struct AccountArgs { + /// `bool` is for deciding whether to use `unsafe` e.g. `Some(true)` for `zero_copy(unsafe)` + zero_copy: Option, + /// Account namespace override, `account` if not specified + namespace: Option, + /// Named overrides + overrides: Option, +} + +impl Parse for AccountArgs { + fn parse(input: ParseStream) -> syn::Result { + let mut parsed = Self::default(); + let args = input.parse_terminated::<_, Comma>(AccountArg::parse)?; + for arg in args { + match arg { + AccountArg::ZeroCopy { is_unsafe } => { + parsed.zero_copy.replace(is_unsafe); + } + AccountArg::Namespace(ns) => { + parsed.namespace.replace(ns); + } + AccountArg::Overrides(ov) => { + parsed.overrides.replace(ov); + } + } + } + + Ok(parsed) + } +} + +enum AccountArg { + ZeroCopy { is_unsafe: bool }, + Namespace(String), + Overrides(Overrides), +} + +impl Parse for AccountArg { + fn parse(input: ParseStream) -> syn::Result { + // Namespace + if let Ok(ns) = input.parse::() { + return Ok(Self::Namespace( + ns.to_token_stream().to_string().replace('\"', ""), + )); + } + + // Zero copy + if input.fork().parse::()? == "zero_copy" { + input.parse::()?; + let is_unsafe = if input.peek(Paren) { + let content; + parenthesized!(content in input); + let content = content.parse::()?; + if content.to_string().as_str().trim() != "unsafe" { + return Err(syn::Error::new( + syn::spanned::Spanned::span(&content), + "Expected `unsafe`", + )); + } + + true + } else { + false + }; + + return Ok(Self::ZeroCopy { is_unsafe }); + }; + + // Overrides + input.parse::().map(Self::Overrides) + } +} + #[proc_macro_derive(ZeroCopyAccessor, attributes(accessor))] pub fn derive_zero_copy_accessor(item: proc_macro::TokenStream) -> proc_macro::TokenStream { let account_strct = parse_macro_input!(item as syn::ItemStruct); @@ -404,8 +485,18 @@ pub fn zero_copy( #[cfg(feature = "idl-build")] { - let no_docs = get_no_docs(); - let idl_build_impl = gen_idl_build_impl_for_struct(&account_strct, no_docs); + let derive_unsafe = if is_unsafe { + // Not a real proc-macro but exists in order to pass the serialization info + quote! { #[derive(bytemuck::Unsafe)] } + } else { + quote! {} + }; + let zc_struct = syn::parse2(quote! { + #derive_unsafe + #ret + }) + .unwrap(); + let idl_build_impl = anchor_syn::idl::impl_idl_build_struct(&zc_struct); return proc_macro::TokenStream::from(quote! { #ret #idl_build_impl @@ -416,10 +507,34 @@ pub fn zero_copy( proc_macro::TokenStream::from(ret) } +/// Convenience macro to define a static public key. +/// +/// Input: a single literal base58 string representation of a Pubkey. +#[proc_macro] +pub fn pubkey(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let pk = parse_macro_input!(input as id::Pubkey); + proc_macro::TokenStream::from(quote! {#pk}) +} + /// Defines the program's ID. This should be used at the root of all Anchor /// based programs. #[proc_macro] pub fn declare_id(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + #[cfg(feature = "idl-build")] + let address = input.clone().to_string(); + let id = parse_macro_input!(input as id::Id); - proc_macro::TokenStream::from(quote! {#id}) + let ret = quote! { #id }; + + #[cfg(feature = "idl-build")] + { + let idl_print = anchor_syn::idl::gen_idl_print_fn_address(address); + return proc_macro::TokenStream::from(quote! { + #ret + #idl_print + }); + } + + #[allow(unreachable_code)] + proc_macro::TokenStream::from(ret) } diff --git a/lang/attribute/constant/Cargo.toml b/lang/attribute/constant/Cargo.toml index d1dde5bdc0..ce5f15a9fc 100644 --- a/lang/attribute/constant/Cargo.toml +++ b/lang/attribute/constant/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "anchor-attribute-constant" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" license = "Apache-2.0" description = "Anchor attribute macro for creating constant types" -rust-version = "1.60" edition = "2021" [lib] @@ -16,6 +15,6 @@ anchor-debug = ["anchor-syn/anchor-debug"] idl-build = ["anchor-syn/idl-build"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0" } +anchor-syn = { path = "../../syn", version = "0.30.1" } quote = "1" syn = { version = "1", features = ["full"] } diff --git a/lang/attribute/constant/src/lib.rs b/lang/attribute/constant/src/lib.rs index fd1f4ad680..685e5faafe 100644 --- a/lang/attribute/constant/src/lib.rs +++ b/lang/attribute/constant/src/lib.rs @@ -1,8 +1,5 @@ extern crate proc_macro; -#[cfg(feature = "idl-build")] -use {anchor_syn::idl::build::gen_idl_print_function_for_constant, quote::quote, syn}; - /// A marker attribute used to mark const values that should be included in the /// generated IDL but functionally does nothing. #[proc_macro_attribute] @@ -12,9 +9,11 @@ pub fn constant( ) -> proc_macro::TokenStream { #[cfg(feature = "idl-build")] { + use quote::quote; + let ts = match syn::parse(input).unwrap() { syn::Item::Const(item) => { - let idl_print = gen_idl_print_function_for_constant(&item); + let idl_print = anchor_syn::idl::gen_idl_print_fn_constant(&item); quote! { #item #idl_print diff --git a/lang/attribute/error/Cargo.toml b/lang/attribute/error/Cargo.toml index 88d781bf25..748b9993c2 100644 --- a/lang/attribute/error/Cargo.toml +++ b/lang/attribute/error/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "anchor-attribute-error" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" license = "Apache-2.0" description = "Anchor attribute macro for creating error types" -rust-version = "1.60" edition = "2021" [lib] @@ -16,6 +15,6 @@ anchor-debug = ["anchor-syn/anchor-debug"] idl-build = ["anchor-syn/idl-build"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0" } +anchor-syn = { path = "../../syn", version = "0.30.1" } quote = "1" syn = { version = "1", features = ["full"] } diff --git a/lang/attribute/event/Cargo.toml b/lang/attribute/event/Cargo.toml index 9546536cca..fd146bbf12 100644 --- a/lang/attribute/event/Cargo.toml +++ b/lang/attribute/event/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "anchor-attribute-event" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" license = "Apache-2.0" @@ -17,7 +17,7 @@ event-cpi = ["anchor-syn/event-cpi"] idl-build = ["anchor-syn/idl-build"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0", features = ["hash"] } +anchor-syn = { path = "../../syn", version = "0.30.1", features = ["hash"] } proc-macro2 = "1" quote = "1" syn = { version = "1", features = ["full"] } diff --git a/lang/attribute/event/src/lib.rs b/lang/attribute/event/src/lib.rs index a8c1837054..17cd41db3f 100644 --- a/lang/attribute/event/src/lib.rs +++ b/lang/attribute/event/src/lib.rs @@ -2,6 +2,7 @@ extern crate proc_macro; #[cfg(feature = "event-cpi")] use anchor_syn::parser::accounts::event_cpi::{add_event_cpi_accounts, EventAuthority}; +use anchor_syn::Overrides; use quote::quote; use syn::parse_macro_input; @@ -10,21 +11,39 @@ use syn::parse_macro_input; /// their programs that clients can subscribe to. Currently, this macro is for /// structs only. /// +/// # Args +/// +/// - `discriminator`: Override the default 8-byte discriminator +/// +/// **Usage:** `discriminator = ` +/// +/// All constant expressions are supported. +/// +/// **Examples:** +/// +/// - `discriminator = 1` (shortcut for `[1]`) +/// - `discriminator = [1, 2, 3, 4]` +/// - `discriminator = b"hi"` +/// - `discriminator = MY_DISC` +/// - `discriminator = get_disc(...)` +/// /// See the [`emit!` macro](emit!) for an example. #[proc_macro_attribute] pub fn event( - _args: proc_macro::TokenStream, + args: proc_macro::TokenStream, input: proc_macro::TokenStream, ) -> proc_macro::TokenStream { + let args = parse_macro_input!(args as Overrides); let event_strct = parse_macro_input!(input as syn::ItemStruct); - let event_name = &event_strct.ident; - let discriminator: proc_macro2::TokenStream = { + let discriminator = args.discriminator.unwrap_or_else(|| { let discriminator_preimage = format!("event:{event_name}").into_bytes(); let discriminator = anchor_syn::hash::hash(&discriminator_preimage); - format!("{:?}", &discriminator.0[..8]).parse().unwrap() - }; + let discriminator: proc_macro2::TokenStream = + format!("{:?}", &discriminator.0[..8]).parse().unwrap(); + quote! { &#discriminator } + }); let ret = quote! { #[derive(anchor_lang::__private::EventIndex, AnchorSerialize, AnchorDeserialize)] @@ -33,20 +52,20 @@ pub fn event( impl anchor_lang::Event for #event_name { fn data(&self) -> Vec { let mut data = Vec::with_capacity(256); - data.extend_from_slice(&#discriminator); + data.extend_from_slice(#event_name::DISCRIMINATOR); self.serialize(&mut data).unwrap(); data } } impl anchor_lang::Discriminator for #event_name { - const DISCRIMINATOR: [u8; 8] = #discriminator; + const DISCRIMINATOR: &'static [u8] = #discriminator; } }; #[cfg(feature = "idl-build")] { - let idl_build = anchor_syn::idl::build::gen_idl_print_function_for_event(&event_strct); + let idl_build = anchor_syn::idl::gen_idl_print_fn_event(&event_strct); return proc_macro::TokenStream::from(quote! { #ret #idl_build @@ -161,7 +180,11 @@ pub fn emit_cpi(input: proc_macro::TokenStream) -> proc_macro::TokenStream { let disc = anchor_lang::event::EVENT_IX_TAG_LE; let inner_data = anchor_lang::Event::data(&#event_struct); - let ix_data: Vec = disc.into_iter().chain(inner_data.into_iter()).collect(); + let ix_data: Vec = disc + .into_iter() + .map(|b| *b) + .chain(inner_data.into_iter()) + .collect(); let ix = anchor_lang::solana_program::instruction::Instruction::new_with_bytes( crate::ID, diff --git a/lang/attribute/program/Cargo.toml b/lang/attribute/program/Cargo.toml index 3005195481..fba2b27fe0 100644 --- a/lang/attribute/program/Cargo.toml +++ b/lang/attribute/program/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "anchor-attribute-program" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" license = "Apache-2.0" description = "Anchor attribute macro for defining a program" -rust-version = "1.60" edition = "2021" [lib] @@ -17,6 +16,12 @@ idl-build = ["anchor-syn/idl-build"] interface-instructions = ["anchor-syn/interface-instructions"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0" } +anchor-lang-idl = { path = "../../../idl", version = "0.1.1", features = ["convert"] } +anchor-syn = { path = "../../syn", version = "0.30.1" } +anyhow = "1" +bs58 = "0.5" +heck = "0.3" +proc-macro2 = "1" quote = "1" +serde_json = "1" syn = { version = "1", features = ["full"] } diff --git a/lang/attribute/program/src/declare_program/common.rs b/lang/attribute/program/src/declare_program/common.rs new file mode 100644 index 0000000000..42f05d73f7 --- /dev/null +++ b/lang/attribute/program/src/declare_program/common.rs @@ -0,0 +1,375 @@ +use anchor_lang_idl::types::{ + Idl, IdlArrayLen, IdlDefinedFields, IdlField, IdlGenericArg, IdlRepr, IdlSerialization, + IdlType, IdlTypeDef, IdlTypeDefGeneric, IdlTypeDefTy, +}; +use proc_macro2::Literal; +use quote::{format_ident, quote}; + +/// This function should ideally return the absolute path to the declared program's id but because +/// `proc_macro2::Span::call_site().source_file().path()` is behind an unstable feature flag, we +/// are not able to reliably decide where the definition is. +pub fn get_canonical_program_id() -> proc_macro2::TokenStream { + quote! { super::__ID } +} + +pub fn gen_docs(docs: &[String]) -> proc_macro2::TokenStream { + let docs = docs + .iter() + .map(|doc| format!("{}{doc}", if doc.is_empty() { "" } else { " " })) + .map(|doc| quote! { #[doc = #doc] }); + quote! { #(#docs)* } +} + +pub fn gen_discriminator(disc: &[u8]) -> proc_macro2::TokenStream { + quote! { [#(#disc), *] } +} + +pub fn gen_accounts_common(idl: &Idl, prefix: &str) -> proc_macro2::TokenStream { + let re_exports = idl + .instructions + .iter() + .map(|ix| format_ident!("__{}_accounts_{}", prefix, ix.name)) + .map(|ident| quote! { pub use super::internal::#ident::*; }); + + quote! { + pub mod accounts { + #(#re_exports)* + } + } +} + +pub fn convert_idl_type_to_syn_type(ty: &IdlType) -> syn::Type { + syn::parse_str(&convert_idl_type_to_str(ty)).unwrap() +} + +// TODO: Impl `ToString` for `IdlType` +pub fn convert_idl_type_to_str(ty: &IdlType) -> String { + match ty { + IdlType::Bool => "bool".into(), + IdlType::U8 => "u8".into(), + IdlType::I8 => "i8".into(), + IdlType::U16 => "u16".into(), + IdlType::I16 => "i16".into(), + IdlType::U32 => "u32".into(), + IdlType::I32 => "i32".into(), + IdlType::F32 => "f32".into(), + IdlType::U64 => "u64".into(), + IdlType::I64 => "i64".into(), + IdlType::F64 => "f64".into(), + IdlType::U128 => "u128".into(), + IdlType::I128 => "i128".into(), + IdlType::U256 => "u256".into(), + IdlType::I256 => "i256".into(), + IdlType::Bytes => "Vec".into(), + IdlType::String => "String".into(), + IdlType::Pubkey => "Pubkey".into(), + IdlType::Option(ty) => format!("Option<{}>", convert_idl_type_to_str(ty)), + IdlType::Vec(ty) => format!("Vec<{}>", convert_idl_type_to_str(ty)), + IdlType::Array(ty, len) => format!( + "[{}; {}]", + convert_idl_type_to_str(ty), + match len { + IdlArrayLen::Generic(len) => len.into(), + IdlArrayLen::Value(len) => len.to_string(), + } + ), + IdlType::Defined { name, generics } => generics + .iter() + .map(|generic| match generic { + IdlGenericArg::Type { ty } => convert_idl_type_to_str(ty), + IdlGenericArg::Const { value } => value.into(), + }) + .reduce(|mut acc, cur| { + if !acc.is_empty() { + acc.push(','); + } + acc.push_str(&cur); + acc + }) + .map(|generics| format!("{name}<{generics}>")) + .unwrap_or(name.into()), + IdlType::Generic(ty) => ty.into(), + _ => unimplemented!("{ty:?}"), + } +} + +pub fn convert_idl_type_def_to_ts( + ty_def: &IdlTypeDef, + ty_defs: &[IdlTypeDef], +) -> proc_macro2::TokenStream { + let name = format_ident!("{}", ty_def.name); + let docs = gen_docs(&ty_def.docs); + + let generics = { + let generics = ty_def + .generics + .iter() + .map(|generic| match generic { + IdlTypeDefGeneric::Type { name } => { + let name = format_ident!("{}", name); + quote! { #name } + } + IdlTypeDefGeneric::Const { name, ty } => { + let name = format_ident!("{}", name); + let ty = format_ident!("{}", ty); + quote! { const #name: #ty } + } + }) + .collect::>(); + if generics.is_empty() { + quote!() + } else { + quote!(<#(#generics,)*>) + } + }; + + let attrs = { + let debug_attr = quote!(#[derive(Debug)]); + + let default_attr = can_derive_default(ty_def, ty_defs) + .then(|| quote!(#[derive(Default)])) + .unwrap_or_default(); + + let ser_attr = match &ty_def.serialization { + IdlSerialization::Borsh => quote!(#[derive(AnchorSerialize, AnchorDeserialize)]), + IdlSerialization::Bytemuck => quote!(#[zero_copy]), + IdlSerialization::BytemuckUnsafe => quote!(#[zero_copy(unsafe)]), + _ => unimplemented!("{:?}", ty_def.serialization), + }; + + let clone_attr = matches!(ty_def.serialization, IdlSerialization::Borsh) + .then(|| quote!(#[derive(Clone)])) + .unwrap_or_default(); + + let copy_attr = matches!(ty_def.serialization, IdlSerialization::Borsh) + .then(|| can_derive_copy(ty_def, ty_defs).then(|| quote!(#[derive(Copy)]))) + .flatten() + .unwrap_or_default(); + + quote! { + #debug_attr + #default_attr + #ser_attr + #clone_attr + #copy_attr + } + }; + + let repr = if let Some(repr) = &ty_def.repr { + let kind = match repr { + IdlRepr::Rust(_) => "Rust", + IdlRepr::C(_) => "C", + IdlRepr::Transparent => "transparent", + _ => unimplemented!("{repr:?}"), + }; + let kind = format_ident!("{kind}"); + + let modifier = match repr { + IdlRepr::Rust(modifier) | IdlRepr::C(modifier) => { + let packed = modifier.packed.then(|| quote!(packed)).unwrap_or_default(); + let align = modifier + .align + .map(Literal::usize_unsuffixed) + .map(|align| quote!(align(#align))) + .unwrap_or_default(); + + if packed.is_empty() { + align + } else if align.is_empty() { + packed + } else { + quote! { #packed, #align } + } + } + _ => quote!(), + }; + let modifier = if modifier.is_empty() { + modifier + } else { + quote! { , #modifier } + }; + + quote! { #[repr(#kind #modifier)] } + } else { + quote!() + }; + + let ty = match &ty_def.ty { + IdlTypeDefTy::Struct { fields } => { + let declare_struct = quote! { pub struct #name #generics }; + handle_defined_fields( + fields.as_ref(), + || quote! { #declare_struct; }, + |fields| { + let fields = fields.iter().map(|field| { + let name = format_ident!("{}", field.name); + let ty = convert_idl_type_to_syn_type(&field.ty); + quote! { pub #name : #ty } + }); + quote! { + #declare_struct { + #(#fields,)* + } + } + }, + |tys| { + let tys = tys + .iter() + .map(convert_idl_type_to_syn_type) + .map(|ty| quote! { pub #ty }); + + quote! { + #declare_struct (#(#tys,)*); + } + }, + ) + } + IdlTypeDefTy::Enum { variants } => { + let variants = variants.iter().map(|variant| { + let variant_name = format_ident!("{}", variant.name); + handle_defined_fields( + variant.fields.as_ref(), + || quote! { #variant_name }, + |fields| { + let fields = fields.iter().map(|field| { + let name = format_ident!("{}", field.name); + let ty = convert_idl_type_to_syn_type(&field.ty); + quote! { #name : #ty } + }); + quote! { + #variant_name { + #(#fields,)* + } + } + }, + |tys| { + let tys = tys.iter().map(convert_idl_type_to_syn_type); + quote! { + #variant_name (#(#tys,)*) + } + }, + ) + }); + + quote! { + pub enum #name #generics { + #(#variants,)* + } + } + } + IdlTypeDefTy::Type { alias } => { + let alias = convert_idl_type_to_syn_type(alias); + quote! { pub type #name = #alias; } + } + }; + + quote! { + #docs + #attrs + #repr + #ty + } +} + +fn can_derive_copy(ty_def: &IdlTypeDef, ty_defs: &[IdlTypeDef]) -> bool { + match &ty_def.ty { + IdlTypeDefTy::Struct { fields } => { + can_derive_common(fields.as_ref(), ty_defs, can_derive_copy_ty) + } + IdlTypeDefTy::Enum { variants } => variants + .iter() + .all(|variant| can_derive_common(variant.fields.as_ref(), ty_defs, can_derive_copy_ty)), + IdlTypeDefTy::Type { alias } => can_derive_copy_ty(alias, ty_defs), + } +} + +fn can_derive_default(ty_def: &IdlTypeDef, ty_defs: &[IdlTypeDef]) -> bool { + match &ty_def.ty { + IdlTypeDefTy::Struct { fields } => { + can_derive_common(fields.as_ref(), ty_defs, can_derive_default_ty) + } + // TODO: Consider storing the default enum variant in IDL + IdlTypeDefTy::Enum { .. } => false, + IdlTypeDefTy::Type { alias } => can_derive_default_ty(alias, ty_defs), + } +} + +fn can_derive_copy_ty(ty: &IdlType, ty_defs: &[IdlTypeDef]) -> bool { + match ty { + IdlType::Option(inner) => can_derive_copy_ty(inner, ty_defs), + IdlType::Array(inner, len) => { + if !can_derive_copy_ty(inner, ty_defs) { + return false; + } + + match len { + IdlArrayLen::Value(_) => true, + IdlArrayLen::Generic(_) => false, + } + } + IdlType::Defined { name, .. } => ty_defs + .iter() + .find(|ty_def| &ty_def.name == name) + .map(|ty_def| can_derive_copy(ty_def, ty_defs)) + .expect("Type def must exist"), + IdlType::Bytes | IdlType::String | IdlType::Vec(_) | IdlType::Generic(_) => false, + _ => true, + } +} + +fn can_derive_default_ty(ty: &IdlType, ty_defs: &[IdlTypeDef]) -> bool { + match ty { + IdlType::Option(inner) => can_derive_default_ty(inner, ty_defs), + IdlType::Vec(inner) => can_derive_default_ty(inner, ty_defs), + IdlType::Array(inner, len) => { + if !can_derive_default_ty(inner, ty_defs) { + return false; + } + + match len { + IdlArrayLen::Value(len) => *len <= 32, + IdlArrayLen::Generic(_) => false, + } + } + IdlType::Defined { name, .. } => ty_defs + .iter() + .find(|ty_def| &ty_def.name == name) + .map(|ty_def| can_derive_default(ty_def, ty_defs)) + .expect("Type def must exist"), + IdlType::Generic(_) => false, + _ => true, + } +} + +fn can_derive_common( + fields: Option<&IdlDefinedFields>, + ty_defs: &[IdlTypeDef], + can_derive_ty: fn(&IdlType, &[IdlTypeDef]) -> bool, +) -> bool { + handle_defined_fields( + fields, + || true, + |fields| { + fields + .iter() + .map(|field| &field.ty) + .all(|ty| can_derive_ty(ty, ty_defs)) + }, + |tys| tys.iter().all(|ty| can_derive_ty(ty, ty_defs)), + ) +} + +fn handle_defined_fields( + fields: Option<&IdlDefinedFields>, + unit_cb: impl Fn() -> R, + named_cb: impl Fn(&[IdlField]) -> R, + tuple_cb: impl Fn(&[IdlType]) -> R, +) -> R { + match fields { + Some(fields) => match fields { + IdlDefinedFields::Named(fields) => named_cb(fields), + IdlDefinedFields::Tuple(tys) => tuple_cb(tys), + }, + _ => unit_cb(), + } +} diff --git a/lang/attribute/program/src/declare_program/mod.rs b/lang/attribute/program/src/declare_program/mod.rs new file mode 100644 index 0000000000..2b96995ee9 --- /dev/null +++ b/lang/attribute/program/src/declare_program/mod.rs @@ -0,0 +1,125 @@ +mod common; +mod mods; + +use anchor_lang_idl::{convert::convert_idl, types::Idl}; +use anyhow::anyhow; +use quote::{quote, ToTokens}; +use syn::parse::{Parse, ParseStream}; + +use common::gen_docs; +use mods::{ + accounts::gen_accounts_mod, client::gen_client_mod, constants::gen_constants_mod, + cpi::gen_cpi_mod, events::gen_events_mod, internal::gen_internal_mod, program::gen_program_mod, + types::gen_types_mod, utils::gen_utils_mod, +}; + +pub struct DeclareProgram { + name: syn::Ident, + idl: Idl, +} + +impl Parse for DeclareProgram { + fn parse(input: ParseStream) -> syn::Result { + let name = input.parse()?; + let idl = get_idl(&name).map_err(|e| syn::Error::new(name.span(), e))?; + Ok(Self { name, idl }) + } +} + +impl ToTokens for DeclareProgram { + fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { + let program = gen_program(&self.idl, &self.name); + tokens.extend(program) + } +} + +fn get_idl(name: &syn::Ident) -> anyhow::Result { + let manifest_dir = std::env::var("CARGO_MANIFEST_DIR").expect("Failed to get manifest dir"); + std::path::Path::new(&manifest_dir) + .ancestors() + .find_map(|ancestor| { + let idl_dir = ancestor.join("idls"); + idl_dir.exists().then_some(idl_dir) + }) + .ok_or_else(|| anyhow!("`idls` directory not found")) + .map(|idl_dir| idl_dir.join(name.to_string()).with_extension("json")) + .map(std::fs::read)? + .map_err(|e| anyhow!("Failed to read IDL `{name}`: {e}")) + .map(|buf| convert_idl(&buf))? +} + +fn gen_program(idl: &Idl, name: &syn::Ident) -> proc_macro2::TokenStream { + let docs = gen_program_docs(idl); + let id = gen_id(idl); + let program_mod = gen_program_mod(&idl.metadata.name); + + // Defined + let constants_mod = gen_constants_mod(idl); + let accounts_mod = gen_accounts_mod(idl); + let events_mod = gen_events_mod(idl); + let types_mod = gen_types_mod(idl); + + // Clients + let cpi_mod = gen_cpi_mod(idl); + let client_mod = gen_client_mod(idl); + let internal_mod = gen_internal_mod(idl); + + // Utils + let utils_mod = gen_utils_mod(idl); + + quote! { + #docs + pub mod #name { + use anchor_lang::prelude::*; + use accounts::*; + use events::*; + use types::*; + + #id + #program_mod + + #constants_mod + #accounts_mod + #events_mod + #types_mod + + #cpi_mod + #client_mod + #internal_mod + + #utils_mod + } + } +} + +fn gen_program_docs(idl: &Idl) -> proc_macro2::TokenStream { + let docs: &[String] = &[ + format!( + "Generated external program declaration of program `{}`.", + idl.metadata.name + ), + String::default(), + ]; + let docs = [docs, &idl.docs].concat(); + gen_docs(&docs) +} + +fn gen_id(idl: &Idl) -> proc_macro2::TokenStream { + let address_bytes = bs58::decode(&idl.address) + .into_vec() + .expect("Invalid `idl.address`"); + let doc = format!("Program ID of program `{}`.", idl.metadata.name); + + quote! { + #[doc = #doc] + pub static ID: Pubkey = __ID; + + /// Const version of `ID` + pub const ID_CONST: Pubkey = __ID_CONST; + + /// The name is intentionally prefixed with `__` in order to reduce to possibility of name + /// clashes with the crate's `ID`. + static __ID: Pubkey = Pubkey::new_from_array([#(#address_bytes,)*]); + const __ID_CONST : Pubkey = Pubkey::new_from_array([#(#address_bytes,)*]); + } +} diff --git a/lang/attribute/program/src/declare_program/mods/accounts.rs b/lang/attribute/program/src/declare_program/mods/accounts.rs new file mode 100644 index 0000000000..9b4821e992 --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/accounts.rs @@ -0,0 +1,119 @@ +use anchor_lang_idl::types::{Idl, IdlSerialization}; +use quote::{format_ident, quote}; + +use super::common::{convert_idl_type_def_to_ts, gen_discriminator, get_canonical_program_id}; + +pub fn gen_accounts_mod(idl: &Idl) -> proc_macro2::TokenStream { + let accounts = idl.accounts.iter().map(|acc| { + let name = format_ident!("{}", acc.name); + let discriminator = gen_discriminator(&acc.discriminator); + let disc = quote! { #name::DISCRIMINATOR }; + + let ty_def = idl + .types + .iter() + .find(|ty| ty.name == acc.name) + .expect("Type must exist"); + + let impls = { + let try_deserialize = quote! { + fn try_deserialize(buf: &mut &[u8]) -> anchor_lang::Result { + if buf.len() < #disc.len() { + return Err(anchor_lang::error::ErrorCode::AccountDiscriminatorNotFound.into()); + } + + let given_disc = &buf[..#disc.len()]; + if #disc != given_disc { + return Err( + anchor_lang::error!(anchor_lang::error::ErrorCode::AccountDiscriminatorMismatch) + .with_account_name(stringify!(#name)) + ); + } + + Self::try_deserialize_unchecked(buf) + } + }; + match ty_def.serialization { + IdlSerialization::Borsh => quote! { + impl anchor_lang::AccountSerialize for #name { + fn try_serialize(&self, writer: &mut W) -> anchor_lang::Result<()> { + if writer.write_all(#disc).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + if AnchorSerialize::serialize(self, writer).is_err() { + return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into()); + } + + Ok(()) + } + } + + impl anchor_lang::AccountDeserialize for #name { + #try_deserialize + + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + let mut data: &[u8] = &buf[#disc.len()..]; + AnchorDeserialize::deserialize(&mut data) + .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize.into()) + } + } + }, + _ => { + let unsafe_bytemuck_impl = + matches!(ty_def.serialization, IdlSerialization::BytemuckUnsafe) + .then(|| { + quote! { + unsafe impl anchor_lang::__private::bytemuck::Pod for #name {} + unsafe impl anchor_lang::__private::bytemuck::Zeroable for #name {} + } + }) + .unwrap_or_default(); + + quote! { + impl anchor_lang::ZeroCopy for #name {} + + impl anchor_lang::AccountDeserialize for #name { + #try_deserialize + + fn try_deserialize_unchecked(buf: &mut &[u8]) -> anchor_lang::Result { + let data: &[u8] = &buf[#disc.len()..]; + let account = anchor_lang::__private::bytemuck::from_bytes(data); + Ok(*account) + } + } + + #unsafe_bytemuck_impl + } + } + } + }; + + let type_def_ts = convert_idl_type_def_to_ts(ty_def, &idl.types); + let program_id = get_canonical_program_id(); + + quote! { + #type_def_ts + + #impls + + impl anchor_lang::Discriminator for #name { + const DISCRIMINATOR: &'static [u8] = &#discriminator; + } + + impl anchor_lang::Owner for #name { + fn owner() -> Pubkey { + #program_id + } + } + } + }); + + quote! { + /// Program account type definitions. + pub mod accounts { + use super::*; + + #(#accounts)* + } + } +} diff --git a/lang/attribute/program/src/declare_program/mods/client.rs b/lang/attribute/program/src/declare_program/mods/client.rs new file mode 100644 index 0000000000..0312750584 --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/client.rs @@ -0,0 +1,32 @@ +use anchor_lang_idl::types::Idl; +use quote::quote; + +use super::common::gen_accounts_common; + +pub fn gen_client_mod(idl: &Idl) -> proc_macro2::TokenStream { + let client_args_mod = gen_client_args_mod(); + let client_accounts_mod = gen_client_accounts_mod(idl); + + quote! { + /// Off-chain client helpers. + pub mod client { + use super::*; + + #client_args_mod + #client_accounts_mod + } + } +} + +fn gen_client_args_mod() -> proc_macro2::TokenStream { + quote! { + /// Client args. + pub mod args { + pub use super::internal::args::*; + } + } +} + +fn gen_client_accounts_mod(idl: &Idl) -> proc_macro2::TokenStream { + gen_accounts_common(idl, "client") +} diff --git a/lang/attribute/program/src/declare_program/mods/constants.rs b/lang/attribute/program/src/declare_program/mods/constants.rs new file mode 100644 index 0000000000..4cb6ec0ed3 --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/constants.rs @@ -0,0 +1,29 @@ +use anchor_lang_idl::types::{Idl, IdlType}; +use quote::{format_ident, quote, ToTokens}; + +use super::common::convert_idl_type_to_str; + +pub fn gen_constants_mod(idl: &Idl) -> proc_macro2::TokenStream { + let constants = idl.constants.iter().map(|c| { + let name = format_ident!("{}", c.name); + let ty = match &c.ty { + IdlType::String => quote!(&str), + _ => parse_expr_ts(&convert_idl_type_to_str(&c.ty)), + }; + let val = parse_expr_ts(&c.value); + + // TODO: Docs + quote! { pub const #name: #ty = #val; } + }); + + quote! { + /// Program constants. + pub mod constants { + #(#constants)* + } + } +} + +fn parse_expr_ts(s: &str) -> proc_macro2::TokenStream { + syn::parse_str::(s).unwrap().to_token_stream() +} diff --git a/lang/attribute/program/src/declare_program/mods/cpi.rs b/lang/attribute/program/src/declare_program/mods/cpi.rs new file mode 100644 index 0000000000..05e1016a27 --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/cpi.rs @@ -0,0 +1,116 @@ +use anchor_lang_idl::types::Idl; +use heck::CamelCase; +use quote::{format_ident, quote}; + +use super::common::{convert_idl_type_to_syn_type, gen_accounts_common, gen_discriminator}; + +pub fn gen_cpi_mod(idl: &Idl) -> proc_macro2::TokenStream { + let cpi_instructions = gen_cpi_instructions(idl); + let cpi_return_type = gen_cpi_return_type(); + let cpi_accounts_mod = gen_cpi_accounts_mod(idl); + + quote! { + /// Cross program invocation (CPI) helpers. + pub mod cpi { + use super::*; + + #cpi_instructions + #cpi_return_type + #cpi_accounts_mod + } + } +} + +fn gen_cpi_instructions(idl: &Idl) -> proc_macro2::TokenStream { + let ixs = idl.instructions.iter().map(|ix| { + let method_name = format_ident!("{}", ix.name); + let accounts_ident = format_ident!("{}", ix.name.to_camel_case()); + + let args = ix.args.iter().map(|arg| { + let name = format_ident!("{}", arg.name); + let ty = convert_idl_type_to_syn_type(&arg.ty); + quote! { #name: #ty } + }); + + let arg_value = if ix.args.is_empty() { + quote! { #accounts_ident } + } else { + let fields= ix.args.iter().map(|arg| format_ident!("{}", arg.name)); + quote! { + #accounts_ident { + #(#fields),* + } + } + }; + + let discriminator = gen_discriminator(&ix.discriminator); + + let (ret_type, ret_value) = match ix.returns.as_ref() { + Some(ty) => { + let ty = convert_idl_type_to_syn_type(ty); + ( + quote! { anchor_lang::Result> }, + quote! { Ok(Return::<#ty> { phantom: std::marker::PhantomData }) }, + ) + }, + None => ( + quote! { anchor_lang::Result<()> }, + quote! { Ok(()) }, + ) + }; + + quote! { + pub fn #method_name<'a, 'b, 'c, 'info>( + ctx: anchor_lang::context::CpiContext<'a, 'b, 'c, 'info, accounts::#accounts_ident<'info>>, + #(#args),* + ) -> #ret_type { + let ix = { + let mut data = Vec::with_capacity(256); + data.extend_from_slice(&#discriminator); + AnchorSerialize::serialize(&internal::args::#arg_value, &mut data) + .map_err(|_| anchor_lang::error::ErrorCode::InstructionDidNotSerialize)?; + + let accounts = ctx.to_account_metas(None); + anchor_lang::solana_program::instruction::Instruction { + program_id: ctx.program.key(), + accounts, + data, + } + }; + + let mut acc_infos = ctx.to_account_infos(); + anchor_lang::solana_program::program::invoke_signed( + &ix, + &acc_infos, + ctx.signer_seeds, + ).map_or_else( + |e| Err(Into::into(e)), + |_| { #ret_value } + ) + } + } + }); + + quote! { + #(#ixs)* + } +} + +fn gen_cpi_return_type() -> proc_macro2::TokenStream { + quote! { + pub struct Return { + phantom: std::marker::PhantomData + } + + impl Return { + pub fn get(&self) -> T { + let (_key, data) = anchor_lang::solana_program::program::get_return_data().unwrap(); + T::try_from_slice(&data).unwrap() + } + } + } +} + +fn gen_cpi_accounts_mod(idl: &Idl) -> proc_macro2::TokenStream { + gen_accounts_common(idl, "cpi_client") +} diff --git a/lang/attribute/program/src/declare_program/mods/events.rs b/lang/attribute/program/src/declare_program/mods/events.rs new file mode 100644 index 0000000000..eff282952e --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/events.rs @@ -0,0 +1,45 @@ +use anchor_lang_idl::types::Idl; +use quote::{format_ident, quote}; + +use super::common::{convert_idl_type_def_to_ts, gen_discriminator}; + +pub fn gen_events_mod(idl: &Idl) -> proc_macro2::TokenStream { + let events = idl.events.iter().map(|ev| { + let name = format_ident!("{}", ev.name); + let discriminator = gen_discriminator(&ev.discriminator); + + let ty_def = idl + .types + .iter() + .find(|ty| ty.name == ev.name) + .map(|ty| convert_idl_type_def_to_ts(ty, &idl.types)) + .expect("Type must exist"); + + quote! { + #[derive(anchor_lang::__private::EventIndex)] + #ty_def + + impl anchor_lang::Event for #name { + fn data(&self) -> Vec { + let mut data = Vec::with_capacity(256); + data.extend_from_slice(&#discriminator); + self.serialize(&mut data).unwrap(); + data + } + } + + impl anchor_lang::Discriminator for #name { + const DISCRIMINATOR: &'static [u8] = &#discriminator; + } + } + }); + + quote! { + /// Program event type definitions. + pub mod events { + use super::*; + + #(#events)* + } + } +} diff --git a/lang/attribute/program/src/declare_program/mods/internal.rs b/lang/attribute/program/src/declare_program/mods/internal.rs new file mode 100644 index 0000000000..7152f26705 --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/internal.rs @@ -0,0 +1,174 @@ +use anchor_lang_idl::types::{Idl, IdlInstructionAccountItem}; +use anchor_syn::{ + codegen::accounts::{__client_accounts, __cpi_client_accounts}, + parser::accounts, + AccountsStruct, +}; +use heck::CamelCase; +use quote::{format_ident, quote}; + +use super::common::{convert_idl_type_to_syn_type, gen_discriminator, get_canonical_program_id}; + +pub fn gen_internal_mod(idl: &Idl) -> proc_macro2::TokenStream { + let internal_args_mod = gen_internal_args_mod(idl); + let internal_accounts_mod = gen_internal_accounts(idl); + + quote! { + #[doc(hidden)] + mod internal { + use super::*; + + #internal_args_mod + #internal_accounts_mod + } + } +} + +fn gen_internal_args_mod(idl: &Idl) -> proc_macro2::TokenStream { + let ixs = idl.instructions.iter().map(|ix| { + let ix_struct_name = format_ident!("{}", ix.name.to_camel_case()); + + let fields = ix.args.iter().map(|arg| { + let name = format_ident!("{}", arg.name); + let ty = convert_idl_type_to_syn_type(&arg.ty); + quote! { pub #name: #ty } + }); + + let ix_struct = if ix.args.is_empty() { + quote! { + pub struct #ix_struct_name; + } + } else { + quote! { + pub struct #ix_struct_name { + #(#fields),* + } + } + }; + + let discriminator = gen_discriminator(&ix.discriminator); + let impl_discriminator = quote! { + impl anchor_lang::Discriminator for #ix_struct_name { + const DISCRIMINATOR: &'static [u8] = &#discriminator; + } + }; + + let impl_ix_data = quote! { + impl anchor_lang::InstructionData for #ix_struct_name {} + }; + + let program_id = get_canonical_program_id(); + let impl_owner = quote! { + impl anchor_lang::Owner for #ix_struct_name { + fn owner() -> Pubkey { + #program_id + } + } + }; + + quote! { + /// Instruction argument + #[derive(AnchorSerialize, AnchorDeserialize)] + #ix_struct + + #impl_discriminator + #impl_ix_data + #impl_owner + } + }); + + quote! { + /// An Anchor generated module containing the program's set of instructions, where each + /// method handler in the `#[program]` mod is associated with a struct defining the input + /// arguments to the method. These should be used directly, when one wants to serialize + /// Anchor instruction data, for example, when specifying instructions instructions on a + /// client. + pub mod args { + use super::*; + + #(#ixs)* + } + } +} + +fn gen_internal_accounts(idl: &Idl) -> proc_macro2::TokenStream { + let cpi_accounts = gen_internal_accounts_common(idl, __cpi_client_accounts::generate); + let client_accounts = gen_internal_accounts_common(idl, __client_accounts::generate); + + quote! { + #cpi_accounts + #client_accounts + } +} + +fn gen_internal_accounts_common( + idl: &Idl, + gen_accounts: impl Fn(&AccountsStruct, proc_macro2::TokenStream) -> proc_macro2::TokenStream, +) -> proc_macro2::TokenStream { + let accounts = idl + .instructions + .iter() + .map(|ix| { + let ident = format_ident!("{}", ix.name.to_camel_case()); + let generics = if ix.accounts.is_empty() { + quote!() + } else { + quote!(<'info>) + }; + let accounts = ix.accounts.iter().map(|acc| match acc { + IdlInstructionAccountItem::Single(acc) => { + let name = format_ident!("{}", acc.name); + + let attrs = { + let signer = acc.signer.then(|| quote!(signer)).unwrap_or_default(); + let mt = acc.writable.then(|| quote!(mut)).unwrap_or_default(); + if signer.is_empty() { + mt + } else if mt.is_empty() { + signer + } else { + quote! { #signer, #mt } + } + }; + + let acc_expr = acc + .optional + .then(|| quote! { Option }) + .unwrap_or_else(|| quote! { AccountInfo #generics }); + + quote! { + #[account(#attrs)] + pub #name: #acc_expr + } + } + IdlInstructionAccountItem::Composite(accs) => { + let name = format_ident!("{}", accs.name); + let ty_name = idl + .instructions + .iter() + .find(|ix| ix.accounts == accs.accounts) + .map(|ix| format_ident!("{}", ix.name.to_camel_case())) + .expect("Instruction must exist"); + + quote! { + pub #name: #ty_name #generics + } + } + }); + + quote! { + #[derive(Accounts)] + pub struct #ident #generics { + #(#accounts,)* + } + } + }) + .map(|accs_struct| { + let accs_struct = syn::parse2(accs_struct).expect("Failed to parse as syn::ItemStruct"); + let accs_struct = + accounts::parse(&accs_struct).expect("Failed to parse accounts struct"); + gen_accounts(&accs_struct, get_canonical_program_id()) + }); + + quote! { #(#accounts)* } +} diff --git a/lang/attribute/program/src/declare_program/mods/mod.rs b/lang/attribute/program/src/declare_program/mods/mod.rs new file mode 100644 index 0000000000..8c9c58a45c --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/mod.rs @@ -0,0 +1,11 @@ +pub mod accounts; +pub mod client; +pub mod constants; +pub mod cpi; +pub mod events; +pub mod internal; +pub mod program; +pub mod types; +pub mod utils; + +use super::common; diff --git a/lang/attribute/program/src/declare_program/mods/program.rs b/lang/attribute/program/src/declare_program/mods/program.rs new file mode 100644 index 0000000000..46806e831d --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/program.rs @@ -0,0 +1,25 @@ +use heck::CamelCase; +use quote::{format_ident, quote}; + +use super::common::get_canonical_program_id; + +pub fn gen_program_mod(program_name: &str) -> proc_macro2::TokenStream { + let name = format_ident!("{}", program_name.to_camel_case()); + let id = get_canonical_program_id(); + quote! { + /// Program definition. + pub mod program { + use super::*; + + /// Program type + #[derive(Clone)] + pub struct #name; + + impl anchor_lang::Id for #name { + fn id() -> Pubkey { + #id + } + } + } + } +} diff --git a/lang/attribute/program/src/declare_program/mods/types.rs b/lang/attribute/program/src/declare_program/mods/types.rs new file mode 100644 index 0000000000..85449e75ba --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/types.rs @@ -0,0 +1,28 @@ +use anchor_lang_idl::types::Idl; +use quote::quote; + +use super::common::convert_idl_type_def_to_ts; + +pub fn gen_types_mod(idl: &Idl) -> proc_macro2::TokenStream { + let types = idl + .types + .iter() + .filter(|ty| { + // Skip accounts and events + !(idl.accounts.iter().any(|acc| acc.name == ty.name) + || idl.events.iter().any(|ev| ev.name == ty.name)) + }) + .map(|ty| convert_idl_type_def_to_ts(ty, &idl.types)); + + quote! { + /// Program type definitions. + /// + /// Note that account and event type definitions are not included in this module, as they + /// have their own dedicated modules. + pub mod types { + use super::*; + + #(#types)* + } + } +} diff --git a/lang/attribute/program/src/declare_program/mods/utils.rs b/lang/attribute/program/src/declare_program/mods/utils.rs new file mode 100644 index 0000000000..4629ddf102 --- /dev/null +++ b/lang/attribute/program/src/declare_program/mods/utils.rs @@ -0,0 +1,115 @@ +use anchor_lang_idl::types::Idl; +use quote::{format_ident, quote}; + +use super::common::gen_discriminator; + +pub fn gen_utils_mod(idl: &Idl) -> proc_macro2::TokenStream { + let account = gen_account(idl); + let event = gen_event(idl); + + quote! { + /// Program utilities. + pub mod utils { + use super::*; + + #account + #event + } + } +} + +fn gen_account(idl: &Idl) -> proc_macro2::TokenStream { + let variants = idl + .accounts + .iter() + .map(|acc| format_ident!("{}", acc.name)) + .map(|name| quote! { #name(#name) }); + let if_statements = idl.accounts.iter().map(|acc| { + let name = format_ident!("{}", acc.name); + let disc = gen_discriminator(&acc.discriminator); + let disc_len = acc.discriminator.len(); + quote! { + if value.starts_with(&#disc) { + return #name::try_from_slice(&value[#disc_len..]) + .map(Self::#name) + .map_err(Into::into) + } + } + }); + + quote! { + /// An enum that includes all accounts of the declared program as a tuple variant. + /// + /// See [`Self::try_from_bytes`] to create an instance from bytes. + pub enum Account { + #(#variants,)* + } + + impl Account { + /// Try to create an account based on the given bytes. + /// + /// This method returns an error if the discriminator of the given bytes don't match + /// with any of the existing accounts, or if the deserialization fails. + pub fn try_from_bytes(bytes: &[u8]) -> Result { + Self::try_from(bytes) + } + } + + impl TryFrom<&[u8]> for Account { + type Error = anchor_lang::error::Error; + + fn try_from(value: &[u8]) -> Result { + #(#if_statements)* + Err(ProgramError::InvalidArgument.into()) + } + } + } +} + +fn gen_event(idl: &Idl) -> proc_macro2::TokenStream { + let variants = idl + .events + .iter() + .map(|ev| format_ident!("{}", ev.name)) + .map(|name| quote! { #name(#name) }); + let if_statements = idl.events.iter().map(|ev| { + let name = format_ident!("{}", ev.name); + let disc = gen_discriminator(&ev.discriminator); + let disc_len = ev.discriminator.len(); + quote! { + if value.starts_with(&#disc) { + return #name::try_from_slice(&value[#disc_len..]) + .map(Self::#name) + .map_err(Into::into) + } + } + }); + + quote! { + /// An enum that includes all events of the declared program as a tuple variant. + /// + /// See [`Self::try_from_bytes`] to create an instance from bytes. + pub enum Event { + #(#variants,)* + } + + impl Event { + /// Try to create an event based on the given bytes. + /// + /// This method returns an error if the discriminator of the given bytes don't match + /// with any of the existing events, or if the deserialization fails. + pub fn try_from_bytes(bytes: &[u8]) -> Result { + Self::try_from(bytes) + } + } + + impl TryFrom<&[u8]> for Event { + type Error = anchor_lang::error::Error; + + fn try_from(value: &[u8]) -> Result { + #(#if_statements)* + Err(ProgramError::InvalidArgument.into()) + } + } + } +} diff --git a/lang/attribute/program/src/lib.rs b/lang/attribute/program/src/lib.rs index 7c506d447a..e9e8a27978 100644 --- a/lang/attribute/program/src/lib.rs +++ b/lang/attribute/program/src/lib.rs @@ -1,5 +1,8 @@ extern crate proc_macro; +mod declare_program; + +use declare_program::DeclareProgram; use quote::ToTokens; use syn::parse_macro_input; @@ -15,6 +18,46 @@ pub fn program( .into() } +/// Declare an external program based on its IDL. +/// +/// The IDL of the program must exist in a directory named `idls`. This directory can be at any +/// depth, e.g. both inside the program's directory (`/idls`) and inside Anchor +/// workspace root directory (`/../../idls`) are valid. +/// +/// # Usage +/// +/// ```rs +/// declare_program!(program_name); +/// ``` +/// +/// This generates a module named `program_name` that can be used to interact with the program +/// without having to add the program's crate as a dependency. +/// +/// Both on-chain and off-chain usage is supported. +/// +/// Use `cargo doc --open` to see the generated modules and their documentation. +/// +/// # Note +/// +/// Re-defining the same program to use the same definitions should be avoided since this results +/// in a larger binary size. +/// +/// A program should only be defined once. If you have multiple programs that depend on the same +/// definition, you should consider creating a separate crate for the external program definition +/// and reusing it in your programs. +/// +/// # Example +/// +/// A full on-chain CPI usage example can be found [here]. +/// +/// [here]: https://github.com/coral-xyz/anchor/tree/v0.30.1/tests/declare-program +#[proc_macro] +pub fn declare_program(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + parse_macro_input!(input as DeclareProgram) + .to_token_stream() + .into() +} + /// The `#[interface]` attribute is used to mark an instruction as belonging /// to an interface implementation, thus transforming its discriminator to the /// proper bytes for that interface instruction. @@ -60,3 +103,53 @@ pub fn interface( // discriminator. input } + +/// This attribute is used to override the Anchor defaults of program instructions. +/// +/// # Args +/// +/// - `discriminator`: Override the default 8-byte discriminator +/// +/// **Usage:** `discriminator = ` +/// +/// All constant expressions are supported. +/// +/// **Examples:** +/// +/// - `discriminator = 1` (shortcut for `[1]`) +/// - `discriminator = [1, 2, 3, 4]` +/// - `discriminator = b"hi"` +/// - `discriminator = MY_DISC` +/// - `discriminator = get_disc(...)` +/// +/// # Example +/// +/// ```ignore +/// use anchor_lang::prelude::*; +/// +/// declare_id!("CustomDiscriminator111111111111111111111111"); +/// +/// #[program] +/// pub mod custom_discriminator { +/// use super::*; +/// +/// #[instruction(discriminator = [1, 2, 3, 4])] +/// pub fn my_ix(_ctx: Context) -> Result<()> { +/// Ok(()) +/// } +/// } +/// +/// #[derive(Accounts)] +/// pub struct MyIx<'info> { +/// pub signer: Signer<'info>, +/// } +/// ``` +#[proc_macro_attribute] +pub fn instruction( + _args: proc_macro::TokenStream, + input: proc_macro::TokenStream, +) -> proc_macro::TokenStream { + // This macro itself is a no-op, but the `#[program]` macro will detect this attribute and use + // the arguments to transform the instruction. + input +} diff --git a/lang/derive/accounts/Cargo.toml b/lang/derive/accounts/Cargo.toml index acf307b3ae..9099584cd0 100644 --- a/lang/derive/accounts/Cargo.toml +++ b/lang/derive/accounts/Cargo.toml @@ -1,11 +1,10 @@ [package] name = "anchor-derive-accounts" -version = "0.29.0" +version = "0.30.1" authors = ["Anchor Maintainers "] repository = "https://github.com/coral-xyz/anchor" license = "Apache-2.0" description = "Anchor Derive macro for accounts" -rust-version = "1.60" edition = "2021" [lib] @@ -18,6 +17,6 @@ idl-build = ["anchor-syn/idl-build"] init-if-needed = ["anchor-syn/init-if-needed"] [dependencies] -anchor-syn = { path = "../../syn", version = "0.29.0" } +anchor-syn = { path = "../../syn", version = "0.30.1" } quote = "1" syn = { version = "1", features = ["full"] } diff --git a/lang/derive/accounts/src/lib.rs b/lang/derive/accounts/src/lib.rs index cb47c0ee40..8d73e735dd 100644 --- a/lang/derive/accounts/src/lib.rs +++ b/lang/derive/accounts/src/lib.rs @@ -591,16 +591,16 @@ use syn::parse_macro_input; ///

/// Example: ///
-/// use anchor_spl::{mint, token::{TokenAccount, Mint, Token}};
+/// use anchor_spl::token_interface::{TokenInterface, TokenAccount, Mint};
 /// ...

 /// #[account(
 ///     mint::token_program = token_a_token_program,
 /// )]
-/// pub token_a_mint: Box>,
+/// pub token_a_mint: InterfaceAccount<'info, Mint>,
 /// #[account(
 ///     mint::token_program = token_b_token_program,
 /// )]
-/// pub token_b_mint: Box>,
+/// pub token_b_mint: InterfaceAccount<'info, Mint>,
 /// #[account(
 ///     init,
 ///     payer = payer,
@@ -608,7 +608,7 @@ use syn::parse_macro_input;
 ///     token::authority = payer,
 ///     token::token_program = token_a_token_program,
 /// )]
-/// pub token_a_account: Box>,
+/// pub token_a_account: InterfaceAccount<'info, TokenAccount>,
 /// #[account(
 ///     init,
 ///     payer = payer,
@@ -616,7 +616,7 @@ use syn::parse_macro_input;
 ///     token::authority = payer,
 ///     token::token_program = token_b_token_program,
 /// )]
-/// pub token_b_account: Box>,
+/// pub token_b_account: InterfaceAccount<'info, TokenAccount>,
 /// pub token_a_token_program: Interface<'info, TokenInterface>,
 /// pub token_b_token_program: Interface<'info, TokenInterface>,
 /// #[account(mut)]
@@ -628,7 +628,7 @@ use syn::parse_macro_input;
 ///     
 /// 
 #[proc_macro_derive(Accounts, attributes(account, instruction))]
-pub fn derive_anchor_deserialize(item: TokenStream) -> TokenStream {
+pub fn derive_accounts(item: TokenStream) -> TokenStream {
     parse_macro_input!(item as anchor_syn::AccountsStruct)
         .to_token_stream()
         .into()
diff --git a/lang/derive/serde/Cargo.toml b/lang/derive/serde/Cargo.toml
index 2b4430bc1d..598d73a38c 100644
--- a/lang/derive/serde/Cargo.toml
+++ b/lang/derive/serde/Cargo.toml
@@ -1,11 +1,10 @@
 [package]
 name = "anchor-derive-serde"
-version = "0.29.0"
+version = "0.30.1"
 authors = ["Anchor Maintainers "]
 repository = "https://github.com/coral-xyz/anchor"
 license = "Apache-2.0"
 description = "Anchor Derive macro for serialization and deserialization"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -15,7 +14,7 @@ proc-macro = true
 idl-build = ["anchor-syn/idl-build"]
 
 [dependencies]
-anchor-syn = { path = "../../syn", version = "0.29.0" }
+anchor-syn = { path = "../../syn", version = "0.30.1" }
 borsh-derive-internal = ">=0.9, <0.11"
 proc-macro2 = "1"
 syn = { version = "1", features = ["full"] }
diff --git a/lang/derive/serde/src/lib.rs b/lang/derive/serde/src/lib.rs
index 248191fecd..7326697b44 100644
--- a/lang/derive/serde/src/lib.rs
+++ b/lang/derive/serde/src/lib.rs
@@ -5,9 +5,6 @@ use proc_macro::TokenStream;
 use proc_macro2::{Span, TokenStream as TokenStream2};
 use syn::{Ident, Item};
 
-#[cfg(feature = "idl-build")]
-use {anchor_syn::idl::build::*, quote::quote};
-
 fn gen_borsh_serialize(input: TokenStream) -> TokenStream2 {
     let cratename = Ident::new("borsh", Span::call_site());
 
@@ -35,15 +32,13 @@ pub fn anchor_serialize(input: TokenStream) -> TokenStream {
 
     #[cfg(feature = "idl-build")]
     {
-        let no_docs = get_no_docs();
+        use anchor_syn::idl::*;
+        use quote::quote;
 
         let idl_build_impl = match syn::parse(input).unwrap() {
-            Item::Struct(item) => gen_idl_build_impl_for_struct(&item, no_docs),
-            Item::Enum(item) => gen_idl_build_impl_for_enum(item, no_docs),
-            Item::Union(item) => {
-                // unions are not included in the IDL - TODO print a warning
-                idl_build_impl_skeleton(quote! {None}, quote! {}, &item.ident, &item.generics)
-            }
+            Item::Struct(item) => impl_idl_build_struct(&item),
+            Item::Enum(item) => impl_idl_build_enum(&item),
+            Item::Union(item) => impl_idl_build_union(&item),
             // Derive macros can only be defined on structs, enums, and unions.
             _ => unreachable!(),
         };
diff --git a/lang/derive/space/Cargo.toml b/lang/derive/space/Cargo.toml
index d5a4249d15..a61242f8a2 100644
--- a/lang/derive/space/Cargo.toml
+++ b/lang/derive/space/Cargo.toml
@@ -1,11 +1,10 @@
 [package]
 name = "anchor-derive-space"
-version = "0.29.0"
+version = "0.30.1"
 authors = ["Anchor Maintainers "]
 repository = "https://github.com/coral-xyz/anchor"
 license = "Apache-2.0"
 description = "Anchor Derive macro to automatically calculate the size of a structure or an enum"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
diff --git a/lang/derive/space/src/lib.rs b/lang/derive/space/src/lib.rs
index f60565a9df..deabb76b5d 100644
--- a/lang/derive/space/src/lib.rs
+++ b/lang/derive/space/src/lib.rs
@@ -4,8 +4,8 @@ use proc_macro::TokenStream;
 use proc_macro2::{Ident, TokenStream as TokenStream2, TokenTree};
 use quote::{quote, quote_spanned, ToTokens};
 use syn::{
-    parse::ParseStream, parse2, parse_macro_input, Attribute, DeriveInput, Fields, GenericArgument,
-    LitInt, PathArguments, Type, TypeArray,
+    parse::ParseStream, parse2, parse_macro_input, punctuated::Punctuated, token::Comma, Attribute,
+    DeriveInput, Field, Fields, GenericArgument, LitInt, PathArguments, Type, TypeArray,
 };
 
 /// Implements a [`Space`](./trait.Space.html) trait on the given
@@ -41,22 +41,30 @@ pub fn derive_init_space(item: TokenStream) -> TokenStream {
     let (impl_generics, ty_generics, where_clause) = input.generics.split_for_impl();
     let name = input.ident;
 
+    let process_struct_fields = |fields: Punctuated| {
+        let recurse = fields.into_iter().map(|f| {
+            let mut max_len_args = get_max_len_args(&f.attrs);
+            len_from_type(f.ty, &mut max_len_args)
+        });
+
+        quote! {
+            #[automatically_derived]
+            impl #impl_generics anchor_lang::Space for #name #ty_generics #where_clause {
+                const INIT_SPACE: usize = 0 #(+ #recurse)*;
+            }
+        }
+    };
+
     let expanded: TokenStream2 = match input.data {
         syn::Data::Struct(strct) => match strct.fields {
-            Fields::Named(named) => {
-                let recurse = named.named.into_iter().map(|f| {
-                    let mut max_len_args = get_max_len_args(&f.attrs);
-                    len_from_type(f.ty, &mut max_len_args)
-                });
-
-                quote! {
-                    #[automatically_derived]
-                    impl #impl_generics anchor_lang::Space for #name #ty_generics #where_clause {
-                        const INIT_SPACE: usize = 0 #(+ #recurse)*;
-                    }
+            Fields::Named(named) => process_struct_fields(named.named),
+            Fields::Unnamed(unnamed) => process_struct_fields(unnamed.unnamed),
+            Fields::Unit => quote! {
+                #[automatically_derived]
+                impl #impl_generics anchor_lang::Space for #name #ty_generics #where_clause {
+                    const INIT_SPACE: usize = 0;
                 }
-            }
-            _ => panic!("Please use named fields in account structure"),
+            },
         },
         syn::Data::Enum(enm) => {
             let variants = enm.variants.into_iter().map(|v| {
diff --git a/lang/src/accounts/account.rs b/lang/src/accounts/account.rs
index b027d57f83..0ba1e974b0 100644
--- a/lang/src/accounts/account.rs
+++ b/lang/src/accounts/account.rs
@@ -86,6 +86,7 @@ use std::ops::{Deref, DerefMut};
 /// those programs are not annotated with `#[account]` so you have to
 /// - create a wrapper type around the structs you want to wrap with Account
 /// - implement the functions required by Account yourself
+///
 /// instead of using `#[account]`. You only have to implement a fraction of the
 /// functions `#[account]` generates. See the example below for the code you have
 /// to write.
@@ -257,8 +258,7 @@ impl<'a, T: AccountSerialize + AccountDeserialize + Clone> Account<'a, T> {
     ) -> Result<()> {
         // Only persist if the owner is the current program and the account is not closed.
         if expected_owner == program_id && !crate::common::is_closed(self.info) {
-            let info = self.to_account_info();
-            let mut data = info.try_borrow_mut_data()?;
+            let mut data = self.info.try_borrow_mut_data()?;
             let dst: &mut [u8] = &mut data;
             let mut writer = BpfWriter::new(dst);
             self.account.try_serialize(&mut writer)?;
diff --git a/lang/src/accounts/account_loader.rs b/lang/src/accounts/account_loader.rs
index caae3057af..a7392299e6 100644
--- a/lang/src/accounts/account_loader.rs
+++ b/lang/src/accounts/account_loader.rs
@@ -6,7 +6,6 @@ use crate::{
     Accounts, AccountsClose, AccountsExit, Key, Owner, Result, ToAccountInfo, ToAccountInfos,
     ToAccountMetas, ZeroCopy,
 };
-use arrayref::array_ref;
 use solana_program::account_info::AccountInfo;
 use solana_program::instruction::AccountMeta;
 use solana_program::pubkey::Pubkey;
@@ -24,7 +23,7 @@ use std::ops::DerefMut;
 /// for example, the [`Account`](crate::accounts::account::Account). Namely,
 /// one must call
 /// - `load_init` after initializing an account (this will ignore the missing
-/// account discriminator that gets added only after the user's instruction code)
+///    account discriminator that gets added only after the user's instruction code)
 /// - `load` when the account is not mutable
 /// - `load_mut` when the account is mutable
 ///
@@ -123,13 +122,15 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
             return Err(Error::from(ErrorCode::AccountOwnedByWrongProgram)
                 .with_pubkeys((*acc_info.owner, T::owner())));
         }
-        let data: &[u8] = &acc_info.try_borrow_data()?;
-        if data.len() < T::discriminator().len() {
+
+        let data = &acc_info.try_borrow_data()?;
+        let disc = T::DISCRIMINATOR;
+        if data.len() < disc.len() {
             return Err(ErrorCode::AccountDiscriminatorNotFound.into());
         }
-        // Discriminator must match.
-        let disc_bytes = array_ref![data, 0, 8];
-        if disc_bytes != &T::discriminator() {
+
+        let given_disc = &data[..disc.len()];
+        if given_disc != disc {
             return Err(ErrorCode::AccountDiscriminatorMismatch.into());
         }
 
@@ -152,17 +153,18 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
     /// Returns a Ref to the account data structure for reading.
     pub fn load(&self) -> Result> {
         let data = self.acc_info.try_borrow_data()?;
-        if data.len() < T::discriminator().len() {
+        let disc = T::DISCRIMINATOR;
+        if data.len() < disc.len() {
             return Err(ErrorCode::AccountDiscriminatorNotFound.into());
         }
 
-        let disc_bytes = array_ref![data, 0, 8];
-        if disc_bytes != &T::discriminator() {
+        let given_disc = &data[..disc.len()];
+        if given_disc != disc {
             return Err(ErrorCode::AccountDiscriminatorMismatch.into());
         }
 
         Ok(Ref::map(data, |data| {
-            bytemuck::from_bytes(&data[8..mem::size_of::() + 8])
+            bytemuck::from_bytes(&data[disc.len()..mem::size_of::() + disc.len()])
         }))
     }
 
@@ -175,17 +177,20 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
         }
 
         let data = self.acc_info.try_borrow_mut_data()?;
-        if data.len() < T::discriminator().len() {
+        let disc = T::DISCRIMINATOR;
+        if data.len() < disc.len() {
             return Err(ErrorCode::AccountDiscriminatorNotFound.into());
         }
 
-        let disc_bytes = array_ref![data, 0, 8];
-        if disc_bytes != &T::discriminator() {
+        let given_disc = &data[..disc.len()];
+        if given_disc != disc {
             return Err(ErrorCode::AccountDiscriminatorMismatch.into());
         }
 
         Ok(RefMut::map(data, |data| {
-            bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::() + 8])
+            bytemuck::from_bytes_mut(
+                &mut data.deref_mut()[disc.len()..mem::size_of::() + disc.len()],
+            )
         }))
     }
 
@@ -201,15 +206,17 @@ impl<'info, T: ZeroCopy + Owner> AccountLoader<'info, T> {
         let data = self.acc_info.try_borrow_mut_data()?;
 
         // The discriminator should be zero, since we're initializing.
-        let mut disc_bytes = [0u8; 8];
-        disc_bytes.copy_from_slice(&data[..8]);
-        let discriminator = u64::from_le_bytes(disc_bytes);
-        if discriminator != 0 {
+        let disc = T::DISCRIMINATOR;
+        let given_disc = &data[..disc.len()];
+        let has_disc = given_disc.iter().any(|b| *b != 0);
+        if has_disc {
             return Err(ErrorCode::AccountDiscriminatorAlreadySet.into());
         }
 
         Ok(RefMut::map(data, |data| {
-            bytemuck::from_bytes_mut(&mut data.deref_mut()[8..mem::size_of::() + 8])
+            bytemuck::from_bytes_mut(
+                &mut data.deref_mut()[disc.len()..mem::size_of::() + disc.len()],
+            )
         }))
     }
 }
@@ -241,7 +248,7 @@ impl<'info, T: ZeroCopy + Owner> AccountsExit<'info> for AccountLoader<'info, T>
             let mut data = self.acc_info.try_borrow_mut_data()?;
             let dst: &mut [u8] = &mut data;
             let mut writer = BpfWriter::new(dst);
-            writer.write_all(&T::discriminator()).unwrap();
+            writer.write_all(T::DISCRIMINATOR).unwrap();
         }
         Ok(())
     }
diff --git a/lang/src/accounts/interface.rs b/lang/src/accounts/interface.rs
index 90e331538a..b5cf1f181d 100644
--- a/lang/src/accounts/interface.rs
+++ b/lang/src/accounts/interface.rs
@@ -59,9 +59,9 @@ use std::ops::Deref;
 /// The required constraints are as follows:
 ///
 /// - `program` is the account of the program itself.
-/// Its constraint checks that `program_data` is the account that contains the program's upgrade authority.
-/// Implicitly, this checks that `program` is a BPFUpgradeable program (`program.programdata_address()?`
-/// will be `None` if it's not).
+///    Its constraint checks that `program_data` is the account that contains the program's upgrade authority.
+///    Implicitly, this checks that `program` is a BPFUpgradeable program (`program.programdata_address()?`
+///    will be `None` if it's not).
 /// - `program_data`'s constraint checks that its upgrade authority is the `authority` account.
 /// - Finally, `authority` needs to sign the transaction.
 ///
diff --git a/lang/src/accounts/interface_account.rs b/lang/src/accounts/interface_account.rs
index 5401641725..fd2a6e1695 100644
--- a/lang/src/accounts/interface_account.rs
+++ b/lang/src/accounts/interface_account.rs
@@ -86,6 +86,7 @@ use std::ops::{Deref, DerefMut};
 /// those programs are not annotated with `#[account]` so you have to
 /// - create a wrapper type around the structs you want to wrap with InterfaceAccount
 /// - implement the functions required by InterfaceAccount yourself
+///
 /// instead of using `#[account]`. You only have to implement a fraction of the
 /// functions `#[account]` generates. See the example below for the code you have
 /// to write.
diff --git a/lang/src/accounts/program.rs b/lang/src/accounts/program.rs
index ac232c4042..1058b62a58 100644
--- a/lang/src/accounts/program.rs
+++ b/lang/src/accounts/program.rs
@@ -9,7 +9,6 @@ use solana_program::bpf_loader_upgradeable::{self, UpgradeableLoaderState};
 use solana_program::instruction::AccountMeta;
 use solana_program::pubkey::Pubkey;
 use std::collections::BTreeSet;
-use std::convert::TryFrom;
 use std::fmt;
 use std::marker::PhantomData;
 use std::ops::Deref;
@@ -60,9 +59,9 @@ use std::ops::Deref;
 /// The required constraints are as follows:
 ///
 /// - `program` is the account of the program itself.
-/// Its constraint checks that `program_data` is the account that contains the program's upgrade authority.
-/// Implicitly, this checks that `program` is a BPFUpgradeable program (`program.programdata_address()?`
-/// will be `None` if it's not).
+///    Its constraint checks that `program_data` is the account that contains the program's upgrade authority.
+///    Implicitly, this checks that `program` is a BPFUpgradeable program (`program.programdata_address()?`
+///    will be `None` if it's not).
 /// - `program_data`'s constraint checks that its upgrade authority is the `authority` account.
 /// - Finally, `authority` needs to sign the transaction.
 ///
diff --git a/lang/src/accounts/system_account.rs b/lang/src/accounts/system_account.rs
index a2ddd6928c..ae895c864a 100644
--- a/lang/src/accounts/system_account.rs
+++ b/lang/src/accounts/system_account.rs
@@ -2,11 +2,7 @@
 
 use crate::error::ErrorCode;
 use crate::*;
-use solana_program::account_info::AccountInfo;
-use solana_program::instruction::AccountMeta;
-use solana_program::pubkey::Pubkey;
 use solana_program::system_program;
-use std::collections::BTreeSet;
 use std::ops::Deref;
 
 /// Type validating that the account is owned by the system program
diff --git a/lang/src/bpf_upgradeable_state.rs b/lang/src/bpf_upgradeable_state.rs
index 9da8385619..2f0c806fd9 100644
--- a/lang/src/bpf_upgradeable_state.rs
+++ b/lang/src/bpf_upgradeable_state.rs
@@ -72,3 +72,13 @@ impl AccountDeserialize for UpgradeableLoaderState {
         bincode::deserialize(buf).map_err(|_| ProgramError::InvalidAccountData.into())
     }
 }
+
+#[cfg(feature = "idl-build")]
+mod idl_build {
+    use super::*;
+
+    impl crate::IdlBuild for ProgramData {}
+    impl crate::Discriminator for ProgramData {
+        const DISCRIMINATOR: &'static [u8] = &[];
+    }
+}
diff --git a/lang/src/error.rs b/lang/src/error.rs
index 09ea04366c..6652811a77 100644
--- a/lang/src/error.rs
+++ b/lang/src/error.rs
@@ -2,6 +2,7 @@ use anchor_lang::error_code;
 use borsh::maybestd::io::Error as BorshIoError;
 use solana_program::{program_error::ProgramError, pubkey::Pubkey};
 use std::fmt::{Debug, Display};
+use std::num::TryFromIntError;
 
 /// The starting point for user defined error codes.
 pub const ERROR_CODE_OFFSET: u32 = 6000;
@@ -20,8 +21,8 @@ pub const ERROR_CODE_OFFSET: u32 = 6000;
 #[error_code(offset = 0)]
 pub enum ErrorCode {
     // Instructions
-    /// 100 - 8 byte instruction identifier not provided
-    #[msg("8 byte instruction identifier not provided")]
+    /// 100 - Instruction discriminator not provided
+    #[msg("Instruction discriminator not provided")]
     InstructionMissing = 100,
     /// 101 - Fallback functions are not supported
     #[msg("Fallback functions are not supported")]
@@ -126,6 +127,56 @@ pub enum ErrorCode {
     /// 2023 - A mint token program constraint was violated
     #[msg("An associated token account token program constraint was violated")]
     ConstraintAssociatedTokenTokenProgram,
+    /// Extension constraints
+    ///
+    /// 2024 - A group pointer extension constraint was violated
+    #[msg("A group pointer extension constraint was violated")]
+    ConstraintMintGroupPointerExtension,
+    /// 2025 - A group pointer extension authority constraint was violated
+    #[msg("A group pointer extension authority constraint was violated")]
+    ConstraintMintGroupPointerExtensionAuthority,
+    /// 2026 - A group pointer extension group address constraint was violated
+    #[msg("A group pointer extension group address constraint was violated")]
+    ConstraintMintGroupPointerExtensionGroupAddress,
+    /// 2027 - A group member pointer extension constraint was violated
+    #[msg("A group member pointer extension constraint was violated")]
+    ConstraintMintGroupMemberPointerExtension,
+    /// 2028 - A group member pointer extension authority constraint was violated
+    #[msg("A group member pointer extension authority constraint was violated")]
+    ConstraintMintGroupMemberPointerExtensionAuthority,
+    /// 2029 - A group member pointer extension member address constraint was violated
+    #[msg("A group member pointer extension group address constraint was violated")]
+    ConstraintMintGroupMemberPointerExtensionMemberAddress,
+    /// 2030 - A metadata pointer extension constraint was violated
+    #[msg("A metadata pointer extension constraint was violated")]
+    ConstraintMintMetadataPointerExtension,
+    /// 2031 - A metadata pointer extension authority constraint was violated
+    #[msg("A metadata pointer extension authority constraint was violated")]
+    ConstraintMintMetadataPointerExtensionAuthority,
+    /// 2032 - A metadata pointer extension metadata address constraint was violated
+    #[msg("A metadata pointer extension metadata address constraint was violated")]
+    ConstraintMintMetadataPointerExtensionMetadataAddress,
+    /// 2033 - A close authority extension constraint was violated
+    #[msg("A close authority constraint was violated")]
+    ConstraintMintCloseAuthorityExtension,
+    /// 2034 - A close authority extension authority constraint was violated
+    #[msg("A close authority extension authority constraint was violated")]
+    ConstraintMintCloseAuthorityExtensionAuthority,
+    /// 2035 - A permanent delegate extension constraint was violated
+    #[msg("A permanent delegate extension constraint was violated")]
+    ConstraintMintPermanentDelegateExtension,
+    /// 2036 - A permanent delegate extension authority constraint was violated
+    #[msg("A permanent delegate extension delegate constraint was violated")]
+    ConstraintMintPermanentDelegateExtensionDelegate,
+    /// 2037 - A transfer hook extension constraint was violated
+    #[msg("A transfer hook extension constraint was violated")]
+    ConstraintMintTransferHookExtension,
+    /// 2038 - A transfer hook extension authority constraint was violated
+    #[msg("A transfer hook extension authority constraint was violated")]
+    ConstraintMintTransferHookExtensionAuthority,
+    /// 2039 - A transfer hook extension transfer hook program id constraint was violated
+    #[msg("A transfer hook extension transfer hook program id constraint was violated")]
+    ConstraintMintTransferHookExtensionProgramId,
 
     // Require
     /// 2500 - A require expression was violated
@@ -154,11 +205,11 @@ pub enum ErrorCode {
     /// 3000 - The account discriminator was already set on this account
     #[msg("The account discriminator was already set on this account")]
     AccountDiscriminatorAlreadySet = 3000,
-    /// 3001 - No 8 byte discriminator was found on the account
-    #[msg("No 8 byte discriminator was found on the account")]
+    /// 3001 - No discriminator was found on the account
+    #[msg("No discriminator was found on the account")]
     AccountDiscriminatorNotFound,
-    /// 3002 - 8 byte discriminator did not match what was expected
-    #[msg("8 byte discriminator did not match what was expected")]
+    /// 3002 - Account discriminator did not match what was expected
+    #[msg("Account discriminator did not match what was expected")]
     AccountDiscriminatorMismatch,
     /// 3003 - Failed to deserialize the account
     #[msg("Failed to deserialize the account")]
@@ -213,6 +264,9 @@ pub enum ErrorCode {
     /// 4101 - You cannot/should not initialize the payer account as a program account
     #[msg("You cannot/should not initialize the payer account as a program account")]
     TryingToInitPayerAsProgramAccount = 4101,
+    /// 4102 - Invalid numeric conversion error
+    #[msg("Error during numeric conversion")]
+    InvalidNumericConversion = 4102,
 
     // Deprecated
     /// 5000 - The API being used is deprecated and should no longer be used
@@ -260,6 +314,18 @@ impl From for Error {
     }
 }
 
+impl From for Error {
+    fn from(e: TryFromIntError) -> Self {
+        Self::AnchorError(Box::new(AnchorError {
+            error_name: ErrorCode::InvalidNumericConversion.name(),
+            error_code_number: ErrorCode::InvalidNumericConversion.into(),
+            error_msg: format!("{}", e),
+            error_origin: None,
+            compared_values: None,
+        }))
+    }
+}
+
 impl Error {
     pub fn log(&self) {
         match self {
diff --git a/lang/src/event.rs b/lang/src/event.rs
index 99f2abde12..8991ce4d92 100644
--- a/lang/src/event.rs
+++ b/lang/src/event.rs
@@ -1,3 +1,3 @@
 // Sha256(anchor:event)[..8]
 pub const EVENT_IX_TAG: u64 = 0x1d9acb512ea545e4;
-pub const EVENT_IX_TAG_LE: [u8; 8] = EVENT_IX_TAG.to_le_bytes();
+pub const EVENT_IX_TAG_LE: &[u8] = EVENT_IX_TAG.to_le_bytes().as_slice();
diff --git a/lang/src/idl.rs b/lang/src/idl.rs
index 24544bd482..5dd19ce69f 100644
--- a/lang/src/idl.rs
+++ b/lang/src/idl.rs
@@ -18,7 +18,6 @@
 //! Anchor programs. To remove them, one can use the `no-idl` feature.
 
 use crate::prelude::*;
-use solana_program::pubkey::Pubkey;
 
 // The first 8 bytes of an instruction to create or modify the IDL account. This
 // instruction is defined outside the main program's instruction enum, so that
@@ -26,7 +25,7 @@ use solana_program::pubkey::Pubkey;
 //
 // Sha256(anchor:idl)[..8];
 pub const IDL_IX_TAG: u64 = 0x0a69e9a778bcf440;
-pub const IDL_IX_TAG_LE: [u8; 8] = IDL_IX_TAG.to_le_bytes();
+pub const IDL_IX_TAG_LE: &[u8] = IDL_IX_TAG.to_le_bytes().as_slice();
 
 // The Pubkey that is stored as the 'authority' on the IdlAccount when the authority
 // is "erased".
@@ -79,3 +78,6 @@ impl IdlAccount {
         "anchor:idl"
     }
 }
+
+#[cfg(feature = "idl-build")]
+pub use anchor_lang_idl::{build::IdlBuild, *};
diff --git a/lang/src/lib.rs b/lang/src/lib.rs
index 9ad5bdf818..5fb3b24fb7 100644
--- a/lang/src/lib.rs
+++ b/lang/src/lib.rs
@@ -28,6 +28,7 @@ extern crate self as anchor_lang;
 use bytemuck::{Pod, Zeroable};
 use solana_program::account_info::AccountInfo;
 use solana_program::instruction::AccountMeta;
+use solana_program::program_error::ProgramError;
 use solana_program::pubkey::Pubkey;
 use std::{collections::BTreeSet, fmt::Debug, io::Write};
 
@@ -47,11 +48,11 @@ pub mod system_program;
 mod vec;
 pub use crate::bpf_upgradeable_state::*;
 pub use anchor_attribute_access_control::access_control;
-pub use anchor_attribute_account::{account, declare_id, zero_copy};
+pub use anchor_attribute_account::{account, declare_id, pubkey, zero_copy};
 pub use anchor_attribute_constant::constant;
 pub use anchor_attribute_error::*;
 pub use anchor_attribute_event::{emit, event};
-pub use anchor_attribute_program::program;
+pub use anchor_attribute_program::{declare_program, instruction, program};
 pub use anchor_derive_accounts::Accounts;
 pub use anchor_derive_serde::{AnchorDeserialize, AnchorSerialize};
 pub use anchor_derive_space::InitSpace;
@@ -65,7 +66,7 @@ pub use solana_program;
 pub use anchor_attribute_event::{emit_cpi, event_cpi};
 
 #[cfg(feature = "idl-build")]
-pub use anchor_syn::{self, idl::build::IdlBuild};
+pub use idl::IdlBuild;
 
 #[cfg(feature = "interface-instructions")]
 pub use anchor_attribute_program::interface;
@@ -186,36 +187,42 @@ pub trait Lamports<'info>: AsRef> {
 
     /// Add lamports to the account.
     ///
-    /// This method is useful for transfering lamports from a PDA.
+    /// This method is useful for transferring lamports from a PDA.
     ///
     /// # Requirements
     ///
     /// 1. The account must be marked `mut`.
     /// 2. The total lamports **before** the transaction must equal to total lamports **after**
-    /// the transaction.
+    ///    the transaction.
     /// 3. `lamports` field of the account info should not currently be borrowed.
     ///
     /// See [`Lamports::sub_lamports`] for subtracting lamports.
     fn add_lamports(&self, amount: u64) -> Result<&Self> {
-        **self.as_ref().try_borrow_mut_lamports()? += amount;
+        **self.as_ref().try_borrow_mut_lamports()? = self
+            .get_lamports()
+            .checked_add(amount)
+            .ok_or(ProgramError::ArithmeticOverflow)?;
         Ok(self)
     }
 
     /// Subtract lamports from the account.
     ///
-    /// This method is useful for transfering lamports from a PDA.
+    /// This method is useful for transferring lamports from a PDA.
     ///
     /// # Requirements
     ///
     /// 1. The account must be owned by the executing program.
     /// 2. The account must be marked `mut`.
     /// 3. The total lamports **before** the transaction must equal to total lamports **after**
-    /// the transaction.
+    ///    the transaction.
     /// 4. `lamports` field of the account info should not currently be borrowed.
     ///
     /// See [`Lamports::add_lamports`] for adding lamports.
     fn sub_lamports(&self, amount: u64) -> Result<&Self> {
-        **self.as_ref().try_borrow_mut_lamports()? -= amount;
+        **self.as_ref().try_borrow_mut_lamports()? = self
+            .get_lamports()
+            .checked_sub(amount)
+            .ok_or(ProgramError::ArithmeticOverflow)?;
         Ok(self)
     }
 }
@@ -272,7 +279,7 @@ pub trait ZeroCopy: Discriminator + Copy + Clone + Zeroable + Pod {}
 pub trait InstructionData: Discriminator + AnchorSerialize {
     fn data(&self) -> Vec {
         let mut data = Vec::with_capacity(256);
-        data.extend_from_slice(&Self::discriminator());
+        data.extend_from_slice(Self::DISCRIMINATOR);
         self.serialize(&mut data).unwrap();
         data
     }
@@ -283,7 +290,7 @@ pub trait InstructionData: Discriminator + AnchorSerialize {
     /// necessary), and because the data field in `Instruction` expects a `Vec`.
     fn write_to(&self, mut data: &mut Vec) {
         data.clear();
-        data.extend_from_slice(&Self::DISCRIMINATOR);
+        data.extend_from_slice(Self::DISCRIMINATOR);
         self.serialize(&mut data).unwrap()
     }
 }
@@ -293,20 +300,9 @@ pub trait Event: AnchorSerialize + AnchorDeserialize + Discriminator {
     fn data(&self) -> Vec;
 }
 
-// The serialized event data to be emitted via a Solana log.
-// TODO: remove this on the next major version upgrade.
-#[doc(hidden)]
-#[deprecated(since = "0.4.2", note = "Please use Event instead")]
-pub trait EventData: AnchorSerialize + Discriminator {
-    fn data(&self) -> Vec;
-}
-
 /// 8 byte unique identifier for a type.
 pub trait Discriminator {
-    const DISCRIMINATOR: [u8; 8];
-    fn discriminator() -> [u8; 8] {
-        Self::DISCRIMINATOR
-    }
+    const DISCRIMINATOR: &'static [u8];
 }
 
 /// Defines the space of an account for initialization.
@@ -392,12 +388,14 @@ pub mod prelude {
         accounts::interface_account::InterfaceAccount, accounts::program::Program,
         accounts::signer::Signer, accounts::system_account::SystemAccount,
         accounts::sysvar::Sysvar, accounts::unchecked_account::UncheckedAccount, constant,
-        context::Context, context::CpiContext, declare_id, emit, err, error, event, program,
-        require, require_eq, require_gt, require_gte, require_keys_eq, require_keys_neq,
-        require_neq, solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, source,
+        context::Context, context::CpiContext, declare_id, declare_program, emit, err, error,
+        event, instruction, program, pubkey, require, require_eq, require_gt, require_gte,
+        require_keys_eq, require_keys_neq, require_neq,
+        solana_program::bpf_loader_upgradeable::UpgradeableLoaderState, source,
         system_program::System, zero_copy, AccountDeserialize, AccountSerialize, Accounts,
-        AccountsClose, AccountsExit, AnchorDeserialize, AnchorSerialize, Id, InitSpace, Key,
-        Lamports, Owner, ProgramData, Result, Space, ToAccountInfo, ToAccountInfos, ToAccountMetas,
+        AccountsClose, AccountsExit, AnchorDeserialize, AnchorSerialize, Discriminator, Id,
+        InitSpace, Key, Lamports, Owner, ProgramData, Result, Space, ToAccountInfo, ToAccountInfos,
+        ToAccountMetas,
     };
     pub use anchor_attribute_error::*;
     pub use borsh;
@@ -422,7 +420,7 @@ pub mod prelude {
     pub use super::{emit_cpi, event_cpi};
 
     #[cfg(feature = "idl-build")]
-    pub use super::IdlBuild;
+    pub use super::idl::IdlBuild;
 
     #[cfg(feature = "interface-instructions")]
     pub use super::interface;
diff --git a/lang/syn/Cargo.toml b/lang/syn/Cargo.toml
index 3a9dca8360..53304f0cfe 100644
--- a/lang/syn/Cargo.toml
+++ b/lang/syn/Cargo.toml
@@ -1,11 +1,10 @@
 [package]
 name = "anchor-syn"
-version = "0.29.0"
+version = "0.30.1"
 authors = ["Anchor Maintainers "]
 repository = "https://github.com/coral-xyz/anchor"
 license = "Apache-2.0"
 description = "Anchor syntax parsing and code generation tools"
-rust-version = "1.60"
 edition = "2021"
 
 [package.metadata.docs.rs]
@@ -17,12 +16,9 @@ allow-missing-optionals = []
 anchor-debug = []
 event-cpi = []
 hash = []
-idl-build = ["idl-parse", "idl-types"]
-idl-parse = ["idl-types"]
-idl-types = []
+idl-build = ["cargo_toml"]
 init-if-needed = []
 interface-instructions = []
-seeds = []
 
 [dependencies]
 anyhow = "1"
@@ -35,3 +31,10 @@ serde_json = "1"
 sha2 = "0.10"
 syn = { version = "1", features = ["full", "extra-traits", "parsing"] }
 thiserror = "1"
+
+# `idl-build` feature only
+cargo_toml = { version = "0.19", optional = true }
+
+# https://blog.rust-lang.org/2024/05/06/check-cfg.html#expecting-custom-cfgs
+[lints.rust]
+unexpected_cfgs = { level = "allow", check-cfg = ["cfg(procmacro2_semver_exempt)"] }
diff --git a/lang/syn/src/codegen/accounts/__client_accounts.rs b/lang/syn/src/codegen/accounts/__client_accounts.rs
index 5433beaf4f..53c6fc9276 100644
--- a/lang/syn/src/codegen/accounts/__client_accounts.rs
+++ b/lang/syn/src/codegen/accounts/__client_accounts.rs
@@ -6,7 +6,10 @@ use std::str::FromStr;
 // Generates the private `__client_accounts` mod implementation, containing
 // a generated struct mapping 1-1 to the `Accounts` struct, except with
 // `Pubkey`s as the types. This is generated for Rust *clients*.
-pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
+pub fn generate(
+    accs: &AccountsStruct,
+    program_id: proc_macro2::TokenStream,
+) -> proc_macro2::TokenStream {
     let name = &accs.ident;
     let account_mod_name: proc_macro2::TokenStream = format!(
         "__client_accounts_{}",
@@ -103,7 +106,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
                         if let Some(#name) = &self.#name {
                             account_metas.push(#meta(*#name, #is_signer));
                         } else {
-                            account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new_readonly(crate::ID, false));
+                            account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new_readonly(#program_id, false));
                         }
                     }
                 } else {
@@ -117,7 +120,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
     // Re-export all composite account structs (i.e. other structs deriving
     // accounts embedded into this struct. Required because, these embedded
     // structs are *not* visible from the #[program] macro, which is responsible
-    // for generating the `accounts` mod, which aggregates all the the generated
+    // for generating the `accounts` mod, which aggregates all the generated
     // accounts used for structs.
     let re_exports: Vec = {
         // First, dedup the exports.
diff --git a/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs b/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs
index 57b4f53730..5211e59305 100644
--- a/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs
+++ b/lang/syn/src/codegen/accounts/__cpi_client_accounts.rs
@@ -7,7 +7,10 @@ use quote::quote;
 // Generates the private `__cpi_client_accounts` mod implementation, containing
 // a generated struct mapping 1-1 to the `Accounts` struct, except with
 // `AccountInfo`s as the types. This is generated for CPI clients.
-pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
+pub fn generate(
+    accs: &AccountsStruct,
+    program_id: proc_macro2::TokenStream,
+) -> proc_macro2::TokenStream {
     let name = &accs.ident;
     let account_mod_name: proc_macro2::TokenStream = format!(
         "__cpi_client_accounts_{}",
@@ -104,7 +107,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
                         if let Some(#name) = &self.#name {
                             account_metas.push(#meta(anchor_lang::Key::key(#name), #is_signer));
                         } else {
-                            account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new_readonly(crate::ID, false));
+                            account_metas.push(anchor_lang::solana_program::instruction::AccountMeta::new_readonly(#program_id, false));
                         }
                     }
                 } else {
@@ -130,7 +133,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
     // Re-export all composite account structs (i.e. other structs deriving
     // accounts embedded into this struct. Required because, these embedded
     // structs are *not* visible from the #[program] macro, which is responsible
-    // for generating the `accounts` mod, which aggregates all the the generated
+    // for generating the `accounts` mod, which aggregates all the generated
     // accounts used for structs.
     let re_exports: Vec = {
         // First, dedup the exports.
diff --git a/lang/syn/src/codegen/accounts/constraints.rs b/lang/syn/src/codegen/accounts/constraints.rs
index 0418501df8..1683d582fe 100644
--- a/lang/syn/src/codegen/accounts/constraints.rs
+++ b/lang/syn/src/codegen/accounts/constraints.rs
@@ -1,6 +1,5 @@
 use quote::quote;
 use std::collections::HashSet;
-use syn::Expr;
 
 use crate::*;
 
@@ -199,6 +198,9 @@ pub fn generate_constraint_init(
 }
 
 pub fn generate_constraint_zeroed(f: &Field, _c: &ConstraintZeroed) -> proc_macro2::TokenStream {
+    let account_ty = f.account_ty();
+    let discriminator = quote! { #account_ty::DISCRIMINATOR };
+
     let field = &f.ident;
     let name_str = field.to_string();
     let ty_decl = f.ty_decl(true);
@@ -206,10 +208,9 @@ pub fn generate_constraint_zeroed(f: &Field, _c: &ConstraintZeroed) -> proc_macr
     quote! {
         let #field: #ty_decl = {
             let mut __data: &[u8] = &#field.try_borrow_data()?;
-            let mut __disc_bytes = [0u8; 8];
-            __disc_bytes.copy_from_slice(&__data[..8]);
-            let __discriminator = u64::from_le_bytes(__disc_bytes);
-            if __discriminator != 0 {
+            let __disc = &__data[..#discriminator.len()];
+            let __has_disc = __disc.iter().any(|b| *b != 0);
+            if __has_disc {
                 return Err(anchor_lang::error::Error::from(anchor_lang::error::ErrorCode::ConstraintZero).with_account_name(#name_str));
             }
             #from_account_info
@@ -304,6 +305,13 @@ pub fn generate_constraint_raw(ident: &Ident, c: &ConstraintRaw) -> proc_macro2:
 
 pub fn generate_constraint_owner(f: &Field, c: &ConstraintOwner) -> proc_macro2::TokenStream {
     let ident = &f.ident;
+    let maybe_deref = match &f.ty {
+        Ty::Account(AccountTy { boxed, .. })
+        | Ty::InterfaceAccount(InterfaceAccountTy { boxed, .. }) => *boxed,
+        _ => false,
+    }
+    .then(|| quote!(*))
+    .unwrap_or_default();
     let owner_address = &c.owner_address;
     let error = generate_custom_error(
         ident,
@@ -311,9 +319,10 @@ pub fn generate_constraint_owner(f: &Field, c: &ConstraintOwner) -> proc_macro2:
         quote! { ConstraintOwner },
         &Some(&(quote! { *my_owner }, quote! { owner_address })),
     );
+
     quote! {
         {
-            let my_owner = AsRef::::as_ref(&#ident).owner;
+            let my_owner = AsRef::::as_ref(& #maybe_deref #ident).owner;
             let owner_address = #owner_address;
             if my_owner != &owner_address {
                 return #error;
@@ -625,17 +634,19 @@ fn generate_constraint_init_group(
                     if !#if_needed || owner_program == &anchor_lang::solana_program::system_program::ID {
                         #payer_optional_check
 
-                        let cpi_program = associated_token_program.to_account_info();
-                        let cpi_accounts = ::anchor_spl::associated_token::Create {
-                            payer: #payer.to_account_info(),
-                            associated_token: #field.to_account_info(),
-                            authority: #owner.to_account_info(),
-                            mint: #mint.to_account_info(),
-                            system_program: system_program.to_account_info(),
-                            token_program: #token_program.to_account_info(),
-                        };
-                        let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, cpi_accounts);
-                        ::anchor_spl::associated_token::create(cpi_ctx)?;
+                        ::anchor_spl::associated_token::create(
+                            anchor_lang::context::CpiContext::new(
+                                associated_token_program.to_account_info(),
+                                ::anchor_spl::associated_token::Create {
+                                    payer: #payer.to_account_info(),
+                                    associated_token: #field.to_account_info(),
+                                    authority: #owner.to_account_info(),
+                                    mint: #mint.to_account_info(),
+                                    system_program: system_program.to_account_info(),
+                                    token_program: #token_program.to_account_info(),
+                                }
+                            )
+                        )?;
                     }
                     let pa: #ty_decl = #from_account_info_unchecked;
                     if #if_needed {
@@ -662,6 +673,16 @@ fn generate_constraint_init_group(
             decimals,
             freeze_authority,
             token_program,
+            group_pointer_authority,
+            group_pointer_group_address,
+            group_member_pointer_authority,
+            group_member_pointer_member_address,
+            metadata_pointer_authority,
+            metadata_pointer_metadata_address,
+            close_authority,
+            permanent_delegate,
+            transfer_hook_authority,
+            transfer_hook_program_id,
         } => {
             let token_program = match token_program {
                 Some(t) => t.to_token_stream(),
@@ -673,6 +694,59 @@ fn generate_constraint_init_group(
                 None => quote! {},
             };
 
+            // extension checks
+
+            let group_pointer_authority_check = match group_pointer_authority {
+                Some(gpa) => check_scope.generate_check(gpa),
+                None => quote! {},
+            };
+
+            let group_pointer_group_address_check = match group_pointer_group_address {
+                Some(gpga) => check_scope.generate_check(gpga),
+                None => quote! {},
+            };
+
+            let group_member_pointer_authority_check = match group_member_pointer_authority {
+                Some(gmpa) => check_scope.generate_check(gmpa),
+                None => quote! {},
+            };
+
+            let group_member_pointer_member_address_check =
+                match group_member_pointer_member_address {
+                    Some(gmpm) => check_scope.generate_check(gmpm),
+                    None => quote! {},
+                };
+
+            let metadata_pointer_authority_check = match metadata_pointer_authority {
+                Some(mpa) => check_scope.generate_check(mpa),
+                None => quote! {},
+            };
+
+            let metadata_pointer_metadata_address_check = match metadata_pointer_metadata_address {
+                Some(mpma) => check_scope.generate_check(mpma),
+                None => quote! {},
+            };
+
+            let close_authority_check = match close_authority {
+                Some(ca) => check_scope.generate_check(ca),
+                None => quote! {},
+            };
+
+            let transfer_hook_authority_check = match transfer_hook_authority {
+                Some(tha) => check_scope.generate_check(tha),
+                None => quote! {},
+            };
+
+            let transfer_hook_program_id_check = match transfer_hook_program_id {
+                Some(thpid) => check_scope.generate_check(thpid),
+                None => quote! {},
+            };
+
+            let permanent_delegate_check = match permanent_delegate {
+                Some(pd) => check_scope.generate_check(pd),
+                None => quote! {},
+            };
+
             let system_program_optional_check = check_scope.generate_check(system_program);
             let token_program_optional_check = check_scope.generate_check(&token_program);
             let rent_optional_check = check_scope.generate_check(rent);
@@ -683,23 +757,126 @@ fn generate_constraint_init_group(
                 #rent_optional_check
                 #owner_optional_check
                 #freeze_authority_optional_check
+                #group_pointer_authority_check
+                #group_pointer_group_address_check
+                #group_member_pointer_authority_check
+                #group_member_pointer_member_address_check
+                #metadata_pointer_authority_check
+                #metadata_pointer_metadata_address_check
+                #close_authority_check
+                #transfer_hook_authority_check
+                #transfer_hook_program_id_check
+                #permanent_delegate_check
             };
 
             let payer_optional_check = check_scope.generate_check(payer);
 
+            let mut extensions = vec![];
+            if group_pointer_authority.is_some() || group_pointer_group_address.is_some() {
+                extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupPointer});
+            }
+
+            if group_member_pointer_authority.is_some()
+                || group_member_pointer_member_address.is_some()
+            {
+                extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupMemberPointer});
+            }
+
+            if metadata_pointer_authority.is_some() || metadata_pointer_metadata_address.is_some() {
+                extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MetadataPointer});
+            }
+
+            if close_authority.is_some() {
+                extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MintCloseAuthority});
+            }
+
+            if transfer_hook_authority.is_some() || transfer_hook_program_id.is_some() {
+                extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::TransferHook});
+            }
+
+            if permanent_delegate.is_some() {
+                extensions.push(quote! {::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::PermanentDelegate});
+            }
+
+            let mint_space = if extensions.is_empty() {
+                quote! { ::anchor_spl::token::Mint::LEN }
+            } else {
+                quote! { ::anchor_spl::token_interface::find_mint_account_size(Some(&vec![#(#extensions),*]))? }
+            };
+
+            let extensions = if extensions.is_empty() {
+                quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::None}
+            } else {
+                quote! {Option::<&::anchor_spl::token_interface::ExtensionsVec>::Some(&vec![#(#extensions),*])}
+            };
+
+            let freeze_authority = match freeze_authority {
+                Some(fa) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#fa.key()) },
+                None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
+            };
+
+            let group_pointer_authority = match group_pointer_authority {
+                Some(gpa) => quote! { Option::::Some(#gpa.key()) },
+                None => quote! { Option::::None },
+            };
+
+            let group_pointer_group_address = match group_pointer_group_address {
+                Some(gpga) => quote! { Option::::Some(#gpga.key()) },
+                None => quote! { Option::::None },
+            };
+
+            let group_member_pointer_authority = match group_member_pointer_authority {
+                Some(gmpa) => quote! { Option::::Some(#gmpa.key()) },
+                None => quote! { Option::::None },
+            };
+
+            let group_member_pointer_member_address = match group_member_pointer_member_address {
+                Some(gmpma) => {
+                    quote! { Option::::Some(#gmpma.key()) }
+                }
+                None => quote! { Option::::None },
+            };
+
+            let metadata_pointer_authority = match metadata_pointer_authority {
+                Some(mpa) => quote! { Option::::Some(#mpa.key()) },
+                None => quote! { Option::::None },
+            };
+
+            let metadata_pointer_metadata_address = match metadata_pointer_metadata_address {
+                Some(mpma) => quote! { Option::::Some(#mpma.key()) },
+                None => quote! { Option::::None },
+            };
+
+            let close_authority = match close_authority {
+                Some(ca) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#ca.key()) },
+                None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
+            };
+
+            let permanent_delegate = match permanent_delegate {
+                Some(pd) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#pd.key()) },
+                None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
+            };
+
+            let transfer_hook_authority = match transfer_hook_authority {
+                Some(tha) => quote! { Option::::Some(#tha.key()) },
+                None => quote! { Option::::None },
+            };
+
+            let transfer_hook_program_id = match transfer_hook_program_id {
+                Some(thpid) => {
+                    quote! { Option::::Some(#thpid.key()) }
+                }
+                None => quote! { Option::::None },
+            };
+
             let create_account = generate_create_account(
                 field,
-                quote! {::anchor_spl::token::Mint::LEN},
+                mint_space,
                 quote! {&#token_program.key()},
                 quote! {#payer},
                 seeds_with_bump,
             );
 
-            let freeze_authority = match freeze_authority {
-                Some(fa) => quote! { Option::<&anchor_lang::prelude::Pubkey>::Some(&#fa.key()) },
-                None => quote! { Option::<&anchor_lang::prelude::Pubkey>::None },
-            };
-
             quote! {
                 // Define the bump and pda variable.
                 #find_pda
@@ -716,6 +893,59 @@ fn generate_constraint_init_group(
                         // Create the account with the system program.
                         #create_account
 
+                        // Initialize extensions.
+                        if let Some(extensions) = #extensions {
+                            for e in extensions {
+                                match e {
+                                    ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupPointer => {
+                                        ::anchor_spl::token_interface::group_pointer_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::GroupPointerInitialize {
+                                            token_program_id: #token_program.to_account_info(),
+                                            mint: #field.to_account_info(),
+                                        }), #group_pointer_authority, #group_pointer_group_address)?;
+                                    },
+                                    ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::GroupMemberPointer => {
+                                        ::anchor_spl::token_interface::group_member_pointer_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::GroupMemberPointerInitialize {
+                                            token_program_id: #token_program.to_account_info(),
+                                            mint: #field.to_account_info(),
+                                        }), #group_member_pointer_authority, #group_member_pointer_member_address)?;
+                                    },
+                                    ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MetadataPointer => {
+                                        ::anchor_spl::token_interface::metadata_pointer_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::MetadataPointerInitialize {
+                                            token_program_id: #token_program.to_account_info(),
+                                            mint: #field.to_account_info(),
+                                        }), #metadata_pointer_authority, #metadata_pointer_metadata_address)?;
+                                    },
+                                    ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::MintCloseAuthority => {
+                                        ::anchor_spl::token_interface::mint_close_authority_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::MintCloseAuthorityInitialize {
+                                            token_program_id: #token_program.to_account_info(),
+                                            mint: #field.to_account_info(),
+                                        }), #close_authority)?;
+                                    },
+                                    ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::TransferHook => {
+                                        ::anchor_spl::token_interface::transfer_hook_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::TransferHookInitialize {
+                                            token_program_id: #token_program.to_account_info(),
+                                            mint: #field.to_account_info(),
+                                        }), #transfer_hook_authority, #transfer_hook_program_id)?;
+                                    },
+                                    ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::NonTransferable => {
+                                        ::anchor_spl::token_interface::non_transferable_mint_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::NonTransferableMintInitialize {
+                                            token_program_id: #token_program.to_account_info(),
+                                            mint: #field.to_account_info(),
+                                        }))?;
+                                    },
+                                    ::anchor_spl::token_interface::spl_token_2022::extension::ExtensionType::PermanentDelegate => {
+                                        ::anchor_spl::token_interface::permanent_delegate_initialize(anchor_lang::context::CpiContext::new(#token_program.to_account_info(), ::anchor_spl::token_interface::PermanentDelegateInitialize {
+                                            token_program_id: #token_program.to_account_info(),
+                                            mint: #field.to_account_info(),
+                                        }), #permanent_delegate.unwrap())?;
+                                    },
+                                    // All extensions specified by the user should be implemented.
+                                    // If this line runs, it means there is a bug in the codegen.
+                                    _ => unimplemented!("{e:?}"),
+                                }
+                            };
+                        }
+
                         // Initialize the mint account.
                         let cpi_program = #token_program.to_account_info();
                         let accounts = ::anchor_spl::token_interface::InitializeMint2 {
@@ -724,6 +954,7 @@ fn generate_constraint_init_group(
                         let cpi_ctx = anchor_lang::context::CpiContext::new(cpi_program, accounts);
                         ::anchor_spl::token_interface::initialize_mint2(cpi_ctx, #decimals, &#owner.key(), #freeze_authority)?;
                     }
+
                     let pa: #ty_decl = #from_account_info_unchecked;
                     if #if_needed {
                         if pa.mint_authority != anchor_lang::solana_program::program_option::COption::Some(#owner.key()) {
@@ -1069,12 +1300,203 @@ fn generate_constraint_mint(
         }
         None => quote! {},
     };
+
+    let group_pointer_authority_check = match &c.group_pointer_authority {
+        Some(group_pointer_authority) => {
+            let group_pointer_authority_optional_check =
+                optional_check_scope.generate_check(group_pointer_authority);
+            quote! {
+                let group_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_pointer::GroupPointer>(#account_ref);
+                if group_pointer.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtension.into());
+                }
+                #group_pointer_authority_optional_check
+                if group_pointer.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_pointer_authority.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtensionAuthority.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let group_pointer_group_address_check = match &c.group_pointer_group_address {
+        Some(group_pointer_group_address) => {
+            let group_pointer_group_address_optional_check =
+                optional_check_scope.generate_check(group_pointer_group_address);
+            quote! {
+                let group_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_pointer::GroupPointer>(#account_ref);
+                if group_pointer.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtension.into());
+                }
+                #group_pointer_group_address_optional_check
+                if group_pointer.unwrap().group_address != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_pointer_group_address.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupPointerExtensionGroupAddress.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let group_member_pointer_authority_check = match &c.group_member_pointer_authority {
+        Some(group_member_pointer_authority) => {
+            let group_member_pointer_authority_optional_check =
+                optional_check_scope.generate_check(group_member_pointer_authority);
+            quote! {
+                let group_member_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_member_pointer::GroupMemberPointer>(#account_ref);
+                if group_member_pointer.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtension.into());
+                }
+                #group_member_pointer_authority_optional_check
+                if group_member_pointer.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_member_pointer_authority.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtensionAuthority.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let group_member_pointer_member_address_check = match &c.group_member_pointer_member_address {
+        Some(group_member_pointer_member_address) => {
+            let group_member_pointer_member_address_optional_check =
+                optional_check_scope.generate_check(group_member_pointer_member_address);
+            quote! {
+                let group_member_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::group_member_pointer::GroupMemberPointer>(#account_ref);
+                if group_member_pointer.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtension.into());
+                }
+                #group_member_pointer_member_address_optional_check
+                if group_member_pointer.unwrap().member_address != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#group_member_pointer_member_address.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintGroupMemberPointerExtensionMemberAddress.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let metadata_pointer_authority_check = match &c.metadata_pointer_authority {
+        Some(metadata_pointer_authority) => {
+            let metadata_pointer_authority_optional_check =
+                optional_check_scope.generate_check(metadata_pointer_authority);
+            quote! {
+                let metadata_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::metadata_pointer::MetadataPointer>(#account_ref);
+                if metadata_pointer.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtension.into());
+                }
+                #metadata_pointer_authority_optional_check
+                if metadata_pointer.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#metadata_pointer_authority.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtensionAuthority.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let metadata_pointer_metadata_address_check = match &c.metadata_pointer_metadata_address {
+        Some(metadata_pointer_metadata_address) => {
+            let metadata_pointer_metadata_address_optional_check =
+                optional_check_scope.generate_check(metadata_pointer_metadata_address);
+            quote! {
+                let metadata_pointer = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::metadata_pointer::MetadataPointer>(#account_ref);
+                if metadata_pointer.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtension.into());
+                }
+                #metadata_pointer_metadata_address_optional_check
+                if metadata_pointer.unwrap().metadata_address != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#metadata_pointer_metadata_address.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintMetadataPointerExtensionMetadataAddress.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let close_authority_check = match &c.close_authority {
+        Some(close_authority) => {
+            let close_authority_optional_check =
+                optional_check_scope.generate_check(close_authority);
+            quote! {
+                let close_authority = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::mint_close_authority::MintCloseAuthority>(#account_ref);
+                if close_authority.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintCloseAuthorityExtension.into());
+                }
+                #close_authority_optional_check
+                if close_authority.unwrap().close_authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#close_authority.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintCloseAuthorityExtensionAuthority.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let permanent_delegate_check = match &c.permanent_delegate {
+        Some(permanent_delegate) => {
+            let permanent_delegate_optional_check =
+                optional_check_scope.generate_check(permanent_delegate);
+            quote! {
+                let permanent_delegate = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::permanent_delegate::PermanentDelegate>(#account_ref);
+                if permanent_delegate.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintPermanentDelegateExtension.into());
+                }
+                #permanent_delegate_optional_check
+                if permanent_delegate.unwrap().delegate != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#permanent_delegate.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintPermanentDelegateExtensionDelegate.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let transfer_hook_authority_check = match &c.transfer_hook_authority {
+        Some(transfer_hook_authority) => {
+            let transfer_hook_authority_optional_check =
+                optional_check_scope.generate_check(transfer_hook_authority);
+            quote! {
+                let transfer_hook = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::transfer_hook::TransferHook>(#account_ref);
+                if transfer_hook.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtension.into());
+                }
+                #transfer_hook_authority_optional_check
+                if transfer_hook.unwrap().authority != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#transfer_hook_authority.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtensionAuthority.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
+    let transfer_hook_program_id_check = match &c.transfer_hook_program_id {
+        Some(transfer_hook_program_id) => {
+            let transfer_hook_program_id_optional_check =
+                optional_check_scope.generate_check(transfer_hook_program_id);
+            quote! {
+                let transfer_hook = ::anchor_spl::token_interface::get_mint_extension_data::<::anchor_spl::token_interface::spl_token_2022::extension::transfer_hook::TransferHook>(#account_ref);
+                if transfer_hook.is_err() {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtension.into());
+                }
+                #transfer_hook_program_id_optional_check
+                if transfer_hook.unwrap().program_id != ::anchor_spl::token_2022_extensions::spl_pod::optional_keys::OptionalNonZeroPubkey::try_from(Some(#transfer_hook_program_id.key()))? {
+                    return Err(anchor_lang::error::ErrorCode::ConstraintMintTransferHookExtensionProgramId.into());
+                }
+            }
+        }
+        None => quote! {},
+    };
+
     quote! {
         {
             #decimal_check
             #mint_authority_check
             #freeze_authority_check
             #token_program_check
+            #group_pointer_authority_check
+            #group_pointer_group_address_check
+            #group_member_pointer_authority_check
+            #group_member_pointer_member_address_check
+            #metadata_pointer_authority_check
+            #metadata_pointer_metadata_address_check
+            #close_authority_check
+            #permanent_delegate_check
+            #transfer_hook_authority_check
+            #transfer_hook_program_id_check
         }
     }
 }
@@ -1098,7 +1520,7 @@ impl<'a> OptionalCheckScope<'a> {
         check_scope
     }
     pub fn generate_check(&mut self, field: impl ToTokens) -> TokenStream {
-        let field_name = tts_to_string(&field);
+        let field_name = parser::tts_to_string(&field);
         if self.seen.contains(&field_name) {
             quote! {}
         } else {
diff --git a/lang/syn/src/codegen/accounts/mod.rs b/lang/syn/src/codegen/accounts/mod.rs
index 2e0c3d5b33..cbb53ca370 100644
--- a/lang/syn/src/codegen/accounts/mod.rs
+++ b/lang/syn/src/codegen/accounts/mod.rs
@@ -5,8 +5,8 @@ use syn::punctuated::Punctuated;
 use syn::{ConstParam, LifetimeDef, Token, TypeParam};
 use syn::{GenericParam, PredicateLifetime, WhereClause, WherePredicate};
 
-mod __client_accounts;
-mod __cpi_client_accounts;
+pub mod __client_accounts;
+pub mod __cpi_client_accounts;
 mod bumps;
 mod constraints;
 mod exit;
@@ -21,8 +21,8 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
     let impl_exit = exit::generate(accs);
     let bumps_struct = bumps::generate(accs);
 
-    let __client_accounts_mod = __client_accounts::generate(accs);
-    let __cpi_client_accounts_mod = __cpi_client_accounts::generate(accs);
+    let __client_accounts_mod = __client_accounts::generate(accs, quote!(crate::ID));
+    let __cpi_client_accounts_mod = __cpi_client_accounts::generate(accs, quote!(crate::ID));
 
     let ret = quote! {
         #impl_try_accounts
@@ -37,10 +37,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
 
     #[cfg(feature = "idl-build")]
     {
-        #![allow(warnings)]
-        let no_docs = crate::idl::build::get_no_docs();
-        let idl_build_impl =
-            crate::idl::build::gen_idl_build_impl_for_accounts_struct(&accs, no_docs);
+        let idl_build_impl = crate::idl::gen_idl_build_impl_accounts_struct(accs);
         return quote! {
             #ret
             #idl_build_impl
diff --git a/lang/syn/src/codegen/accounts/try_accounts.rs b/lang/syn/src/codegen/accounts/try_accounts.rs
index a817bcce8a..17a5b5870a 100644
--- a/lang/syn/src/codegen/accounts/try_accounts.rs
+++ b/lang/syn/src/codegen/accounts/try_accounts.rs
@@ -29,7 +29,7 @@ pub fn generate(accs: &AccountsStruct) -> proc_macro2::TokenStream {
                     }
                 }
                 AccountField::Field(f) => {
-                    // `init` and `zero` acccounts are special cased as they are
+                    // `init` and `zero` accounts are special cased as they are
                     // deserialized by constraints. Here, we just take out the
                     // AccountInfo for later use at constraint validation time.
                     if is_init(af) || f.constraints.zeroed.is_some()  {
@@ -143,7 +143,7 @@ pub fn generate_constraints(accs: &AccountsStruct) -> proc_macro2::TokenStream {
         accs.fields.iter().filter(|af| !is_init(af)).collect();
 
     // Deserialization for each pda init field. This must be after
-    // the inital extraction from the accounts slice and before access_checks.
+    // the initial extraction from the accounts slice and before access_checks.
     let init_fields: Vec = accs
         .fields
         .iter()
diff --git a/lang/syn/src/codegen/error.rs b/lang/syn/src/codegen/error.rs
index 2eedd7b489..aa30e57418 100644
--- a/lang/syn/src/codegen/error.rs
+++ b/lang/syn/src/codegen/error.rs
@@ -1,9 +1,6 @@
 use crate::Error;
 use quote::quote;
 
-#[cfg(feature = "idl-build")]
-use crate::idl::build::gen_idl_print_function_for_error;
-
 pub fn generate(error: Error) -> proc_macro2::TokenStream {
     let error_enum = &error.raw_enum;
     let enum_name = &error.ident;
@@ -103,10 +100,10 @@ pub fn generate(error: Error) -> proc_macro2::TokenStream {
 
     #[cfg(feature = "idl-build")]
     {
-        let idl_build = gen_idl_print_function_for_error(&error);
+        let idl_print = crate::idl::gen_idl_print_fn_error(&error);
         return quote! {
             #ret
-            #idl_build
+            #idl_print
         };
     };
 
diff --git a/lang/syn/src/codegen/program/dispatch.rs b/lang/syn/src/codegen/program/dispatch.rs
index ef99b7e56a..71f8559d1e 100644
--- a/lang/syn/src/codegen/program/dispatch.rs
+++ b/lang/syn/src/codegen/program/dispatch.rs
@@ -4,42 +4,66 @@ use quote::quote;
 
 pub fn generate(program: &Program) -> proc_macro2::TokenStream {
     // Dispatch all global instructions.
-    let global_dispatch_arms: Vec = program
-        .ixs
-        .iter()
-        .map(|ix| {
-            let ix_method_name = &ix.raw_method.sig.ident;
-            let ix_name_camel: proc_macro2::TokenStream = ix_method_name
-                .to_string()
-                .as_str()
-                .to_camel_case()
-                .parse()
-                .expect("Failed to parse ix method name in camel as `TokenStream`");
+    let global_ixs = program.ixs.iter().map(|ix| {
+        let ix_method_name = &ix.raw_method.sig.ident;
+        let ix_name_camel: proc_macro2::TokenStream = ix_method_name
+            .to_string()
+            .to_camel_case()
+            .parse()
+            .expect("Failed to parse ix method name in camel as `TokenStream`");
+        let discriminator = quote! { instruction::#ix_name_camel::DISCRIMINATOR };
 
-            quote! {
-                instruction::#ix_name_camel::DISCRIMINATOR => {
-                    __private::__global::#ix_method_name(
-                        program_id,
-                        accounts,
-                        ix_data,
-                    )
-                }
+        quote! {
+            if data.starts_with(#discriminator) {
+                return __private::__global::#ix_method_name(
+                    program_id,
+                    accounts,
+                    &data[#discriminator.len()..],
+                )
             }
-        })
-        .collect();
-
-    let fallback_fn = gen_fallback(program).unwrap_or(quote! {
-        Err(anchor_lang::error::ErrorCode::InstructionFallbackNotFound.into())
+        }
     });
 
-    let event_cpi_handler = generate_event_cpi_handler();
+    // Generate the event-cpi instruction handler based on whether the `event-cpi` feature is enabled.
+    let event_cpi_handler = {
+        #[cfg(feature = "event-cpi")]
+        quote! {
+            // `event-cpi` feature is enabled, dispatch self-cpi instruction
+            __private::__events::__event_dispatch(
+                program_id,
+                accounts,
+                &data[anchor_lang::event::EVENT_IX_TAG_LE.len()..]
+            )
+        }
+        #[cfg(not(feature = "event-cpi"))]
+        quote! {
+            // `event-cpi` feature is not enabled
+            Err(anchor_lang::error::ErrorCode::EventInstructionStub.into())
+        }
+    };
+
+    let fallback_fn = program
+        .fallback_fn
+        .as_ref()
+        .map(|fallback_fn| {
+            let program_name = &program.name;
+            let fn_name = &fallback_fn.raw_method.sig.ident;
+            quote! {
+                #program_name::#fn_name(program_id, accounts, data)
+            }
+        })
+        .unwrap_or_else(|| {
+            quote! {
+                Err(anchor_lang::error::ErrorCode::InstructionFallbackNotFound.into())
+            }
+        });
 
     quote! {
         /// Performs method dispatch.
         ///
         /// Each method in an anchor program is uniquely defined by a namespace
         /// and a rust identifier (i.e., the name given to the method). These
-        /// two pieces can be combined to creater a method identifier,
+        /// two pieces can be combined to create a method identifier,
         /// specifically, Anchor uses
         ///
         /// Sha256(":")[..8],
@@ -55,69 +79,29 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
             accounts: &'info [AccountInfo<'info>],
             data: &[u8],
         ) -> anchor_lang::Result<()> {
-            // Split the instruction data into the first 8 byte method
-            // identifier (sighash) and the serialized instruction data.
-            let mut ix_data: &[u8] = data;
-            let sighash: [u8; 8] = {
-                let mut sighash: [u8; 8] = [0; 8];
-                sighash.copy_from_slice(&ix_data[..8]);
-                ix_data = &ix_data[8..];
-                sighash
-            };
+            #(#global_ixs)*
 
+            // Dispatch IDL instructions
+            if data.starts_with(anchor_lang::idl::IDL_IX_TAG_LE) {
+                // If the method identifier is the IDL tag, then execute an IDL
+                // instruction, injected into all Anchor programs unless they have
+                // `no-idl` feature enabled
+                #[cfg(not(feature = "no-idl"))]
+                return __private::__idl::__idl_dispatch(
+                    program_id,
+                    accounts,
+                    &data[anchor_lang::idl::IDL_IX_TAG_LE.len()..],
+                );
+                #[cfg(feature = "no-idl")]
+                return Err(anchor_lang::error::ErrorCode::IdlInstructionStub.into());
+            }
 
-            use anchor_lang::Discriminator;
-            match sighash {
-                #(#global_dispatch_arms)*
-                anchor_lang::idl::IDL_IX_TAG_LE => {
-                    // If the method identifier is the IDL tag, then execute an IDL
-                    // instruction, injected into all Anchor programs unless they have
-                    // no-idl enabled
-                    #[cfg(not(feature = "no-idl"))]
-                    {
-                        __private::__idl::__idl_dispatch(
-                            program_id,
-                            accounts,
-                            &ix_data,
-                        )
-                    }
-                    #[cfg(feature = "no-idl")]
-                    {
-                        Err(anchor_lang::error::ErrorCode::IdlInstructionStub.into())
-                    }
-                }
-                anchor_lang::event::EVENT_IX_TAG_LE => {
-                    #event_cpi_handler
-                }
-                _ => {
-                    #fallback_fn
-                }
+            // Dispatch Event CPI instruction
+            if data.starts_with(anchor_lang::event::EVENT_IX_TAG_LE) {
+                return #event_cpi_handler;
             }
-        }
-    }
-}
 
-pub fn gen_fallback(program: &Program) -> Option {
-    program.fallback_fn.as_ref().map(|fallback_fn| {
-        let program_name = &program.name;
-        let method = &fallback_fn.raw_method;
-        let fn_name = &method.sig.ident;
-        quote! {
-            #program_name::#fn_name(program_id, accounts, data)
+            #fallback_fn
         }
-    })
-}
-
-/// Generate the event-cpi instruction handler based on whether the `event-cpi` feature is enabled.
-pub fn generate_event_cpi_handler() -> proc_macro2::TokenStream {
-    #[cfg(feature = "event-cpi")]
-    quote! {
-        // `event-cpi` feature is enabled, dispatch self-cpi instruction
-        __private::__events::__event_dispatch(program_id, accounts, &ix_data)
-    }
-    #[cfg(not(feature = "event-cpi"))]
-    quote! {
-        // `event-cpi` feature is not enabled
-        Err(anchor_lang::error::ErrorCode::EventInstructionStub.into())
     }
 }
diff --git a/lang/syn/src/codegen/program/entry.rs b/lang/syn/src/codegen/program/entry.rs
index 4b04da232a..3b83ee91ed 100644
--- a/lang/syn/src/codegen/program/entry.rs
+++ b/lang/syn/src/codegen/program/entry.rs
@@ -1,13 +1,9 @@
-use crate::program_codegen::dispatch;
 use crate::Program;
 use heck::CamelCase;
 use quote::quote;
 
 pub fn generate(program: &Program) -> proc_macro2::TokenStream {
     let name: proc_macro2::TokenStream = program.name.to_string().to_camel_case().parse().unwrap();
-    let fallback_maybe = dispatch::gen_fallback(program).unwrap_or(quote! {
-        Err(anchor_lang::error::ErrorCode::InstructionMissing.into())
-    });
     quote! {
         #[cfg(not(feature = "no-entrypoint"))]
         anchor_lang::solana_program::entrypoint!(entry);
@@ -62,9 +58,6 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
             if *program_id != ID {
                 return Err(anchor_lang::error::ErrorCode::DeclaredProgramIdMismatch.into());
             }
-            if data.len() < 8 {
-                return #fallback_maybe;
-            }
 
             dispatch(program_id, accounts, data)
         }
diff --git a/lang/syn/src/codegen/program/idl.rs b/lang/syn/src/codegen/program/idl.rs
index 757a2097e5..f45173c2f5 100644
--- a/lang/syn/src/codegen/program/idl.rs
+++ b/lang/syn/src/codegen/program/idl.rs
@@ -147,7 +147,10 @@ pub fn idl_accounts_and_functions() -> proc_macro2::TokenStream {
             let owner = accounts.program.key;
             let to = Pubkey::create_with_seed(&base, seed, owner).unwrap();
             // Space: account discriminator || authority pubkey || vec len || vec data
-            let space = std::cmp::min(8 + 32 + 4 + data_len as usize, 10_000);
+            let space = std::cmp::min(
+                IdlAccount::DISCRIMINATOR.len() + 32 + 4 + data_len as usize,
+                10_000
+            );
             let rent = Rent::get()?;
             let lamports = rent.minimum_balance(space);
             let seeds = &[&[nonce][..]];
diff --git a/lang/syn/src/codegen/program/instruction.rs b/lang/syn/src/codegen/program/instruction.rs
index 8e6ea4c487..1f4cd72674 100644
--- a/lang/syn/src/codegen/program/instruction.rs
+++ b/lang/syn/src/codegen/program/instruction.rs
@@ -21,15 +21,25 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
                         .unwrap()
                 })
                 .collect();
-            let ix_data_trait = {
-                let sighash_arr = ix
-                    .interface_discriminator
-                    .unwrap_or(sighash(SIGHASH_GLOBAL_NAMESPACE, name));
-                let sighash_tts: proc_macro2::TokenStream =
-                    format!("{sighash_arr:?}").parse().unwrap();
+            let impls = {
+                let discriminator = match ix.overrides.as_ref() {
+                    Some(overrides) if overrides.discriminator.is_some() => {
+                        overrides.discriminator.as_ref().unwrap().to_owned()
+                    }
+                    _ => {
+                        // TODO: Remove `interface_discriminator`
+                        let discriminator = ix
+                            .interface_discriminator
+                            .unwrap_or_else(|| sighash(SIGHASH_GLOBAL_NAMESPACE, name));
+                        let discriminator: proc_macro2::TokenStream =
+                            format!("{discriminator:?}").parse().unwrap();
+                        quote! { &#discriminator }
+                    }
+                };
+
                 quote! {
                     impl anchor_lang::Discriminator for #ix_name_camel {
-                        const DISCRIMINATOR: [u8; 8] = #sighash_tts;
+                        const DISCRIMINATOR: &'static [u8] = #discriminator;
                     }
                     impl anchor_lang::InstructionData for #ix_name_camel {}
                     impl anchor_lang::Owner for #ix_name_camel {
@@ -46,7 +56,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
                     #[derive(AnchorSerialize, AnchorDeserialize)]
                     pub struct #ix_name_camel;
 
-                    #ix_data_trait
+                    #impls
                 }
             } else {
                 quote! {
@@ -56,7 +66,7 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
                         #(#raw_args),*
                     }
 
-                    #ix_data_trait
+                    #impls
                 }
             }
         })
@@ -72,7 +82,6 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
         pub mod instruction {
             use super::*;
 
-
             #(#variants)*
         }
     }
diff --git a/lang/syn/src/codegen/program/mod.rs b/lang/syn/src/codegen/program/mod.rs
index c8f96ae104..ed2c9bbb46 100644
--- a/lang/syn/src/codegen/program/mod.rs
+++ b/lang/syn/src/codegen/program/mod.rs
@@ -39,12 +39,10 @@ pub fn generate(program: &Program) -> proc_macro2::TokenStream {
 
     #[cfg(feature = "idl-build")]
     {
-        let no_docs = crate::idl::build::get_no_docs();
-        let idl_build = crate::idl::build::gen_idl_print_function_for_program(program, no_docs);
-
+        let idl_build_impl = crate::idl::gen_idl_print_fn_program(program);
         return quote! {
             #ret
-            #idl_build
+            #idl_build_impl
         };
     };
 
diff --git a/lang/syn/src/hash.rs b/lang/syn/src/hash.rs
index ee4d06bd3f..60a5cfb473 100644
--- a/lang/syn/src/hash.rs
+++ b/lang/syn/src/hash.rs
@@ -3,7 +3,7 @@
 
 use serde::{Deserialize, Serialize};
 use sha2::{Digest, Sha256};
-use std::{convert::TryFrom, fmt, mem, str::FromStr};
+use std::{fmt, mem, str::FromStr};
 use thiserror::Error;
 
 pub const HASH_BYTES: usize = 32;
@@ -78,11 +78,6 @@ impl Hash {
         Hash(<[u8; HASH_BYTES]>::try_from(hash_slice).unwrap())
     }
 
-    #[cfg(target_arch = "bpf")]
-    pub const fn new_from_array(hash_array: [u8; HASH_BYTES]) -> Self {
-        Self(hash_array)
-    }
-
     pub fn to_bytes(self) -> [u8; HASH_BYTES] {
         self.0
     }
@@ -92,28 +87,9 @@ impl Hash {
 pub fn hashv(vals: &[&[u8]]) -> Hash {
     // Perform the calculation inline, calling this from within a program is
     // not supported
-    #[cfg(not(target_arch = "bpf"))]
-    {
-        let mut hasher = Hasher::default();
-        hasher.hashv(vals);
-        hasher.result()
-    }
-    // Call via a system call to perform the calculation
-    #[cfg(target_arch = "bpf")]
-    {
-        extern "C" {
-            fn sol_sha256(vals: *const u8, val_len: u64, hash_result: *mut u8) -> u64;
-        }
-        let mut hash_result = [0; HASH_BYTES];
-        unsafe {
-            sol_sha256(
-                vals as *const _ as *const u8,
-                vals.len() as u64,
-                &mut hash_result as *mut _ as *mut u8,
-            );
-        }
-        Hash::new_from_array(hash_result)
-    }
+    let mut hasher = Hasher::default();
+    hasher.hashv(vals);
+    hasher.result()
 }
 
 /// Return a Sha256 hash for the given data.
diff --git a/lang/syn/src/idl/accounts.rs b/lang/syn/src/idl/accounts.rs
new file mode 100644
index 0000000000..faa05a5bbb
--- /dev/null
+++ b/lang/syn/src/idl/accounts.rs
@@ -0,0 +1,461 @@
+use anyhow::{anyhow, Result};
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+
+use super::common::{get_idl_module_path, get_no_docs};
+use crate::{AccountField, AccountsStruct, Field, InitKind, Ty};
+
+/// Generate the IDL build impl for the Accounts struct.
+pub fn gen_idl_build_impl_accounts_struct(accounts: &AccountsStruct) -> TokenStream {
+    let resolution = option_env!("ANCHOR_IDL_BUILD_RESOLUTION")
+        .map(|val| val == "TRUE")
+        .unwrap_or_default();
+    let no_docs = get_no_docs();
+    let idl = get_idl_module_path();
+
+    let ident = &accounts.ident;
+    let (impl_generics, ty_generics, where_clause) = accounts.generics.split_for_impl();
+
+    let (accounts, defined) = accounts
+        .fields
+        .iter()
+        .map(|acc| match acc {
+            AccountField::Field(acc) => {
+                let name = acc.ident.to_string();
+                let writable = acc.constraints.is_mutable();
+                let signer = match acc.ty {
+                    Ty::Signer => true,
+                    _ => acc.constraints.is_signer(),
+                };
+                let optional = acc.is_optional;
+                let docs = match &acc.docs {
+                    Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
+                    _ => quote! { vec![] },
+                };
+
+                let (address, pda, relations) = if resolution {
+                    (
+                        get_address(acc),
+                        get_pda(acc, accounts),
+                        get_relations(acc, accounts),
+                    )
+                } else {
+                    (quote! { None }, quote! { None }, quote! { vec![] })
+                };
+
+                let acc_type_path = match &acc.ty {
+                    Ty::Account(ty)
+                    // Skip `UpgradeableLoaderState` type for now until `bincode` serialization
+                    // is supported.
+                    //
+                    // TODO: Remove this once either `bincode` serialization is supported or
+                    // we wrap the type in order to implement `IdlBuild` in `anchor-lang`.
+                        if !ty
+                            .account_type_path
+                            .path
+                            .to_token_stream()
+                            .to_string()
+                            .contains("UpgradeableLoaderState") =>
+                    {
+                        Some(&ty.account_type_path)
+                    }
+                    Ty::AccountLoader(ty) => Some(&ty.account_type_path),
+                    Ty::InterfaceAccount(ty) => Some(&ty.account_type_path),
+                    _ => None,
+                };
+
+                (
+                    quote! {
+                        #idl::IdlInstructionAccountItem::Single(#idl::IdlInstructionAccount {
+                            name: #name.into(),
+                            docs: #docs,
+                            writable: #writable,
+                            signer: #signer,
+                            optional: #optional,
+                            address: #address,
+                            pda: #pda,
+                            relations: #relations,
+                        })
+                    },
+                    acc_type_path,
+                )
+            }
+            AccountField::CompositeField(comp_f) => {
+                let ty = if let syn::Type::Path(path) = &comp_f.raw_field.ty {
+                    // some::path::Foo<'info> -> some::path::Foo
+                    let mut res = syn::Path {
+                        leading_colon: path.path.leading_colon,
+                        segments: syn::punctuated::Punctuated::new(),
+                    };
+                    for segment in &path.path.segments {
+                        let s = syn::PathSegment {
+                            ident: segment.ident.clone(),
+                            arguments: syn::PathArguments::None,
+                        };
+                        res.segments.push(s);
+                    }
+                    res
+                } else {
+                    panic!(
+                        "Compose field type must be a path but received: {:?}",
+                        comp_f.raw_field.ty
+                    )
+                };
+                let name = comp_f.ident.to_string();
+
+                (
+                    quote! {
+                        #idl::IdlInstructionAccountItem::Composite(#idl::IdlInstructionAccounts {
+                            name: #name.into(),
+                            accounts: <#ty>::__anchor_private_gen_idl_accounts(accounts, types),
+                        })
+                    },
+                    None,
+                )
+            }
+        })
+        .unzip::<_, _, Vec<_>, Vec<_>>();
+    let defined = defined.into_iter().flatten().collect::>();
+
+    quote! {
+        impl #impl_generics #ident #ty_generics #where_clause {
+            pub fn __anchor_private_gen_idl_accounts(
+                accounts: &mut std::collections::BTreeMap,
+                types: &mut std::collections::BTreeMap,
+            ) -> Vec<#idl::IdlInstructionAccountItem> {
+                #(
+                    if let Some(ty) = <#defined>::create_type() {
+                        let account = #idl::IdlAccount {
+                            name: ty.name.clone(),
+                            discriminator: #defined::DISCRIMINATOR.into(),
+                        };
+                        accounts.insert(account.name.clone(), account);
+                        types.insert(ty.name.clone(), ty);
+                        <#defined>::insert_types(types);
+                    }
+                );*
+
+                vec![#(#accounts),*]
+            }
+        }
+    }
+}
+
+fn get_address(acc: &Field) -> TokenStream {
+    match &acc.ty {
+        Ty::Program(ty) => ty
+            .account_type_path
+            .path
+            .segments
+            .last()
+            .map(|seg| &seg.ident)
+            .map(|ident| quote! { Some(#ident::id().to_string()) })
+            .unwrap_or_else(|| quote! { None }),
+        Ty::Sysvar(_) => {
+            let ty = acc.account_ty();
+            let sysvar_id_trait = quote!(anchor_lang::solana_program::sysvar::SysvarId);
+            quote! { Some(<#ty as #sysvar_id_trait>::id().to_string()) }
+        }
+        _ => acc
+            .constraints
+            .address
+            .as_ref()
+            .map(|constraint| &constraint.address)
+            .filter(|address| !matches!(address, syn::Expr::Field(_)))
+            .map(|address| quote! { Some(#address.to_string()) })
+            .unwrap_or_else(|| quote! { None }),
+    }
+}
+
+fn get_pda(acc: &Field, accounts: &AccountsStruct) -> TokenStream {
+    let idl = get_idl_module_path();
+    let parse_default = |expr: &syn::Expr| parse_seed(expr, accounts);
+
+    // Seeds
+    let seed_constraints = acc.constraints.seeds.as_ref();
+    let pda = seed_constraints
+        .map(|seed| seed.seeds.iter().map(parse_default))
+        .and_then(|seeds| seeds.collect::>>().ok())
+        .map(|seeds| {
+            let program = seed_constraints
+                .and_then(|seed| seed.program_seed.as_ref())
+                .and_then(|program| parse_default(program).ok())
+                .map(|program| quote! { Some(#program) })
+                .unwrap_or_else(|| quote! { None });
+
+            quote! {
+                Some(
+                    #idl::IdlPda {
+                        seeds: vec![#(#seeds),*],
+                        program: #program,
+                    }
+                )
+            }
+        });
+    if let Some(pda) = pda {
+        return pda;
+    }
+
+    // Associated token
+    let pda = acc
+        .constraints
+        .init
+        .as_ref()
+        .and_then(|init| match &init.kind {
+            InitKind::AssociatedToken {
+                owner,
+                mint,
+                token_program,
+            } => Some((owner, mint, token_program)),
+            _ => None,
+        })
+        .or_else(|| {
+            acc.constraints
+                .associated_token
+                .as_ref()
+                .map(|ata| (&ata.wallet, &ata.mint, &ata.token_program))
+        })
+        .and_then(|(wallet, mint, token_program)| {
+            // ATA constraints have implicit `.key()` call
+            let parse_expr = |ts| parse_default(&syn::parse2(ts).unwrap()).ok();
+            let parse_ata = |expr| parse_expr(quote! { #expr.key().as_ref() });
+
+            let wallet = parse_ata(wallet);
+            let mint = parse_ata(mint);
+            let token_program = token_program
+                .as_ref()
+                .and_then(parse_ata)
+                .or_else(|| parse_expr(quote!(anchor_spl::token::ID)));
+
+            let seeds = match (wallet, mint, token_program) {
+                (Some(w), Some(m), Some(tp)) => quote! { vec![#w, #tp, #m] },
+                _ => return None,
+            };
+
+            let program = parse_expr(quote!(anchor_spl::associated_token::ID))
+                .map(|program| quote! { Some(#program) })
+                .unwrap();
+
+            Some(quote! {
+                Some(
+                    #idl::IdlPda {
+                        seeds: #seeds,
+                        program: #program,
+                    }
+                )
+            })
+        });
+    if let Some(pda) = pda {
+        return pda;
+    }
+
+    quote! { None }
+}
+
+/// Parse a seeds constraint, extracting the `IdlSeed` types.
+///
+/// Note: This implementation makes assumptions about the types that can be used (e.g., no
+/// program-defined function calls in seeds).
+///
+/// This probably doesn't cover all cases. If you see a warning log, you can add a new case here.
+/// In the worst case, we miss a seed and the parser will treat the given seeds as empty and so
+/// clients will simply fail to automatically populate the PDA accounts.
+///
+/// # Seed assumptions
+///
+/// Seeds must be of one of the following forms:
+///
+/// - Constant
+/// - Instruction argument
+/// - Account key or field
+fn parse_seed(seed: &syn::Expr, accounts: &AccountsStruct) -> Result {
+    let idl = get_idl_module_path();
+    let args = accounts.instruction_args().unwrap_or_default();
+    match seed {
+        syn::Expr::MethodCall(_) => {
+            let seed_path = SeedPath::new(seed)?;
+
+            if args.contains_key(&seed_path.name) {
+                let path = seed_path.path();
+
+                Ok(quote! {
+                    #idl::IdlSeed::Arg(
+                        #idl::IdlSeedArg {
+                            path: #path.into(),
+                        }
+                    )
+                })
+            } else if let Some(account_field) = accounts
+                .fields
+                .iter()
+                .find(|field| *field.ident() == seed_path.name)
+            {
+                let path = seed_path.path();
+                let account = match account_field.ty_name() {
+                    Some(name) if !seed_path.subfields.is_empty() => {
+                        quote! { Some(#name.into()) }
+                    }
+                    _ => quote! { None },
+                };
+
+                Ok(quote! {
+                    #idl::IdlSeed::Account(
+                        #idl::IdlSeedAccount {
+                            path: #path.into(),
+                            account: #account,
+                        }
+                    )
+                })
+            } else if seed_path.name.contains('"') {
+                let seed = seed_path.name.trim_start_matches("b\"").trim_matches('"');
+                Ok(quote! {
+                    #idl::IdlSeed::Const(
+                        #idl::IdlSeedConst {
+                            value: #seed.into(),
+                        }
+                    )
+                })
+            } else {
+                Ok(quote! {
+                    #idl::IdlSeed::Const(
+                        #idl::IdlSeedConst {
+                            value: #seed.into(),
+                        }
+                    )
+                })
+            }
+        }
+        syn::Expr::Path(path) => {
+            let seed = path
+                .path
+                .get_ident()
+                .map(|ident| ident.to_string())
+                .filter(|ident| args.contains_key(ident))
+                .map(|path| {
+                    quote! {
+                        #idl::IdlSeed::Arg(
+                            #idl::IdlSeedArg {
+                                path: #path.into(),
+                            }
+                        )
+                    }
+                })
+                .unwrap_or_else(|| {
+                    // Not all types can be converted to `Vec` with `.into` call e.g. `Pubkey`.
+                    // This is problematic for `seeds::program` but a hacky way to handle this
+                    // scenerio is to check whether the last segment of the path ends with `ID`.
+                    let seed = path
+                        .path
+                        .segments
+                        .last()
+                        .filter(|seg| seg.ident.to_string().ends_with("ID"))
+                        .map(|_| quote! { #seed.as_ref() })
+                        .unwrap_or_else(|| quote! { #seed });
+                    quote! {
+                        #idl::IdlSeed::Const(
+                            #idl::IdlSeedConst {
+                                value: #seed.into(),
+                            }
+                        )
+                    }
+                });
+            Ok(seed)
+        }
+        syn::Expr::Lit(_) => Ok(quote! {
+            #idl::IdlSeed::Const(
+                #idl::IdlSeedConst {
+                    value: #seed.into(),
+                }
+            )
+        }),
+        syn::Expr::Reference(rf) => parse_seed(&rf.expr, accounts),
+        _ => Err(anyhow!("Unexpected seed: {seed:?}")),
+    }
+}
+
+/// SeedPath represents the deconstructed syntax of a single pda seed,
+/// consisting of a variable name and a vec of all the sub fields accessed
+/// on that variable name. For example, if a seed is `my_field.my_data.as_ref()`,
+/// then the field name is `my_field` and the vec of sub fields is `[my_data]`.
+struct SeedPath {
+    /// Seed name
+    name: String,
+    /// All path components for the subfields accessed on this seed
+    subfields: Vec,
+}
+
+impl SeedPath {
+    /// Extract the seed path from a single seed expression.
+    fn new(seed: &syn::Expr) -> Result {
+        // Convert the seed into the raw string representation.
+        let seed_str = seed.to_token_stream().to_string();
+
+        // Check unsupported cases e.g. `&(account.field + 1).to_le_bytes()`
+        if !seed_str.contains('"')
+            && seed_str.contains(|c: char| matches!(c, '+' | '-' | '*' | '/' | '%' | '^'))
+        {
+            return Err(anyhow!("Seed expression not supported: {seed:#?}"));
+        }
+
+        // Break up the seed into each subfield component.
+        let mut components = seed_str.split('.').collect::>();
+        if components.len() <= 1 {
+            return Err(anyhow!("Seed is in unexpected format: {seed:#?}"));
+        }
+
+        // The name of the variable (or field).
+        let name = components.remove(0).to_owned();
+
+        // The path to the seed (only if the `name` type is a struct).
+        let mut path = Vec::new();
+        while !components.is_empty() {
+            let subfield = components.remove(0);
+            if subfield.contains("()") {
+                break;
+            }
+            path.push(subfield.into());
+        }
+        if path.len() == 1 && (path[0] == "key" || path[0] == "key()") {
+            path = Vec::new();
+        }
+
+        Ok(SeedPath {
+            name,
+            subfields: path,
+        })
+    }
+
+    /// Get the full path to the data this seed represents.
+    fn path(&self) -> String {
+        match self.subfields.len() {
+            0 => self.name.to_owned(),
+            _ => format!("{}.{}", self.name, self.subfields.join(".")),
+        }
+    }
+}
+
+fn get_relations(acc: &Field, accounts: &AccountsStruct) -> TokenStream {
+    let relations = accounts
+        .fields
+        .iter()
+        .filter_map(|af| match af {
+            AccountField::Field(f) => f
+                .constraints
+                .has_one
+                .iter()
+                .filter_map(|c| match &c.join_target {
+                    syn::Expr::Path(path) => path
+                        .path
+                        .segments
+                        .first()
+                        .filter(|seg| seg.ident == acc.ident)
+                        .map(|_| Some(f.ident.to_string())),
+                    _ => None,
+                })
+                .collect::>>(),
+            _ => None,
+        })
+        .flatten()
+        .collect::>();
+    quote! { vec![#(#relations.into()),*] }
+}
diff --git a/lang/syn/src/idl/address.rs b/lang/syn/src/idl/address.rs
new file mode 100644
index 0000000000..092647a1fe
--- /dev/null
+++ b/lang/syn/src/idl/address.rs
@@ -0,0 +1,15 @@
+use proc_macro2::TokenStream;
+use quote::quote;
+
+use super::common::gen_print_section;
+
+pub fn gen_idl_print_fn_address(address: String) -> TokenStream {
+    let fn_body = gen_print_section("address", quote! { #address });
+
+    quote! {
+        #[test]
+        pub fn __anchor_private_print_idl_address() {
+            #fn_body
+        }
+    }
+}
diff --git a/lang/syn/src/idl/build.rs b/lang/syn/src/idl/build.rs
deleted file mode 100644
index 1aea742b85..0000000000
--- a/lang/syn/src/idl/build.rs
+++ /dev/null
@@ -1,948 +0,0 @@
-pub use serde_json;
-
-use crate::{parser::docs, AccountField, AccountsStruct, Error, Program};
-use heck::MixedCase;
-use proc_macro2::TokenStream;
-use quote::{format_ident, quote};
-use syn::{Ident, ItemEnum, ItemStruct};
-
-/// A trait that types must implement in order to generate the IDL via compilation.
-///
-/// This trait is automatically implemented for Anchor all types that use the `AnchorSerialize`
-/// proc macro. Note that manually implementing the `AnchorSerialize` trait will **NOT** have the
-/// same effect.
-///
-/// Types that don't implement this trait will cause a compile error during the IDL generation.
-///
-/// The methods have default implementation that allows the program to compile but the type will
-/// **NOT** be included in the IDL.
-pub trait IdlBuild {
-    /// Returns the full module path of the type.
-    fn __anchor_private_full_path() -> String {
-        String::default()
-    }
-
-    /// Returns the IDL type definition of the type or `None` if it doesn't exist.
-    fn __anchor_private_gen_idl_type() -> Option {
-        None
-    }
-
-    /// Insert the type definition to the defined types hashmap.
-    fn __anchor_private_insert_idl_defined(
-        _defined_types: &mut std::collections::HashMap,
-    ) {
-    }
-}
-
-#[inline(always)]
-fn get_module_paths() -> (TokenStream, TokenStream) {
-    (
-        quote!(anchor_lang::anchor_syn::idl::types),
-        quote!(anchor_lang::anchor_syn::idl::build::serde_json),
-    )
-}
-
-#[inline(always)]
-pub fn get_no_docs() -> bool {
-    std::option_env!("ANCHOR_IDL_BUILD_NO_DOCS")
-        .map(|val| val == "TRUE")
-        .unwrap_or(false)
-}
-
-#[inline(always)]
-pub fn get_seeds_feature() -> bool {
-    std::option_env!("ANCHOR_IDL_BUILD_SEEDS_FEATURE")
-        .map(|val| val == "TRUE")
-        .unwrap_or(false)
-}
-
-// Returns TokenStream for IdlType enum and the syn::TypePath for the defined
-// type if any.
-// Returns Err when the type wasn't parsed successfully.
-#[allow(clippy::result_unit_err)]
-pub fn idl_type_ts_from_syn_type(
-    ty: &syn::Type,
-    type_params: &Vec,
-) -> Result<(TokenStream, Vec), ()> {
-    let (idl, _) = get_module_paths();
-
-    fn the_only_segment_is(path: &syn::TypePath, cmp: &str) -> bool {
-        if path.path.segments.len() != 1 {
-            return false;
-        };
-        return path.path.segments.first().unwrap().ident == cmp;
-    }
-
-    // Foo -> first::path
-    fn get_first_angle_bracketed_path_arg(segment: &syn::PathSegment) -> Option<&syn::Type> {
-        match &segment.arguments {
-            syn::PathArguments::AngleBracketed(arguments) => match arguments.args.first() {
-                Some(syn::GenericArgument::Type(ty)) => Some(ty),
-                _ => None,
-            },
-            _ => None,
-        }
-    }
-
-    match ty {
-        syn::Type::Path(path) if the_only_segment_is(path, "bool") => {
-            Ok((quote! { #idl::IdlType::Bool }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "u8") => {
-            Ok((quote! { #idl::IdlType::U8 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "i8") => {
-            Ok((quote! { #idl::IdlType::I8 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "u16") => {
-            Ok((quote! { #idl::IdlType::U16 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "i16") => {
-            Ok((quote! { #idl::IdlType::I16 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "u32") => {
-            Ok((quote! { #idl::IdlType::U32 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "i32") => {
-            Ok((quote! { #idl::IdlType::I32 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "f32") => {
-            Ok((quote! { #idl::IdlType::F32 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "u64") => {
-            Ok((quote! { #idl::IdlType::U64 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "i64") => {
-            Ok((quote! { #idl::IdlType::I64 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "f64") => {
-            Ok((quote! { #idl::IdlType::F64 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "u128") => {
-            Ok((quote! { #idl::IdlType::U128 }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "i128") => {
-            Ok((quote! { #idl::IdlType::I128 }, vec![]))
-        }
-        syn::Type::Path(path)
-            if the_only_segment_is(path, "String") || the_only_segment_is(path, "&str") =>
-        {
-            Ok((quote! { #idl::IdlType::String }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "Pubkey") => {
-            Ok((quote! { #idl::IdlType::PublicKey }, vec![]))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "Vec") => {
-            let segment = path.path.segments.first().unwrap();
-            let arg = match get_first_angle_bracketed_path_arg(segment) {
-                Some(arg) => arg,
-                None => unreachable!("Vec arguments can only be of AngleBracketed variant"),
-            };
-            match arg {
-                syn::Type::Path(path) if the_only_segment_is(path, "u8") => {
-                    return Ok((quote! {#idl::IdlType::Bytes}, vec![]));
-                }
-                _ => (),
-            };
-            let (inner, defined) = idl_type_ts_from_syn_type(arg, type_params)?;
-            Ok((quote! { #idl::IdlType::Vec(Box::new(#inner)) }, defined))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "Option") => {
-            let segment = path.path.segments.first().unwrap();
-            let arg = match get_first_angle_bracketed_path_arg(segment) {
-                Some(arg) => arg,
-                None => unreachable!("Option arguments can only be of AngleBracketed variant"),
-            };
-            let (inner, defined) = idl_type_ts_from_syn_type(arg, type_params)?;
-            Ok((quote! { #idl::IdlType::Option(Box::new(#inner)) }, defined))
-        }
-        syn::Type::Path(path) if the_only_segment_is(path, "Box") => {
-            let segment = path.path.segments.first().unwrap();
-            let arg = match get_first_angle_bracketed_path_arg(segment) {
-                Some(arg) => arg,
-                None => unreachable!("Box arguments can only be of AngleBracketed variant"),
-            };
-            let (ts, defined) = idl_type_ts_from_syn_type(arg, type_params)?;
-            Ok((quote! { #ts }, defined))
-        }
-        syn::Type::Array(arr) => {
-            let len = arr.len.clone();
-            let len_is_generic = type_params.iter().any(|param| match len {
-                syn::Expr::Path(ref path) => path.path.is_ident(param),
-                _ => false,
-            });
-
-            let (inner, defined) = idl_type_ts_from_syn_type(&arr.elem, type_params)?;
-
-            if len_is_generic {
-                match len {
-                    syn::Expr::Path(ref len) => {
-                        let len = len.path.get_ident().unwrap().to_string();
-                        Ok((
-                            quote! { #idl::IdlType::GenericLenArray(Box::new(#inner), #len.into()) },
-                            defined,
-                        ))
-                    }
-                    _ => unreachable!("Array length can only be a generic parameter"),
-                }
-            } else {
-                Ok((
-                    quote! { #idl::IdlType::Array(Box::new(#inner), #len) },
-                    defined,
-                ))
-            }
-        }
-        syn::Type::Path(path) => {
-            let is_generic_param = type_params.iter().any(|param| path.path.is_ident(param));
-
-            if is_generic_param {
-                let generic = format!("{}", path.path.get_ident().unwrap());
-                Ok((quote! { #idl::IdlType::Generic(#generic.into()) }, vec![]))
-            } else {
-                let mut params = vec![];
-                let mut defined = vec![path.clone()];
-
-                if let Some(segment) = &path.path.segments.last() {
-                    if let syn::PathArguments::AngleBracketed(ref args) = segment.arguments {
-                        for arg in &args.args {
-                            match arg {
-                                syn::GenericArgument::Type(ty) => {
-                                    let (ts, def) = idl_type_ts_from_syn_type(ty, type_params)?;
-                                    params.push(quote! { #idl::IdlDefinedTypeArg::Type(#ts) });
-                                    defined.extend(def);
-                                }
-                                syn::GenericArgument::Const(c) => params.push(
-                                    quote! { #idl::IdlDefinedTypeArg::Value(format!("{}", #c))},
-                                ),
-                                _ => (),
-                            }
-                        }
-                    }
-                }
-
-                if !params.is_empty() {
-                    let params = quote! { vec![#(#params),*] };
-                    Ok((
-                        quote! { #idl::IdlType::DefinedWithTypeArgs {
-                            name: <#path>::__anchor_private_full_path(),
-                            args: #params
-                        } },
-                        defined,
-                    ))
-                } else {
-                    Ok((
-                        quote! { #idl::IdlType::Defined(<#path>::__anchor_private_full_path()) },
-                        vec![path.clone()],
-                    ))
-                }
-            }
-        }
-        syn::Type::Reference(reference) => match reference.elem.as_ref() {
-            syn::Type::Slice(slice) if matches!(&*slice.elem, syn::Type::Path(path) if the_only_segment_is(path, "u8")) =>
-            {
-                return Ok((quote! {#idl::IdlType::Bytes}, vec![]));
-            }
-            _ => panic!("Reference types other than byte slice(`&[u8]`) are not allowed"),
-        },
-        _ => Err(()),
-    }
-}
-
-// Returns TokenStream for IdlField struct and the syn::TypePath for the defined
-// type if any.
-// Returns Err when the type wasn't parsed successfully
-#[allow(clippy::result_unit_err)]
-pub fn idl_field_ts_from_syn_field(
-    field: &syn::Field,
-    no_docs: bool,
-    type_params: &Vec,
-) -> Result<(TokenStream, Vec), ()> {
-    let (idl, _) = get_module_paths();
-
-    let name = field.ident.as_ref().unwrap().to_string().to_mixed_case();
-    let docs = match docs::parse(&field.attrs) {
-        Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
-        _ => quote! {None},
-    };
-    let (ty, defined) = idl_type_ts_from_syn_type(&field.ty, type_params)?;
-
-    Ok((
-        quote! {
-            #idl::IdlField {
-                name: #name.into(),
-                docs: #docs,
-                ty: #ty,
-            }
-        },
-        defined,
-    ))
-}
-
-// Returns TokenStream for IdlEventField struct and the syn::TypePath for the defined
-// type if any.
-// Returns Err when the type wasn't parsed successfully
-#[allow(clippy::result_unit_err)]
-pub fn idl_event_field_ts_from_syn_field(
-    field: &syn::Field,
-) -> Result<(TokenStream, Vec), ()> {
-    let (idl, _) = get_module_paths();
-
-    let name = field.ident.as_ref().unwrap().to_string().to_mixed_case();
-    let (ty, defined) = idl_type_ts_from_syn_type(&field.ty, &vec![])?;
-
-    let index: bool = field
-        .attrs
-        .get(0)
-        .and_then(|attr| attr.path.segments.first())
-        .map(|segment| segment.ident == "index")
-        .unwrap_or(false);
-
-    Ok((
-        quote! {
-            #idl::IdlEventField {
-                name: #name.into(),
-                ty: #ty,
-                index: #index,
-            }
-        },
-        defined,
-    ))
-}
-
-// Returns TokenStream for IdlTypeDefinitionTy::Struct and Vec<&syn::TypePath>
-// for the defined types if any.
-// Returns Err if any of the fields weren't parsed successfully.
-#[allow(clippy::result_unit_err)]
-pub fn idl_type_definition_ts_from_syn_struct(
-    item_strct: &syn::ItemStruct,
-    no_docs: bool,
-) -> Result<(TokenStream, Vec), ()> {
-    let (idl, _) = get_module_paths();
-
-    let docs = match docs::parse(&item_strct.attrs) {
-        Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
-        _ => quote! {None},
-    };
-
-    let type_params = item_strct
-        .generics
-        .params
-        .iter()
-        .filter_map(|p| match p {
-            syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
-            syn::GenericParam::Const(c) => Some(c.ident.clone()),
-            _ => None,
-        })
-        .collect::>();
-    let (fields, defined): (Vec, Vec>) = match &item_strct.fields {
-        syn::Fields::Named(fields) => fields
-            .named
-            .iter()
-            .map(|f: &syn::Field| idl_field_ts_from_syn_field(f, no_docs, &type_params))
-            .collect::, _>>()?
-            .into_iter()
-            .unzip::<_, _, Vec<_>, Vec<_>>(),
-        _ => return Err(()),
-    };
-    let defined = defined
-        .into_iter()
-        .flatten()
-        .collect::>();
-
-    let generics = if !type_params.is_empty() {
-        let g: Vec = type_params.iter().map(|id| id.to_string()).collect();
-        quote! { Some(vec![#(#g.into()),*]) }
-    } else {
-        quote! { None }
-    };
-
-    Ok((
-        quote! {
-            #idl::IdlTypeDefinition {
-                name: Self::__anchor_private_full_path(),
-                generics: #generics,
-                docs: #docs,
-                ty: #idl::IdlTypeDefinitionTy::Struct{
-                    fields: vec![
-                        #(#fields),*
-                    ]
-                }
-            },
-        },
-        defined,
-    ))
-}
-
-// Returns TokenStream for IdlTypeDefinitionTy::Enum and the Vec<&syn::TypePath>
-// for the defined types if any.
-// Returns Err if any of the fields didn't parse successfully.
-#[allow(clippy::result_unit_err)]
-pub fn idl_type_definition_ts_from_syn_enum(
-    enum_item: &syn::ItemEnum,
-    no_docs: bool,
-) -> Result<(TokenStream, Vec), ()> {
-    let (idl, _) = get_module_paths();
-
-    let docs = match docs::parse(&enum_item.attrs) {
-        Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
-        _ => quote! {None},
-    };
-
-    let type_params = enum_item
-        .generics
-        .params
-        .iter()
-        .filter_map(|p| match p {
-            syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
-            syn::GenericParam::Const(c) => Some(c.ident.clone()),
-            _ => None,
-        })
-        .collect::>();
-
-    let (variants, defined): (Vec, Vec>) = enum_item.variants.iter().map(|variant: &syn::Variant| {
-        let name = variant.ident.to_string();
-        let (fields, defined): (TokenStream, Vec) = match &variant.fields {
-            syn::Fields::Unit => (quote!{None}, vec![]),
-            syn::Fields::Unnamed(fields) => {
-                let (types, defined) = fields.unnamed
-                    .iter()
-                    .map(|f| idl_type_ts_from_syn_type(&f.ty, &type_params))
-                    .collect::, _>>()?
-                    .into_iter()
-                    .unzip::, Vec, Vec>>();
-                let defined = defined
-                    .into_iter()
-                    .flatten()
-                    .collect::>();
-
-                (quote!{ Some(#idl::EnumFields::Tuple(vec![#(#types),*]))}, defined)
-            }
-            syn::Fields::Named(fields) => {
-                let (fields, defined) = fields.named
-                    .iter()
-                    .map(|f| idl_field_ts_from_syn_field(f, no_docs, &type_params))
-                    .collect::, _>>()?
-                    .into_iter()
-                    .unzip::, Vec, Vec>>();
-                let defined = defined
-                    .into_iter()
-                    .flatten()
-                    .collect::>();
-
-                (quote!{ Some(#idl::EnumFields::Named(vec![#(#fields),*]))}, defined)
-            }
-        };
-
-        Ok((quote!{ #idl::IdlEnumVariant{ name: #name.into(), fields: #fields }}, defined))
-    })
-    .collect::, _>>()?
-    .into_iter()
-    .unzip::, Vec, Vec>>();
-
-    let defined = defined
-        .into_iter()
-        .flatten()
-        .collect::>();
-
-    let generics = if !type_params.is_empty() {
-        let g: Vec = type_params.iter().map(|id| id.to_string()).collect();
-        quote! { Some(vec![#(#g.into()),*]) }
-    } else {
-        quote! { None }
-    };
-
-    Ok((
-        quote! {
-            #idl::IdlTypeDefinition {
-                name: Self::__anchor_private_full_path(),
-                generics: #generics,
-                docs: #docs,
-                ty: #idl::IdlTypeDefinitionTy::Enum{
-                    variants: vec![
-                        #(#variants),*
-                    ]
-                }
-            }
-        },
-        defined,
-    ))
-}
-
-pub fn idl_build_impl_skeleton(
-    idl_type_definition_ts: TokenStream,
-    insert_defined_ts: TokenStream,
-    ident: &Ident,
-    input_generics: &syn::Generics,
-) -> TokenStream {
-    let (idl, _) = get_module_paths();
-    let name = ident.to_string();
-    let (impl_generics, ty_generics, where_clause) = input_generics.split_for_impl();
-    let idl_build_trait = quote! {anchor_lang::anchor_syn::idl::build::IdlBuild};
-
-    quote! {
-        impl #impl_generics #idl_build_trait for #ident #ty_generics #where_clause {
-            fn __anchor_private_full_path() -> String {
-                format!("{}::{}", std::module_path!(), #name)
-            }
-
-            fn __anchor_private_gen_idl_type() -> Option<#idl::IdlTypeDefinition> {
-                #idl_type_definition_ts
-            }
-
-            fn __anchor_private_insert_idl_defined(
-                defined_types: &mut std::collections::HashMap
-            ) {
-                #insert_defined_ts
-            }
-        }
-    }
-}
-
-// generates the IDL generation impl for for a struct
-pub fn gen_idl_build_impl_for_struct(strct: &ItemStruct, no_docs: bool) -> TokenStream {
-    let idl_type_definition_ts: TokenStream;
-    let insert_defined_ts: TokenStream;
-
-    if let Ok((ts, defined)) = idl_type_definition_ts_from_syn_struct(strct, no_docs) {
-        idl_type_definition_ts = quote! {Some(#ts)};
-        insert_defined_ts = quote! {
-            #({
-                <#defined>::__anchor_private_insert_idl_defined(defined_types);
-
-                let path = <#defined>::__anchor_private_full_path();
-                <#defined>::__anchor_private_gen_idl_type()
-                    .and_then(|ty| defined_types.insert(path, ty));
-            });*
-        };
-    } else {
-        idl_type_definition_ts = quote! {None};
-        insert_defined_ts = quote! {};
-    }
-
-    let ident = &strct.ident;
-    let input_generics = &strct.generics;
-
-    idl_build_impl_skeleton(
-        idl_type_definition_ts,
-        insert_defined_ts,
-        ident,
-        input_generics,
-    )
-}
-
-// generates the IDL generation impl for for an enum
-pub fn gen_idl_build_impl_for_enum(enm: ItemEnum, no_docs: bool) -> TokenStream {
-    let idl_type_definition_ts: TokenStream;
-    let insert_defined_ts: TokenStream;
-
-    if let Ok((ts, defined)) = idl_type_definition_ts_from_syn_enum(&enm, no_docs) {
-        idl_type_definition_ts = quote! {Some(#ts)};
-        insert_defined_ts = quote! {
-            #({
-                <#defined>::__anchor_private_insert_idl_defined(defined_types);
-
-                let path = <#defined>::__anchor_private_full_path();
-                <#defined>::__anchor_private_gen_idl_type()
-                    .and_then(|ty| defined_types.insert(path, ty));
-            });*
-        };
-    } else {
-        idl_type_definition_ts = quote! {None};
-        insert_defined_ts = quote! {};
-    }
-
-    let ident = &enm.ident;
-    let input_generics = &enm.generics;
-
-    idl_build_impl_skeleton(
-        idl_type_definition_ts,
-        insert_defined_ts,
-        ident,
-        input_generics,
-    )
-}
-
-// generates the IDL generation impl for for an event
-pub fn gen_idl_build_impl_for_event(event_strct: &ItemStruct) -> TokenStream {
-    fn parse_fields(
-        fields: &syn::FieldsNamed,
-    ) -> Result<(Vec, Vec), ()> {
-        let (fields, defined) = fields
-            .named
-            .iter()
-            .map(idl_event_field_ts_from_syn_field)
-            .collect::, _>>()?
-            .into_iter()
-            .unzip::<_, _, Vec<_>, Vec<_>>();
-        let defined = defined
-            .into_iter()
-            .flatten()
-            .collect::>();
-
-        Ok((fields, defined))
-    }
-
-    let res = match &event_strct.fields {
-        syn::Fields::Named(fields) => parse_fields(fields),
-        _ => Err(()),
-    };
-
-    let (idl, _) = get_module_paths();
-    let name = event_strct.ident.to_string();
-
-    let (ret_ts, types_ts) = match res {
-        Ok((fields, defined)) => {
-            let ret_ts = quote! {
-                Some(
-                    #idl::IdlEvent {
-                        name: #name.into(),
-                        fields: vec![#(#fields),*],
-                    }
-                )
-            };
-            let types_ts = quote! {
-                #({
-                    <#defined>::__anchor_private_insert_idl_defined(defined_types);
-
-                    let path = <#defined>::__anchor_private_full_path();
-                    <#defined>::__anchor_private_gen_idl_type()
-                        .and_then(|ty| defined_types.insert(path, ty));
-                });*
-            };
-            (ret_ts, types_ts)
-        }
-        Err(()) => (quote! { None }, quote! {}),
-    };
-
-    let ident = &event_strct.ident;
-    let input_generics = &event_strct.generics;
-    let (impl_generics, ty_generics, where_clause) = input_generics.split_for_impl();
-
-    quote! {
-        impl #impl_generics #ident #ty_generics #where_clause {
-            pub fn __anchor_private_gen_idl_event(
-                defined_types: &mut std::collections::HashMap,
-            ) -> Option<#idl::IdlEvent> {
-                #types_ts
-                #ret_ts
-            }
-        }
-    }
-}
-
-// generates the IDL generation impl for the Accounts struct
-pub fn gen_idl_build_impl_for_accounts_struct(
-    accs_strct: &AccountsStruct,
-    no_docs: bool,
-) -> TokenStream {
-    let (idl, _) = get_module_paths();
-
-    let ident = &accs_strct.ident;
-    let (impl_generics, ty_generics, where_clause) = accs_strct.generics.split_for_impl();
-
-    let (accounts, acc_types): (Vec, Vec>) = accs_strct
-        .fields
-        .iter()
-        .map(|acc: &AccountField| match acc {
-            AccountField::CompositeField(comp_f) => {
-                let ty = if let syn::Type::Path(path) = &comp_f.raw_field.ty {
-                    // some::path::Foo<'info> -> some::path::Foo
-                    let mut res = syn::Path {
-                        leading_colon: path.path.leading_colon,
-                        segments: syn::punctuated::Punctuated::new(),
-                    };
-                    for segment in &path.path.segments {
-                        let s = syn::PathSegment {
-                            ident: segment.ident.clone(),
-                            arguments: syn::PathArguments::None,
-                        };
-                        res.segments.push(s);
-                    };
-                    res
-                } else {
-                    panic!("expecting path")
-                };
-                let name = comp_f.ident.to_string().to_mixed_case();
-                (quote!{
-                    #idl::IdlAccountItem::IdlAccounts(#idl::IdlAccounts {
-                        name: #name.into(),
-                        accounts: <#ty>::__anchor_private_gen_idl_accounts(accounts, defined_types),
-                    })
-                }, None)
-            }
-            AccountField::Field(acc) => {
-                let name = acc.ident.to_string().to_mixed_case();
-                let is_mut = acc.constraints.is_mutable();
-                let is_signer = match acc.ty {
-                    crate::Ty::Signer => true,
-                    _ => acc.constraints.is_signer()
-                };
-                let is_optional = if acc.is_optional { quote!{Some(true)} } else { quote!{None} };
-                let docs = match &acc.docs {
-                    Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
-                    _ => quote! {None},
-                };
-                let pda = quote!{None}; // TODO
-                let relations = super::parse::relations::parse(acc, get_seeds_feature());
-
-                let acc_type_path = match &acc.ty {
-                    crate::Ty::Account(ty) => Some(&ty.account_type_path),
-                    crate::Ty::AccountLoader(ty) => Some(&ty.account_type_path),
-                    crate::Ty::InterfaceAccount(ty) => Some(&ty.account_type_path),
-                    _ => None,
-                };
-
-                (quote!{
-                    #idl::IdlAccountItem::IdlAccount(#idl::IdlAccount{
-                        name: #name.into(),
-                        is_mut: #is_mut,
-                        is_signer: #is_signer,
-                        is_optional: #is_optional,
-                        docs: #docs,
-                        pda: #pda,
-                        relations: vec![#(#relations.into()),*],
-                    })
-                }, acc_type_path)
-            }
-        })
-        .unzip::, Vec, Vec>>();
-    let acc_types = acc_types
-        .into_iter()
-        .flatten()
-        .collect::>();
-
-    quote! {
-        impl #impl_generics #ident #ty_generics #where_clause {
-            pub fn __anchor_private_gen_idl_accounts(
-                accounts: &mut std::collections::HashMap,
-                defined_types: &mut std::collections::HashMap,
-            ) -> Vec<#idl::IdlAccountItem> {
-                #({
-                    <#acc_types>::__anchor_private_insert_idl_defined(defined_types);
-
-                    let path = <#acc_types>::__anchor_private_full_path();
-                    <#acc_types>::__anchor_private_gen_idl_type()
-                        .and_then(|ty| accounts.insert(path, ty));
-
-                });*
-
-                vec![#(#accounts),*]
-            }
-        }
-    }
-}
-
-// generates the IDL generation print function for the program module
-pub fn gen_idl_print_function_for_program(program: &Program, no_docs: bool) -> TokenStream {
-    let (idl, serde_json) = get_module_paths();
-
-    let (instructions, defined) = program
-        .ixs
-        .iter()
-        .flat_map(|ix| -> Result<_, ()> {
-            let name = ix.ident.to_string().to_mixed_case();
-            let docs = match &ix.docs {
-                Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
-                _ => quote! {None},
-            };
-            let ctx_ident = &ix.anchor_ident;
-
-            let (args, mut defined) = ix
-                .args
-                .iter()
-                .map(|arg| {
-                    let arg_name = arg.name.to_string().to_mixed_case();
-                    let docs = match docs::parse(&arg.raw_arg.attrs) {
-                        Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
-                        _ => quote! {None},
-                    };
-                    let (ty, defined) = idl_type_ts_from_syn_type(&arg.raw_arg.ty, &vec![])?;
-
-                    Ok((quote! {
-                        #idl::IdlField {
-                            name: #arg_name.into(),
-                            docs: #docs,
-                            ty: #ty,
-                        }
-                    }, defined))
-                })
-                .collect::, ()>>()?
-                .into_iter()
-                .unzip::, Vec, Vec>>();
-
-            let returns = match idl_type_ts_from_syn_type(&ix.returns.ty, &vec![]) {
-                Ok((ty, def)) => {
-                    defined.push(def);
-                    quote!{ Some(#ty) }
-                },
-                Err(()) => quote!{ None }
-            };
-
-            Ok((quote! {
-                #idl::IdlInstruction {
-                    name: #name.into(),
-                    docs: #docs,
-                    accounts: #ctx_ident::__anchor_private_gen_idl_accounts(
-                        &mut accounts,
-                        &mut defined_types,
-                    ),
-                    args: vec![#(#args),*],
-                    returns: #returns,
-                }
-            }, defined))
-        })
-        .unzip::>, Vec, Vec>>>();
-    let defined = defined
-        .into_iter()
-        .flatten()
-        .flatten()
-        .collect::>();
-
-    let name = program.name.to_string();
-    let docs = match &program.docs {
-        Some(docs) if !no_docs => quote! {Some(vec![#(#docs.into()),*])},
-        _ => quote! {None},
-    };
-
-    quote! {
-        #[test]
-        pub fn __anchor_private_print_idl_program() {
-            let mut accounts: std::collections::HashMap =
-                std::collections::HashMap::new();
-            let mut defined_types: std::collections::HashMap =
-                std::collections::HashMap::new();
-
-            #({
-                <#defined>::__anchor_private_insert_idl_defined(&mut defined_types);
-
-                let path = <#defined>::__anchor_private_full_path();
-                <#defined>::__anchor_private_gen_idl_type()
-                    .and_then(|ty| defined_types.insert(path, ty));
-            });*
-
-            let instructions = vec![#(#instructions),*];
-
-            let idl = #idl::Idl {
-                version: env!("CARGO_PKG_VERSION").into(),
-                name: #name.into(),
-                docs: #docs,
-                constants: vec![],
-                instructions,
-                accounts: accounts.into_values().collect(),
-                types: defined_types.into_values().collect(),
-                events: None,
-                errors: None,
-                metadata: None,
-            };
-
-            println!("---- IDL begin program ----");
-            println!("{}", #serde_json::to_string_pretty(&idl).unwrap());
-            println!("---- IDL end program ----");
-        }
-    }
-}
-
-pub fn gen_idl_print_function_for_event(event: &ItemStruct) -> TokenStream {
-    let (idl, serde_json) = get_module_paths();
-
-    let ident = &event.ident;
-    let fn_name = format_ident!("__anchor_private_print_idl_event_{}", ident.to_string());
-    let impl_gen = gen_idl_build_impl_for_event(event);
-
-    quote! {
-        #impl_gen
-
-        #[test]
-        pub fn #fn_name() {
-            let mut defined_types: std::collections::HashMap = std::collections::HashMap::new();
-            let event = #ident::__anchor_private_gen_idl_event(&mut defined_types);
-
-            if let Some(event) = event {
-                let json = #serde_json::json!({
-                    "event": event,
-                    "defined_types": defined_types.into_values().collect::>()
-                });
-
-                println!("---- IDL begin event ----");
-                println!("{}", #serde_json::to_string_pretty(&json).unwrap());
-                println!("---- IDL end event ----");
-            }
-        }
-    }
-}
-
-pub fn gen_idl_print_function_for_constant(item: &syn::ItemConst) -> TokenStream {
-    let fn_name = format_ident!(
-        "__anchor_private_print_idl_const_{}",
-        item.ident.to_string()
-    );
-    let (idl, serde_json) = get_module_paths();
-
-    let name = item.ident.to_string();
-    let expr = &item.expr;
-
-    let impl_ts = match idl_type_ts_from_syn_type(&item.ty, &vec![]) {
-        Ok((ty, _)) => quote! {
-            let value = format!("{:?}", #expr);
-
-            let idl = #idl::IdlConst {
-                name: #name.into(),
-                ty: #ty,
-                value,
-            };
-
-            println!("---- IDL begin const ----");
-            println!("{}", #serde_json::to_string_pretty(&idl).unwrap());
-            println!("---- IDL end const ----");
-        },
-        Err(()) => quote! {},
-    };
-
-    quote! {
-        #[test]
-        pub fn #fn_name() {
-            #impl_ts
-        }
-    }
-}
-
-pub fn gen_idl_print_function_for_error(error: &Error) -> TokenStream {
-    let fn_name = format_ident!(
-        "__anchor_private_print_idl_error_{}",
-        error.ident.to_string()
-    );
-    let (idl, serde_json) = get_module_paths();
-
-    let error_codes = error
-        .codes
-        .iter()
-        .map(|code| {
-            let id = code.id;
-            let name = code.ident.to_string();
-
-            let msg = match code.msg.clone() {
-                Some(msg) => quote! { Some(#msg.to_string()) },
-                None => quote! { None },
-            };
-
-            quote! {
-                #idl::IdlErrorCode {
-                    code: anchor_lang::error::ERROR_CODE_OFFSET + #id,
-                    name: #name.into(),
-                    msg: #msg,
-                }
-            }
-        })
-        .collect::>();
-
-    quote! {
-        #[test]
-        pub fn #fn_name() {
-            let errors = vec![#(#error_codes),*];
-
-            println!("---- IDL begin errors ----");
-            println!("{}", #serde_json::to_string_pretty(&errors).unwrap());
-            println!("---- IDL end errors ----");
-        }
-    }
-}
diff --git a/lang/syn/src/idl/common.rs b/lang/syn/src/idl/common.rs
new file mode 100644
index 0000000000..c8e95059a0
--- /dev/null
+++ b/lang/syn/src/idl/common.rs
@@ -0,0 +1,46 @@
+use std::path::{Path, PathBuf};
+
+use anyhow::{anyhow, Result};
+use proc_macro2::TokenStream;
+use quote::{quote, ToTokens};
+
+pub fn find_path(name: &str, path: impl AsRef) -> Result {
+    let path = path.as_ref();
+    for ancestor in path.ancestors() {
+        let file_path = ancestor.join(name);
+        if file_path.exists() {
+            return file_path.canonicalize().map_err(Into::into);
+        }
+    }
+
+    Err(anyhow!("Path ({path:?}) not found"))
+}
+
+pub fn get_no_docs() -> bool {
+    option_env!("ANCHOR_IDL_BUILD_NO_DOCS")
+        .map(|val| val == "TRUE")
+        .unwrap_or_default()
+}
+
+pub fn get_program_path() -> Result {
+    std::env::var("ANCHOR_IDL_BUILD_PROGRAM_PATH")
+        .map(PathBuf::from)
+        .map_err(|_| anyhow!("Failed to get program path"))
+}
+
+pub fn get_idl_module_path() -> TokenStream {
+    quote!(anchor_lang::idl::types)
+}
+
+pub fn get_serde_json_module_path() -> TokenStream {
+    quote!(anchor_lang::idl::serde_json)
+}
+
+pub fn gen_print_section(name: &str, value: impl ToTokens) -> TokenStream {
+    let serde_json = get_serde_json_module_path();
+    quote! {
+        println!("--- IDL begin {} ---", #name);
+        println!("{}", #serde_json::to_string_pretty(&{ #value }).unwrap());
+        println!("--- IDL end {} ---", #name);
+    }
+}
diff --git a/lang/syn/src/idl/constant.rs b/lang/syn/src/idl/constant.rs
new file mode 100644
index 0000000000..34fcfc7e58
--- /dev/null
+++ b/lang/syn/src/idl/constant.rs
@@ -0,0 +1,45 @@
+use heck::SnakeCase;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+use super::{
+    common::{gen_print_section, get_idl_module_path, get_no_docs},
+    defined::gen_idl_type,
+};
+use crate::parser::docs;
+
+pub fn gen_idl_print_fn_constant(item: &syn::ItemConst) -> TokenStream {
+    let idl = get_idl_module_path();
+    let no_docs = get_no_docs();
+
+    let name = item.ident.to_string();
+    let expr = &item.expr;
+    let fn_name = format_ident!("__anchor_private_print_idl_const_{}", name.to_snake_case());
+
+    let docs = match docs::parse(&item.attrs) {
+        Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
+        _ => quote! { vec![] },
+    };
+
+    let fn_body = match gen_idl_type(&item.ty, &[]) {
+        Ok((ty, _)) => gen_print_section(
+            "const",
+            quote! {
+                #idl::IdlConst {
+                    name: #name.into(),
+                    docs: #docs,
+                    ty: #ty,
+                    value: format!("{:?}", #expr),
+                }
+            },
+        ),
+        _ => quote! {},
+    };
+
+    quote! {
+        #[test]
+        pub fn #fn_name() {
+            #fn_body
+        }
+    }
+}
diff --git a/lang/syn/src/idl/defined.rs b/lang/syn/src/idl/defined.rs
new file mode 100644
index 0000000000..3820d18b21
--- /dev/null
+++ b/lang/syn/src/idl/defined.rs
@@ -0,0 +1,623 @@
+use anyhow::{anyhow, Result};
+use proc_macro2::TokenStream;
+use quote::quote;
+
+use super::common::{get_idl_module_path, get_no_docs};
+use crate::parser::docs;
+
+/// Generate `IdlBuild` impl for a struct.
+pub fn impl_idl_build_struct(item: &syn::ItemStruct) -> TokenStream {
+    impl_idl_build(&item.ident, &item.generics, gen_idl_type_def_struct(item))
+}
+
+/// Generate `IdlBuild` impl for an enum.
+pub fn impl_idl_build_enum(item: &syn::ItemEnum) -> TokenStream {
+    impl_idl_build(&item.ident, &item.generics, gen_idl_type_def_enum(item))
+}
+
+/// Generate `IdlBuild` impl for a union.
+///
+/// Unions are not currently supported in the IDL.
+pub fn impl_idl_build_union(item: &syn::ItemUnion) -> TokenStream {
+    impl_idl_build(
+        &item.ident,
+        &item.generics,
+        Err(anyhow!("Unions are not supported")),
+    )
+}
+
+/// Generate `IdlBuild` implementation.
+fn impl_idl_build(
+    ident: &syn::Ident,
+    generics: &syn::Generics,
+    type_def: Result<(TokenStream, Vec)>,
+) -> TokenStream {
+    let idl = get_idl_module_path();
+    let (impl_generics, ty_generics, where_clause) = generics.split_for_impl();
+    let idl_build_trait = quote!(anchor_lang::idl::build::IdlBuild);
+
+    let (idl_type_def, insert_defined) = match type_def {
+        Ok((ts, defined)) => (
+            quote! { Some(#ts) },
+            quote! {
+                #(
+                    if let Some(ty) = <#defined>::create_type() {
+                        types.insert(<#defined>::get_full_path(), ty);
+                        <#defined>::insert_types(types);
+                    }
+                );*
+            },
+        ),
+        _ => (quote! { None }, quote! {}),
+    };
+
+    quote! {
+        impl #impl_generics #idl_build_trait for #ident #ty_generics #where_clause {
+            fn create_type() -> Option<#idl::IdlTypeDef> {
+                #idl_type_def
+            }
+
+            fn insert_types(
+                types: &mut std::collections::BTreeMap
+            ) {
+                #insert_defined
+            }
+
+            fn get_full_path() -> String {
+                format!("{}::{}", module_path!(), stringify!(#ident))
+            }
+        }
+    }
+}
+
+pub fn gen_idl_type_def_struct(
+    strct: &syn::ItemStruct,
+) -> Result<(TokenStream, Vec)> {
+    gen_idl_type_def(&strct.attrs, &strct.generics, |generic_params| {
+        let no_docs = get_no_docs();
+        let idl = get_idl_module_path();
+
+        let (fields, defined) = match &strct.fields {
+            syn::Fields::Unit => (quote! { None }, vec![]),
+            syn::Fields::Named(fields) => {
+                let (fields, defined) = fields
+                    .named
+                    .iter()
+                    .map(|f| gen_idl_field(f, generic_params, no_docs))
+                    .collect::>>()?
+                    .into_iter()
+                    .unzip::<_, _, Vec<_>, Vec<_>>();
+
+                (
+                    quote! { Some(#idl::IdlDefinedFields::Named(vec![#(#fields),*])) },
+                    defined,
+                )
+            }
+            syn::Fields::Unnamed(fields) => {
+                let (types, defined) = fields
+                    .unnamed
+                    .iter()
+                    .map(|f| gen_idl_type(&f.ty, generic_params))
+                    .collect::>>()?
+                    .into_iter()
+                    .unzip::<_, Vec<_>, Vec<_>, Vec<_>>();
+
+                (
+                    quote! { Some(#idl::IdlDefinedFields::Tuple(vec![#(#types),*])) },
+                    defined,
+                )
+            }
+        };
+        let defined = defined.into_iter().flatten().collect::>();
+
+        Ok((
+            quote! {
+                #idl::IdlTypeDefTy::Struct {
+                    fields: #fields,
+                }
+            },
+            defined,
+        ))
+    })
+}
+
+fn gen_idl_type_def_enum(enm: &syn::ItemEnum) -> Result<(TokenStream, Vec)> {
+    gen_idl_type_def(&enm.attrs, &enm.generics, |generic_params| {
+        let no_docs = get_no_docs();
+        let idl = get_idl_module_path();
+
+        let (variants, defined) = enm
+            .variants
+            .iter()
+            .map(|variant| {
+                let name = variant.ident.to_string();
+                let (fields, defined) = match &variant.fields {
+                    syn::Fields::Unit => (quote! { None }, vec![]),
+                    syn::Fields::Named(fields) => {
+                        let (fields, defined) = fields
+                            .named
+                            .iter()
+                            .map(|f| gen_idl_field(f, generic_params, no_docs))
+                            .collect::>>()?
+                            .into_iter()
+                            .unzip::<_, Vec<_>, Vec<_>, Vec<_>>();
+                        let defined = defined.into_iter().flatten().collect::>();
+
+                        (
+                            quote! { Some(#idl::IdlDefinedFields::Named(vec![#(#fields),*])) },
+                            defined,
+                        )
+                    }
+                    syn::Fields::Unnamed(fields) => {
+                        let (types, defined) = fields
+                            .unnamed
+                            .iter()
+                            .map(|f| gen_idl_type(&f.ty, generic_params))
+                            .collect::>>()?
+                            .into_iter()
+                            .unzip::<_, Vec<_>, Vec<_>, Vec<_>>();
+                        let defined = defined.into_iter().flatten().collect::>();
+
+                        (
+                            quote! { Some(#idl::IdlDefinedFields::Tuple(vec![#(#types),*])) },
+                            defined,
+                        )
+                    }
+                };
+
+                Ok((
+                    quote! { #idl::IdlEnumVariant { name: #name.into(), fields: #fields } },
+                    defined,
+                ))
+            })
+            .collect::>>()?
+            .into_iter()
+            .unzip::<_, _, Vec<_>, Vec<_>>();
+        let defined = defined.into_iter().flatten().collect::>();
+
+        Ok((
+            quote! {
+                #idl::IdlTypeDefTy::Enum {
+                    variants: vec![#(#variants),*],
+                }
+            },
+            defined,
+        ))
+    })
+}
+
+fn gen_idl_type_def(
+    attrs: &[syn::Attribute],
+    generics: &syn::Generics,
+    create_fields: F,
+) -> Result<(TokenStream, Vec)>
+where
+    F: Fn(&[syn::Ident]) -> Result<(TokenStream, Vec)>,
+{
+    let no_docs = get_no_docs();
+    let idl = get_idl_module_path();
+
+    let docs = match docs::parse(attrs) {
+        Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
+        _ => quote! { vec![] },
+    };
+
+    let serialization = get_attr_str("derive", attrs)
+        .and_then(|derive| {
+            if derive.contains("bytemuck") {
+                if derive.to_lowercase().contains("unsafe") {
+                    Some(quote! { #idl::IdlSerialization::BytemuckUnsafe })
+                } else {
+                    Some(quote! { #idl::IdlSerialization::Bytemuck })
+                }
+            } else {
+                None
+            }
+        })
+        .unwrap_or_else(|| quote! { #idl::IdlSerialization::default() });
+
+    let repr = get_attr_str("repr", attrs)
+        .map(|repr| {
+            let packed = repr.contains("packed");
+            let align = repr
+                .find("align")
+                .and_then(|i| repr.get(i..))
+                .and_then(|align| {
+                    align
+                        .find('(')
+                        .and_then(|start| align.find(')').and_then(|end| align.get(start + 1..end)))
+                })
+                .and_then(|size| size.parse::().ok())
+                .map(|size| quote! { Some(#size) })
+                .unwrap_or_else(|| quote! { None });
+            let modifier = quote! {
+                #idl::IdlReprModifier {
+                    packed: #packed,
+                    align: #align,
+                }
+            };
+
+            if repr.contains("transparent") {
+                quote! { #idl::IdlRepr::Transparent }
+            } else if repr.contains('C') {
+                quote! { #idl::IdlRepr::C(#modifier) }
+            } else {
+                quote! { #idl::IdlRepr::Rust(#modifier) }
+            }
+        })
+        .map(|repr| quote! { Some(#repr) })
+        .unwrap_or_else(|| quote! { None });
+
+    let generic_params = generics
+        .params
+        .iter()
+        .filter_map(|p| match p {
+            syn::GenericParam::Type(ty) => Some(ty.ident.clone()),
+            syn::GenericParam::Const(c) => Some(c.ident.clone()),
+            _ => None,
+        })
+        .collect::>();
+    let (ty, defined) = create_fields(&generic_params)?;
+
+    let generics = generics
+        .params
+        .iter()
+        .filter_map(|p| match p {
+            syn::GenericParam::Type(ty) => {
+                let name = ty.ident.to_string();
+                Some(quote! {
+                    #idl::IdlTypeDefGeneric::Type {
+                        name: #name.into(),
+                    }
+                })
+            }
+            syn::GenericParam::Const(c) => {
+                let name = c.ident.to_string();
+                let ty = match &c.ty {
+                    syn::Type::Path(path) => get_first_segment(path).ident.to_string(),
+                    _ => unreachable!("Const generic type can only be path"),
+                };
+                Some(quote! {
+                    #idl::IdlTypeDefGeneric::Const {
+                        name: #name.into(),
+                        ty: #ty.into(),
+                    }
+                })
+            }
+            _ => None,
+        })
+        .collect::>();
+
+    Ok((
+        quote! {
+            #idl::IdlTypeDef {
+                name: Self::get_full_path(),
+                docs: #docs,
+                serialization: #serialization,
+                repr: #repr,
+                generics: vec![#(#generics.into()),*],
+                ty: #ty,
+            }
+        },
+        defined,
+    ))
+}
+
+fn get_attr_str(name: impl AsRef, attrs: &[syn::Attribute]) -> Option {
+    attrs
+        .iter()
+        .filter(|attr| {
+            attr.path
+                .segments
+                .first()
+                .filter(|seg| seg.ident == name)
+                .is_some()
+        })
+        .map(|attr| attr.tokens.to_string())
+        .reduce(|acc, cur| {
+            format!(
+                "{} , {}",
+                acc.get(..acc.len() - 1).unwrap(),
+                cur.get(1..).unwrap()
+            )
+        })
+}
+
+fn gen_idl_field(
+    field: &syn::Field,
+    generic_params: &[syn::Ident],
+    no_docs: bool,
+) -> Result<(TokenStream, Vec)> {
+    let idl = get_idl_module_path();
+
+    let name = field.ident.as_ref().unwrap().to_string();
+    let docs = match docs::parse(&field.attrs) {
+        Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
+        _ => quote! { vec![] },
+    };
+    let (ty, defined) = gen_idl_type(&field.ty, generic_params)?;
+
+    Ok((
+        quote! {
+            #idl::IdlField {
+                name: #name.into(),
+                docs: #docs,
+                ty: #ty,
+            }
+        },
+        defined,
+    ))
+}
+
+pub fn gen_idl_type(
+    ty: &syn::Type,
+    generic_params: &[syn::Ident],
+) -> Result<(TokenStream, Vec)> {
+    let idl = get_idl_module_path();
+
+    fn the_only_segment_is(path: &syn::TypePath, cmp: &str) -> bool {
+        if path.path.segments.len() != 1 {
+            return false;
+        };
+        return get_first_segment(path).ident == cmp;
+    }
+
+    fn get_angle_bracketed_type_args(seg: &syn::PathSegment) -> Vec<&syn::Type> {
+        match &seg.arguments {
+            syn::PathArguments::AngleBracketed(ab) => ab
+                .args
+                .iter()
+                .filter_map(|arg| match arg {
+                    syn::GenericArgument::Type(ty) => Some(ty),
+                    _ => None,
+                })
+                .collect(),
+            _ => panic!("No angle bracket for {seg:#?}"),
+        }
+    }
+
+    match ty {
+        syn::Type::Path(path) if the_only_segment_is(path, "bool") => {
+            Ok((quote! { #idl::IdlType::Bool }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "u8") => {
+            Ok((quote! { #idl::IdlType::U8 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "i8") => {
+            Ok((quote! { #idl::IdlType::I8 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "u16") => {
+            Ok((quote! { #idl::IdlType::U16 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "i16") => {
+            Ok((quote! { #idl::IdlType::I16 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "u32") => {
+            Ok((quote! { #idl::IdlType::U32 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "i32") => {
+            Ok((quote! { #idl::IdlType::I32 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "f32") => {
+            Ok((quote! { #idl::IdlType::F32 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "u64") => {
+            Ok((quote! { #idl::IdlType::U64 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "i64") => {
+            Ok((quote! { #idl::IdlType::I64 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "f64") => {
+            Ok((quote! { #idl::IdlType::F64 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "u128") => {
+            Ok((quote! { #idl::IdlType::U128 }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "i128") => {
+            Ok((quote! { #idl::IdlType::I128 }, vec![]))
+        }
+        syn::Type::Path(path)
+            if the_only_segment_is(path, "String") || the_only_segment_is(path, "str") =>
+        {
+            Ok((quote! { #idl::IdlType::String }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "Pubkey") => {
+            Ok((quote! { #idl::IdlType::Pubkey }, vec![]))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "Option") => {
+            let segment = get_first_segment(path);
+            let arg = get_angle_bracketed_type_args(segment)
+                .into_iter()
+                .next()
+                .unwrap();
+            let (inner, defined) = gen_idl_type(arg, generic_params)?;
+            Ok((quote! { #idl::IdlType::Option(Box::new(#inner)) }, defined))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "Vec") => {
+            let segment = get_first_segment(path);
+            let arg = get_angle_bracketed_type_args(segment)
+                .into_iter()
+                .next()
+                .unwrap();
+            match arg {
+                syn::Type::Path(path) if the_only_segment_is(path, "u8") => {
+                    return Ok((quote! {#idl::IdlType::Bytes}, vec![]));
+                }
+                _ => (),
+            };
+            let (inner, defined) = gen_idl_type(arg, generic_params)?;
+            Ok((quote! { #idl::IdlType::Vec(Box::new(#inner)) }, defined))
+        }
+        syn::Type::Path(path) if the_only_segment_is(path, "Box") => {
+            let segment = get_first_segment(path);
+            let arg = get_angle_bracketed_type_args(segment)
+                .into_iter()
+                .next()
+                .unwrap();
+            gen_idl_type(arg, generic_params)
+        }
+        syn::Type::Array(arr) => {
+            let len = &arr.len;
+            let is_generic = generic_params.iter().any(|param| match len {
+                syn::Expr::Path(path) => path.path.is_ident(param),
+                _ => false,
+            });
+
+            let len = if is_generic {
+                match len {
+                    syn::Expr::Path(len) => {
+                        let len = len.path.get_ident().unwrap().to_string();
+                        quote! { #idl::IdlArrayLen::Generic(#len.into()) }
+                    }
+                    _ => unreachable!("Array length can only be a generic parameter"),
+                }
+            } else {
+                quote! { #idl::IdlArrayLen::Value(#len) }
+            };
+
+            let (inner, defined) = gen_idl_type(&arr.elem, generic_params)?;
+            Ok((
+                quote! { #idl::IdlType::Array(Box::new(#inner), #len) },
+                defined,
+            ))
+        }
+        // Defined
+        syn::Type::Path(path) => {
+            let is_generic_param = generic_params.iter().any(|param| path.path.is_ident(param));
+            if is_generic_param {
+                let generic = get_first_segment(path).ident.to_string();
+                return Ok((quote! { #idl::IdlType::Generic(#generic.into()) }, vec![]));
+            }
+
+            // Handle type aliases and external types
+            #[cfg(procmacro2_semver_exempt)]
+            {
+                use super::{common::find_path, external::get_external_type};
+                use crate::parser::context::CrateContext;
+                use quote::ToTokens;
+
+                let source_path = proc_macro2::Span::call_site().source_file().path();
+                let lib_path = find_path("lib.rs", &source_path).expect("lib.rs should exist");
+
+                if let Ok(ctx) = CrateContext::parse(lib_path) {
+                    let name = path.path.segments.last().unwrap().ident.to_string();
+                    let alias = ctx.type_aliases().find(|ty| ty.ident == name);
+                    if let Some(alias) = alias {
+                        if let Some(segment) = path.path.segments.last() {
+                            if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
+                                let inners = args
+                                    .args
+                                    .iter()
+                                    .map(|arg| match arg {
+                                        syn::GenericArgument::Type(ty) => match ty {
+                                            syn::Type::Path(inner_ty) => {
+                                                inner_ty.path.to_token_stream().to_string()
+                                            }
+                                            _ => {
+                                                unimplemented!("Inner type not implemented: {ty:?}")
+                                            }
+                                        },
+                                        syn::GenericArgument::Const(c) => {
+                                            c.to_token_stream().to_string()
+                                        }
+                                        _ => unimplemented!("Arg not implemented: {arg:?}"),
+                                    })
+                                    .collect::>();
+
+                                let outer = match &*alias.ty {
+                                    syn::Type::Path(outer_ty) => outer_ty.path.to_token_stream(),
+                                    syn::Type::Array(outer_ty) => outer_ty.to_token_stream(),
+                                    _ => unimplemented!("Type not implemented: {:?}", alias.ty),
+                                }
+                                .to_string();
+
+                                let resolved_alias = alias
+                                    .generics
+                                    .params
+                                    .iter()
+                                    .map(|param| match param {
+                                        syn::GenericParam::Const(param) => param.ident.to_string(),
+                                        syn::GenericParam::Type(param) => param.ident.to_string(),
+                                        _ => panic!("Lifetime parameters are not allowed"),
+                                    })
+                                    .enumerate()
+                                    .fold(outer, |acc, (i, cur)| {
+                                        let inner = &inners[i];
+                                        // The spacing of the `outer` variable can differ between
+                                        // versions, e.g. `[T; N]` and `[T ; N]`
+                                        acc.replace(&format!(" {cur} "), &format!(" {inner} "))
+                                            .replace(&format!(" {cur},"), &format!(" {inner},"))
+                                            .replace(&format!("[{cur} "), &format!("[{inner} "))
+                                            .replace(&format!("[{cur};"), &format!("[{inner};"))
+                                            .replace(&format!(" {cur}]"), &format!(" {inner}]"))
+                                    });
+                                if let Ok(ty) = syn::parse_str(&resolved_alias) {
+                                    return gen_idl_type(&ty, generic_params);
+                                }
+                            }
+                        };
+
+                        // Non-generic type alias e.g. `type UnixTimestamp = i64`
+                        return gen_idl_type(&*alias.ty, generic_params);
+                    }
+
+                    // Handle external types
+                    let is_external = ctx
+                        .structs()
+                        .map(|s| s.ident.to_string())
+                        .chain(ctx.enums().map(|e| e.ident.to_string()))
+                        .find(|defined| defined == &name)
+                        .is_none();
+                    if is_external {
+                        if let Ok(Some(ty)) = get_external_type(&name, source_path) {
+                            return gen_idl_type(&ty, generic_params);
+                        }
+                    }
+                }
+            }
+
+            // Defined in crate
+            let mut generics = vec![];
+            let mut defined = vec![path.clone()];
+
+            if let Some(segment) = path.path.segments.last() {
+                if let syn::PathArguments::AngleBracketed(args) = &segment.arguments {
+                    for arg in &args.args {
+                        match arg {
+                            syn::GenericArgument::Type(ty) => {
+                                let (ty, def) = gen_idl_type(ty, generic_params)?;
+                                generics.push(quote! { #idl::IdlGenericArg::Type { ty: #ty } });
+                                defined.extend(def);
+                            }
+                            syn::GenericArgument::Const(c) => generics.push(
+                                quote! { #idl::IdlGenericArg::Const { value: #c.to_string() } },
+                            ),
+                            _ => (),
+                        }
+                    }
+                }
+            }
+
+            Ok((
+                quote! {
+                    #idl::IdlType::Defined {
+                        name: <#path>::get_full_path(),
+                        generics: vec![#(#generics),*],
+                    }
+                },
+                defined,
+            ))
+        }
+        syn::Type::Reference(reference) => match reference.elem.as_ref() {
+            syn::Type::Slice(slice) if matches!(&*slice.elem, syn::Type::Path(path) if the_only_segment_is(path, "u8")) => {
+                Ok((quote! {#idl::IdlType::Bytes}, vec![]))
+            }
+            _ => gen_idl_type(&reference.elem, generic_params),
+        },
+        _ => Err(anyhow!("Unknown type: {ty:#?}")),
+    }
+}
+
+fn get_first_segment(type_path: &syn::TypePath) -> &syn::PathSegment {
+    type_path.path.segments.first().unwrap()
+}
diff --git a/lang/syn/src/idl/error.rs b/lang/syn/src/idl/error.rs
new file mode 100644
index 0000000000..dcff0f5e27
--- /dev/null
+++ b/lang/syn/src/idl/error.rs
@@ -0,0 +1,44 @@
+use heck::SnakeCase;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+use super::common::{gen_print_section, get_idl_module_path};
+use crate::Error;
+
+pub fn gen_idl_print_fn_error(error: &Error) -> TokenStream {
+    let idl = get_idl_module_path();
+
+    let fn_name = format_ident!(
+        "__anchor_private_print_idl_error_{}",
+        error.ident.to_string().to_snake_case()
+    );
+
+    let error_codes = error
+        .codes
+        .iter()
+        .map(|code| {
+            let id = code.id;
+            let name = code.ident.to_string();
+            let msg = match &code.msg {
+                Some(msg) => quote! { Some(#msg.into()) },
+                None => quote! { None },
+            };
+
+            quote! {
+                #idl::IdlErrorCode {
+                    code: anchor_lang::error::ERROR_CODE_OFFSET + #id,
+                    name: #name.into(),
+                    msg: #msg,
+                }
+            }
+        })
+        .collect::>();
+    let fn_body = gen_print_section("errors", quote! { vec![#(#error_codes),*] });
+
+    quote! {
+        #[test]
+        pub fn #fn_name() {
+            #fn_body
+        }
+    }
+}
diff --git a/lang/syn/src/idl/event.rs b/lang/syn/src/idl/event.rs
new file mode 100644
index 0000000000..0838bb381c
--- /dev/null
+++ b/lang/syn/src/idl/event.rs
@@ -0,0 +1,81 @@
+use heck::SnakeCase;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+use super::{
+    common::{gen_print_section, get_idl_module_path, get_serde_json_module_path},
+    defined::gen_idl_type_def_struct,
+};
+
+pub fn gen_idl_print_fn_event(event_struct: &syn::ItemStruct) -> TokenStream {
+    let idl = get_idl_module_path();
+    let serde_json = get_serde_json_module_path();
+
+    let ident = &event_struct.ident;
+    let fn_name = format_ident!(
+        "__anchor_private_print_idl_event_{}",
+        ident.to_string().to_snake_case()
+    );
+    let idl_build_impl = impl_idl_build_event(event_struct);
+
+    let print_ts = gen_print_section(
+        "event",
+        quote! {
+            #serde_json::json!({
+                "event": event,
+                "types": types.into_values().collect::>()
+            })
+        },
+    );
+
+    quote! {
+        #idl_build_impl
+
+        #[test]
+        pub fn #fn_name() {
+            let mut types: std::collections::BTreeMap =
+                std::collections::BTreeMap::new();
+            if let Some(event) = #ident::__anchor_private_gen_idl_event(&mut types) {
+                #print_ts
+            }
+        }
+    }
+}
+
+/// Generate IDL build impl for an event.
+fn impl_idl_build_event(event_struct: &syn::ItemStruct) -> TokenStream {
+    let idl = get_idl_module_path();
+
+    let ident = &event_struct.ident;
+    let (impl_generics, ty_generics, where_clause) = event_struct.generics.split_for_impl();
+
+    let fn_body = match gen_idl_type_def_struct(event_struct) {
+        Ok((ts, defined)) => quote! {
+            #(
+                if let Some(ty) = <#defined>::create_type() {
+                    types.insert(<#defined>::get_full_path(), ty);
+                    <#defined>::insert_types(types);
+                }
+            );*
+
+            let ty = #ts;
+            let event = #idl::IdlEvent {
+                name: ty.name.clone(),
+                discriminator: Self::DISCRIMINATOR.into(),
+            };
+            types.insert(ty.name.clone(), ty);
+            Some(event)
+        },
+        _ => quote! { None },
+    };
+
+    quote! {
+        impl #impl_generics #ident #ty_generics #where_clause {
+            pub fn __anchor_private_gen_idl_event(
+                types: &mut std::collections::BTreeMap,
+            ) -> Option<#idl::IdlEvent> {
+                #fn_body
+            }
+        }
+    }
+}
diff --git a/lang/syn/src/idl/external.rs b/lang/syn/src/idl/external.rs
new file mode 100644
index 0000000000..e6e5f58093
--- /dev/null
+++ b/lang/syn/src/idl/external.rs
@@ -0,0 +1,143 @@
+use std::{
+    env, fs,
+    path::{Path, PathBuf},
+};
+
+use anyhow::{anyhow, Result};
+use cargo_toml::Manifest;
+use quote::ToTokens;
+
+use super::common::{find_path, get_program_path};
+use crate::parser::context::CrateContext;
+
+pub fn get_external_type(name: &str, path: impl AsRef) -> Result> {
+    let use_path = get_uses(path.as_ref())?
+        .into_iter()
+        .find(|u| u.split("::").last().unwrap() == name)
+        .ok_or_else(|| anyhow!("`{name}` not found in use statements"))?;
+
+    // Get crate name and version from lock file
+    let program_path = get_program_path()?;
+    let lock_path = find_path("Cargo.lock", program_path)?;
+    let lock_file = parse_lock_file(lock_path)?;
+    let registry_path = get_registry_path()?;
+
+    recursively_find_type(name, &use_path, ®istry_path, &lock_file)
+}
+
+fn recursively_find_type(
+    defined_name: &str,
+    use_path: &str,
+    registry_path: &Path,
+    lock_file: &[(String, String)],
+) -> Result> {
+    let crate_name = use_path.split("::").next().unwrap();
+    let (crate_name, version) = lock_file
+        .iter()
+        .find(|(name, _)| name == crate_name || name == &crate_name.replace('_', "-"))
+        .ok_or_else(|| anyhow!("Crate should exist in the lock file"))?;
+
+    let crate_path = registry_path.join(format!("{crate_name}-{version}"));
+    let lib_path = crate_path.join("src").join("lib.rs");
+    let ctx = CrateContext::parse(&lib_path)?;
+
+    // TODO: Struct and enum
+
+    let alias = ctx.type_aliases().find(|item| item.ident == defined_name);
+    match alias {
+        Some(alias) => Ok(Some(*alias.ty.to_owned())),
+        None => {
+            // Check re-exported deps e.g. `anchor_lang::solana_program::...`
+            let cargo_toml_path = find_path("Cargo.toml", &lib_path)?;
+            let deps = Manifest::from_path(cargo_toml_path)?.dependencies;
+            let paths = use_path.split("::").skip(1).collect::>();
+            let paths = paths.iter().enumerate().filter_map(|(i, path)| {
+                if deps.contains_key(*path) || deps.contains_key(&path.replace('_', "-")) {
+                    Some(paths.iter().skip(i).copied().collect::>().join("::"))
+                } else {
+                    None
+                }
+            });
+            for path in paths {
+                let result = recursively_find_type(defined_name, &path, registry_path, lock_file);
+                if result.is_ok() {
+                    return result;
+                }
+            }
+
+            Ok(None)
+        }
+    }
+}
+
+fn get_registry_path() -> Result {
+    #[allow(deprecated)]
+    let path = env::home_dir()
+        .unwrap()
+        .join(".cargo")
+        .join("registry")
+        .join("src");
+    fs::read_dir(&path)?
+        .filter_map(|entry| entry.ok())
+        .find_map(|entry| {
+            let file_name = entry.file_name();
+            if file_name.to_string_lossy().starts_with("index.crates.io") {
+                Some(file_name)
+            } else {
+                None
+            }
+        })
+        .map(|name| path.join(name))
+        .ok_or_else(|| anyhow!("crates.io registry not found"))
+}
+
+fn parse_lock_file(path: impl AsRef) -> Result> {
+    let parsed = fs::read_to_string(path.as_ref())?
+        .split("[[package]]")
+        .skip(1)
+        .map(|pkg| {
+            let get_value = |key: &str| -> String {
+                pkg.lines()
+                    .find(|line| line.starts_with(key))
+                    .expect(&format!("`{key}` line not found"))
+                    .split('"')
+                    .nth(1)
+                    .unwrap()
+                    .to_owned()
+            };
+            let name = get_value("name");
+            let version = get_value("version");
+            (name, version)
+        })
+        .collect::>();
+    Ok(parsed)
+}
+
+fn get_uses(path: impl AsRef) -> Result> {
+    let content = fs::read_to_string(path.as_ref())?;
+    let uses = syn::parse_file(&content)?
+        .items
+        .into_iter()
+        .filter_map(|item| match item {
+            syn::Item::Use(u) => Some(flatten_uses(&u.tree)),
+            _ => None,
+        })
+        .flatten()
+        .collect::>();
+    Ok(uses)
+}
+
+fn flatten_uses(tree: &syn::UseTree) -> Vec {
+    match tree {
+        syn::UseTree::Group(group) => group.items.iter().flat_map(flatten_uses).collect(),
+        syn::UseTree::Path(path) => flatten_uses(&path.tree)
+            .into_iter()
+            .map(|item| format!("{}::{}", path.ident, item))
+            .collect(),
+        syn::UseTree::Glob(glob) => {
+            vec![format!("{}", glob.star_token.to_token_stream().to_string())]
+        }
+        syn::UseTree::Name(name) => vec![name.ident.to_string()],
+        syn::UseTree::Rename(rename) => vec![rename.ident.to_string()],
+    }
+}
diff --git a/lang/syn/src/idl/mod.rs b/lang/syn/src/idl/mod.rs
index e2979e8b15..42c7dbe77e 100644
--- a/lang/syn/src/idl/mod.rs
+++ b/lang/syn/src/idl/mod.rs
@@ -1,7 +1,19 @@
-pub mod types;
+#![allow(dead_code)]
 
-#[cfg(feature = "idl-build")]
-pub mod build;
+mod accounts;
+mod address;
+mod common;
+mod constant;
+mod defined;
+mod error;
+mod event;
+mod external;
+mod program;
 
-#[cfg(feature = "idl-parse")]
-pub mod parse;
+pub use accounts::gen_idl_build_impl_accounts_struct;
+pub use address::gen_idl_print_fn_address;
+pub use constant::gen_idl_print_fn_constant;
+pub use defined::{impl_idl_build_enum, impl_idl_build_struct, impl_idl_build_union};
+pub use error::gen_idl_print_fn_error;
+pub use event::gen_idl_print_fn_event;
+pub use program::gen_idl_print_fn_program;
diff --git a/lang/syn/src/idl/parse/file.rs b/lang/syn/src/idl/parse/file.rs
deleted file mode 100644
index 14ebdf2018..0000000000
--- a/lang/syn/src/idl/parse/file.rs
+++ /dev/null
@@ -1,590 +0,0 @@
-use crate::idl::types::*;
-use crate::parser::context::CrateContext;
-use crate::parser::{self, accounts, docs, error, program};
-use crate::Ty;
-use crate::{AccountField, AccountsStruct};
-use anyhow::anyhow;
-use anyhow::Result;
-use heck::MixedCase;
-use quote::ToTokens;
-use std::collections::{HashMap, HashSet};
-use std::path::Path;
-use std::str::FromStr;
-use syn::{
-    Expr, ExprLit, ItemConst,
-    Lit::{Byte, ByteStr},
-};
-
-use super::relations;
-
-const DERIVE_NAME: &str = "Accounts";
-// TODO: share this with `anchor_lang` crate.
-const ERROR_CODE_OFFSET: u32 = 6000;
-
-/// Parse an entire interface file.
-pub fn parse(
-    path: impl AsRef,
-    version: String,
-    seeds_feature: bool,
-    no_docs: bool,
-    safety_checks: bool,
-) -> Result {
-    let ctx = CrateContext::parse(path)?;
-    if safety_checks {
-        ctx.safety_checks()?;
-    }
-
-    let program_mod = parse_program_mod(&ctx)?;
-    let mut program = program::parse(program_mod)?;
-
-    if no_docs {
-        program.docs = None;
-        for ix in &mut program.ixs {
-            ix.docs = None;
-        }
-    }
-
-    let accs = parse_account_derives(&ctx);
-
-    let error = parse_error_enum(&ctx).map(|mut e| error::parse(&mut e, None));
-    let error_codes = error.as_ref().map(|e| {
-        e.codes
-            .iter()
-            .map(|code| IdlErrorCode {
-                code: ERROR_CODE_OFFSET + code.id,
-                name: code.ident.to_string(),
-                msg: code.msg.clone(),
-            })
-            .collect::>()
-    });
-
-    let instructions = program
-        .ixs
-        .iter()
-        .map(|ix| {
-            let args = ix
-                .args
-                .iter()
-                .map(|arg| {
-                    let doc = if !no_docs {
-                        docs::parse(&arg.raw_arg.attrs)
-                    } else {
-                        None
-                    };
-                    IdlField {
-                        name: arg.name.to_string().to_mixed_case(),
-                        docs: doc,
-                        ty: to_idl_type(&ctx, &arg.raw_arg.ty),
-                    }
-                })
-                .collect::>();
-            // todo: don't unwrap
-            let accounts_strct = accs.get(&ix.anchor_ident.to_string()).unwrap();
-            let accounts = idl_accounts(&ctx, accounts_strct, &accs, seeds_feature, no_docs);
-            let ret_type_str = ix.returns.ty.to_token_stream().to_string();
-            let returns = match ret_type_str.as_str() {
-                "()" => None,
-                _ => Some(ret_type_str.parse().unwrap()),
-            };
-            IdlInstruction {
-                name: ix.ident.to_string().to_mixed_case(),
-                docs: ix.docs.clone(),
-                accounts,
-                args,
-                returns,
-            }
-        })
-        .collect::>();
-
-    let events = parse_events(&ctx)
-        .iter()
-        .map(|e: &&syn::ItemStruct| {
-            let fields = match &e.fields {
-                syn::Fields::Named(n) => n,
-                _ => panic!("Event fields must be named"),
-            };
-            let fields = fields
-                .named
-                .iter()
-                .map(|f: &syn::Field| {
-                    let index = match f.attrs.first() {
-                        None => false,
-                        Some(i) => parser::tts_to_string(&i.path) == "index",
-                    };
-                    IdlEventField {
-                        name: f.ident.clone().unwrap().to_string().to_mixed_case(),
-                        ty: to_idl_type(&ctx, &f.ty),
-                        index,
-                    }
-                })
-                .collect::>();
-
-            IdlEvent {
-                name: e.ident.to_string(),
-                fields,
-            }
-        })
-        .collect::>();
-
-    // All user defined types.
-    let mut accounts = vec![];
-    let mut types = vec![];
-    let ty_defs = parse_ty_defs(&ctx, no_docs)?;
-
-    let account_structs = parse_accounts(&ctx);
-    let account_names: HashSet = account_structs
-        .iter()
-        .map(|a| a.ident.to_string())
-        .collect::>();
-
-    let error_name = error.map(|e| e.name).unwrap_or_default();
-
-    // All types that aren't in the accounts section, are in the types section.
-    for ty_def in ty_defs {
-        // Don't add the error type to the types or accounts sections.
-        if ty_def.name != error_name {
-            if account_names.contains(&ty_def.name) {
-                accounts.push(ty_def);
-            } else if !events.iter().any(|e| e.name == ty_def.name) {
-                types.push(ty_def);
-            }
-        }
-    }
-
-    let constants = parse_consts(&ctx)
-        .iter()
-        .map(|c: &&syn::ItemConst| to_idl_const(c))
-        .collect::>();
-
-    Ok(Idl {
-        version,
-        name: program.name.to_string(),
-        docs: program.docs.clone(),
-        instructions,
-        types,
-        accounts,
-        events: if events.is_empty() {
-            None
-        } else {
-            Some(events)
-        },
-        errors: error_codes,
-        metadata: None,
-        constants,
-    })
-}
-
-/// Parse the main program mod.
-fn parse_program_mod(ctx: &CrateContext) -> Result {
-    let root = ctx.root_module();
-    let mods = root
-        .items()
-        .filter_map(|i| match i {
-            syn::Item::Mod(item_mod) => {
-                let mod_count = item_mod
-                    .attrs
-                    .iter()
-                    .filter(|attr| attr.path.segments.last().unwrap().ident == "program")
-                    .count();
-                if mod_count != 1 {
-                    return None;
-                }
-                Some(item_mod)
-            }
-            _ => None,
-        })
-        .collect::>();
-
-    match mods.len() {
-        0 => Err(anyhow!("Program module not found")),
-        1 => Ok(mods[0].clone()),
-        _ => Err(anyhow!("Multiple program modules are not allowed")),
-    }
-}
-
-fn parse_error_enum(ctx: &CrateContext) -> Option {
-    ctx.enums()
-        .find(|item_enum| {
-            let attrs_count = item_enum
-                .attrs
-                .iter()
-                .filter(|attr| {
-                    let segment = attr.path.segments.last().unwrap();
-                    segment.ident == "error_code"
-                })
-                .count();
-            match attrs_count {
-                0 => false,
-                1 => true,
-                _ => panic!("Invalid syntax: one error attribute allowed"),
-            }
-        })
-        .cloned()
-}
-
-fn parse_events(ctx: &CrateContext) -> Vec<&syn::ItemStruct> {
-    ctx.structs()
-        .filter(|item_strct| {
-            let attrs_count = item_strct
-                .attrs
-                .iter()
-                .filter(|attr| {
-                    let segment = attr.path.segments.last().unwrap();
-                    segment.ident == "event"
-                })
-                .count();
-            match attrs_count {
-                0 => false,
-                1 => true,
-                _ => panic!("Invalid syntax: one event attribute allowed"),
-            }
-        })
-        .collect()
-}
-
-fn parse_accounts(ctx: &CrateContext) -> Vec<&syn::ItemStruct> {
-    ctx.structs()
-        .filter(|item_strct| {
-            let attrs_count = item_strct
-                .attrs
-                .iter()
-                .filter(|attr| {
-                    let segment = attr.path.segments.last().unwrap();
-                    segment.ident == "account" || segment.ident == "associated"
-                })
-                .count();
-            match attrs_count {
-                0 => false,
-                1 => true,
-                _ => panic!("Invalid syntax: one account attribute allowed"),
-            }
-        })
-        .collect()
-}
-
-// Parse all structs implementing the `Accounts` trait.
-fn parse_account_derives(ctx: &CrateContext) -> HashMap {
-    // TODO: parse manual implementations. Currently we only look
-    //       for derives.
-    ctx.structs()
-        .filter_map(|i_strct| {
-            for attr in &i_strct.attrs {
-                if attr.path.is_ident("derive") && attr.tokens.to_string().contains(DERIVE_NAME) {
-                    let strct = accounts::parse(i_strct).expect("Code not parseable");
-                    return Some((strct.ident.to_string(), strct));
-                }
-            }
-            None
-        })
-        .collect()
-}
-
-fn parse_consts(ctx: &CrateContext) -> Vec<&syn::ItemConst> {
-    ctx.consts()
-        .filter(|item_strct| {
-            for attr in &item_strct.attrs {
-                if attr.path.segments.last().unwrap().ident == "constant" {
-                    return true;
-                }
-            }
-            false
-        })
-        .collect()
-}
-
-// Parse all user defined types in the file.
-fn parse_ty_defs(ctx: &CrateContext, no_docs: bool) -> Result> {
-    ctx.structs()
-        .filter_map(|item_strct| {
-            // Only take public types
-            if !matches!(&item_strct.vis, syn::Visibility::Public(_)) {
-                return None;
-            }
-
-            // Only take serializable types
-            let serializable = item_strct.attrs.iter().any(|attr| {
-                let attr_string = attr.tokens.to_string();
-                let attr_name = attr.path.segments.last().unwrap().ident.to_string();
-                let attr_serializable = ["account", "associated", "event", "zero_copy"];
-
-                let derived_serializable = attr_name == "derive"
-                    && attr_string.contains("AnchorSerialize")
-                    && attr_string.contains("AnchorDeserialize");
-
-                attr_serializable.iter().any(|a| *a == attr_name) || derived_serializable
-            });
-
-            if !serializable {
-                return None;
-            }
-
-            let name = item_strct.ident.to_string();
-            let doc = if !no_docs {
-                docs::parse(&item_strct.attrs)
-            } else {
-                None
-            };
-            let fields = match &item_strct.fields {
-                syn::Fields::Named(fields) => fields
-                    .named
-                    .iter()
-                    .map(|f: &syn::Field| {
-                        let doc = if !no_docs {
-                            docs::parse(&f.attrs)
-                        } else {
-                            None
-                        };
-                        Ok(IdlField {
-                            name: f.ident.as_ref().unwrap().to_string().to_mixed_case(),
-                            docs: doc,
-                            ty: to_idl_type(ctx, &f.ty),
-                        })
-                    })
-                    .collect::>>(),
-                syn::Fields::Unnamed(_) => return None,
-                _ => panic!("Empty structs are not allowed."),
-            };
-
-            Some(fields.map(|fields| IdlTypeDefinition {
-                name,
-                generics: None,
-                docs: doc,
-                ty: IdlTypeDefinitionTy::Struct { fields },
-            }))
-        })
-        .chain(ctx.enums().filter_map(|enm| {
-            // Only take public types
-            if !matches!(&enm.vis, syn::Visibility::Public(_)) {
-                return None;
-            }
-
-            let name = enm.ident.to_string();
-            let doc = if !no_docs {
-                docs::parse(&enm.attrs)
-            } else {
-                None
-            };
-            let variants = enm
-                .variants
-                .iter()
-                .map(|variant: &syn::Variant| {
-                    let name = variant.ident.to_string();
-                    let fields = match &variant.fields {
-                        syn::Fields::Unit => None,
-                        syn::Fields::Unnamed(fields) => {
-                            let fields: Vec = fields
-                                .unnamed
-                                .iter()
-                                .map(|f| to_idl_type(ctx, &f.ty))
-                                .collect();
-                            Some(EnumFields::Tuple(fields))
-                        }
-                        syn::Fields::Named(fields) => {
-                            let fields: Vec = fields
-                                .named
-                                .iter()
-                                .map(|f: &syn::Field| {
-                                    let name =
-                                        f.ident.as_ref().unwrap().to_string().to_mixed_case();
-                                    let doc = if !no_docs {
-                                        docs::parse(&f.attrs)
-                                    } else {
-                                        None
-                                    };
-                                    let ty = to_idl_type(ctx, &f.ty);
-                                    IdlField {
-                                        name,
-                                        docs: doc,
-                                        ty,
-                                    }
-                                })
-                                .collect();
-                            Some(EnumFields::Named(fields))
-                        }
-                    };
-                    IdlEnumVariant { name, fields }
-                })
-                .collect::>();
-
-            Some(Ok(IdlTypeDefinition {
-                name,
-                generics: None,
-                docs: doc,
-                ty: IdlTypeDefinitionTy::Enum { variants },
-            }))
-        }))
-        .chain(ctx.type_aliases().filter_map(|alias| {
-            // Only take public types
-            if !matches!(&alias.vis, syn::Visibility::Public(_)) {
-                return None;
-            }
-            // Generic type aliases are not currently supported
-            if alias.generics.lt_token.is_some() {
-                return None;
-            }
-
-            let name = alias.ident.to_string();
-            let doc = if !no_docs {
-                docs::parse(&alias.attrs)
-            } else {
-                None
-            };
-            let result = IdlType::from_str(&alias.ty.to_token_stream().to_string()).map(|value| {
-                IdlTypeDefinition {
-                    name,
-                    generics: None,
-                    docs: doc,
-                    ty: IdlTypeDefinitionTy::Alias { value },
-                }
-            });
-
-            match &result {
-                Ok(_) => Some(result),
-                Err(_) => None,
-            }
-        }))
-        .collect()
-}
-
-// Replace variable array lengths with values
-fn resolve_variable_array_lengths(ctx: &CrateContext, mut tts_string: String) -> String {
-    for constant in ctx.consts().filter(|c| match *c.ty {
-        // Filter to only those consts that are of type usize or could be cast to usize
-        syn::Type::Path(ref p) => {
-            let segment = p.path.segments.last().unwrap();
-            matches!(
-                segment.ident.to_string().as_str(),
-                "usize"
-                    | "u8"
-                    | "u16"
-                    | "u32"
-                    | "u64"
-                    | "u128"
-                    | "isize"
-                    | "i8"
-                    | "i16"
-                    | "i32"
-                    | "i64"
-                    | "i128"
-            )
-        }
-        _ => false,
-    }) {
-        let mut check_string = tts_string.clone();
-        // Strip whitespace to handle accidental double whitespaces
-        check_string.retain(|c| !c.is_whitespace());
-        let size_string = format!("{}]", &constant.ident.to_string());
-        let cast_size_string = format!("{}asusize]", &constant.ident.to_string());
-        // Check for something to replace
-        let mut replacement_string = None;
-        if check_string.contains(cast_size_string.as_str()) {
-            replacement_string = Some(cast_size_string);
-        } else if check_string.contains(size_string.as_str()) {
-            replacement_string = Some(size_string);
-        }
-        if let Some(replacement_string) = replacement_string {
-            // Check for the existence of consts existing elsewhere in the
-            // crate which have the same name, are usize, and have a
-            // different value. We can't know which was intended for the
-            // array size from ctx.
-            if ctx.consts().any(|c| {
-                c != constant
-                    && c.ident == constant.ident
-                    && c.ty == constant.ty
-                    && c.expr != constant.expr
-            }) {
-                panic!("Crate wide unique name required for array size const.");
-            }
-            // Replace the match, don't break because there might be multiple replacements to be
-            // made in the case of multidimensional arrays
-            tts_string = check_string.replace(
-                &replacement_string,
-                format!("{}]", &constant.expr.to_token_stream()).as_str(),
-            );
-        }
-    }
-    tts_string
-}
-
-fn to_idl_type(ctx: &CrateContext, ty: &syn::Type) -> IdlType {
-    let mut tts_string = parser::tts_to_string(ty);
-    if tts_string.starts_with('[') {
-        tts_string = resolve_variable_array_lengths(ctx, tts_string);
-    }
-    // Box -> FooType
-    tts_string = tts_string
-        .strip_prefix("Box < ")
-        .and_then(|t| t.strip_suffix(" >"))
-        .unwrap_or(&tts_string)
-        .into();
-
-    tts_string.parse().unwrap()
-}
-
-// TODO parse other issues
-fn to_idl_const(item: &ItemConst) -> IdlConst {
-    let name = item.ident.to_string();
-
-    if let Expr::Lit(ExprLit { lit, .. }) = &*item.expr {
-        match lit {
-            ByteStr(lit_byte_str) => {
-                return IdlConst {
-                    name,
-                    ty: IdlType::Bytes,
-                    value: format!("{:?}", lit_byte_str.value()),
-                }
-            }
-            Byte(lit_byte) => {
-                return IdlConst {
-                    name,
-                    ty: IdlType::U8,
-                    value: lit_byte.value().to_string(),
-                }
-            }
-            _ => (),
-        }
-    }
-
-    IdlConst {
-        name,
-        ty: item.ty.to_token_stream().to_string().parse().unwrap(),
-        value: item.expr.to_token_stream().to_string().parse().unwrap(),
-    }
-}
-
-fn idl_accounts(
-    ctx: &CrateContext,
-    accounts: &AccountsStruct,
-    global_accs: &HashMap,
-    seeds_feature: bool,
-    no_docs: bool,
-) -> Vec {
-    accounts
-        .fields
-        .iter()
-        .map(|acc: &AccountField| match acc {
-            AccountField::CompositeField(comp_f) => {
-                let accs_strct = global_accs.get(&comp_f.symbol).unwrap_or_else(|| {
-                    panic!("Could not resolve Accounts symbol {}", comp_f.symbol)
-                });
-                let accounts = idl_accounts(ctx, accs_strct, global_accs, seeds_feature, no_docs);
-                IdlAccountItem::IdlAccounts(IdlAccounts {
-                    name: comp_f.ident.to_string().to_mixed_case(),
-                    accounts,
-                })
-            }
-            AccountField::Field(acc) => IdlAccountItem::IdlAccount(IdlAccount {
-                name: acc.ident.to_string().to_mixed_case(),
-                is_mut: acc.constraints.is_mutable(),
-                is_signer: match acc.ty {
-                    Ty::Signer => true,
-                    _ => acc.constraints.is_signer(),
-                },
-                is_optional: if acc.is_optional { Some(true) } else { None },
-                docs: if !no_docs { acc.docs.clone() } else { None },
-                pda: super::pda::parse(ctx, accounts, acc, seeds_feature),
-                relations: relations::parse(acc, seeds_feature),
-            }),
-        })
-        .collect::>()
-}
diff --git a/lang/syn/src/idl/parse/mod.rs b/lang/syn/src/idl/parse/mod.rs
deleted file mode 100644
index 88dc4e7ba7..0000000000
--- a/lang/syn/src/idl/parse/mod.rs
+++ /dev/null
@@ -1,120 +0,0 @@
-use crate::idl::types::*;
-
-pub mod file;
-pub mod pda;
-pub mod relations;
-
-impl std::str::FromStr for IdlType {
-    type Err = anyhow::Error;
-
-    fn from_str(s: &str) -> Result {
-        let mut s = s.to_string();
-        fn array_from_str(inner: &str) -> IdlType {
-            match inner.strip_suffix(']') {
-                None => {
-                    let (raw_type, raw_length) = inner.rsplit_once(';').unwrap();
-                    let ty = IdlType::from_str(raw_type).unwrap();
-                    let len = raw_length.replace('_', "").parse::().unwrap();
-                    IdlType::Array(Box::new(ty), len)
-                }
-                Some(nested_inner) => array_from_str(&nested_inner[1..]),
-            }
-        }
-        s.retain(|c| !c.is_whitespace());
-
-        let r = match s.as_str() {
-            "bool" => IdlType::Bool,
-            "u8" => IdlType::U8,
-            "i8" => IdlType::I8,
-            "u16" => IdlType::U16,
-            "i16" => IdlType::I16,
-            "u32" => IdlType::U32,
-            "i32" => IdlType::I32,
-            "f32" => IdlType::F32,
-            "u64" => IdlType::U64,
-            "i64" => IdlType::I64,
-            "f64" => IdlType::F64,
-            "u128" => IdlType::U128,
-            "i128" => IdlType::I128,
-            "u256" => IdlType::U256,
-            "i256" => IdlType::I256,
-            "Vec" => IdlType::Bytes,
-            "String" | "&str" | "&'staticstr" => IdlType::String,
-            "Pubkey" => IdlType::PublicKey,
-            _ => match s.to_string().strip_prefix("Option<") {
-                None => match s.to_string().strip_prefix("Vec<") {
-                    None => {
-                        if s.to_string().starts_with('[') {
-                            array_from_str(&s)
-                        } else {
-                            IdlType::Defined(s.to_string())
-                        }
-                    }
-                    Some(inner) => {
-                        let inner_ty = Self::from_str(
-                            inner
-                                .strip_suffix('>')
-                                .ok_or_else(|| anyhow::anyhow!("Invalid option"))?,
-                        )?;
-                        IdlType::Vec(Box::new(inner_ty))
-                    }
-                },
-                Some(inner) => {
-                    let inner_ty = Self::from_str(
-                        inner
-                            .strip_suffix('>')
-                            .ok_or_else(|| anyhow::anyhow!("Invalid option"))?,
-                    )?;
-                    IdlType::Option(Box::new(inner_ty))
-                }
-            },
-        };
-        Ok(r)
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::idl::types::IdlType;
-    use std::str::FromStr;
-
-    #[test]
-    fn multidimensional_array() {
-        assert_eq!(
-            IdlType::from_str("[[u8;16];32]").unwrap(),
-            IdlType::Array(Box::new(IdlType::Array(Box::new(IdlType::U8), 16)), 32)
-        );
-    }
-
-    #[test]
-    fn array() {
-        assert_eq!(
-            IdlType::from_str("[Pubkey;16]").unwrap(),
-            IdlType::Array(Box::new(IdlType::PublicKey), 16)
-        );
-    }
-
-    #[test]
-    fn array_with_underscored_length() {
-        assert_eq!(
-            IdlType::from_str("[u8;50_000]").unwrap(),
-            IdlType::Array(Box::new(IdlType::U8), 50000)
-        );
-    }
-
-    #[test]
-    fn option() {
-        assert_eq!(
-            IdlType::from_str("Option").unwrap(),
-            IdlType::Option(Box::new(IdlType::Bool))
-        )
-    }
-
-    #[test]
-    fn vector() {
-        assert_eq!(
-            IdlType::from_str("Vec").unwrap(),
-            IdlType::Vec(Box::new(IdlType::Bool))
-        )
-    }
-}
diff --git a/lang/syn/src/idl/parse/pda.rs b/lang/syn/src/idl/parse/pda.rs
deleted file mode 100644
index d9561c29c1..0000000000
--- a/lang/syn/src/idl/parse/pda.rs
+++ /dev/null
@@ -1,389 +0,0 @@
-use crate::idl::types::*;
-use crate::parser;
-use crate::parser::context::CrateContext;
-use crate::ConstraintSeedsGroup;
-use crate::{AccountsStruct, Field};
-use std::collections::HashMap;
-use std::str::FromStr;
-use syn::{Expr, ExprLit, Lit, Path};
-
-// Parses a seeds constraint, extracting the IdlSeed types.
-//
-// Note: This implementation makes assumptions about the types that can be used
-//       (e.g., no program-defined function calls in seeds).
-//
-//       This probably doesn't cover all cases. If you see a warning log, you
-//       can add a new case here. In the worst case, we miss a seed and
-//       the parser will treat the given seeds as empty and so clients will
-//       simply fail to automatically populate the PDA accounts.
-//
-// Seed Assumptions: Seeds must be of one of the following forms:
-//
-// - instruction argument.
-// - account context field pubkey.
-// - account data, where the account is defined in the current program.
-//   We make an exception for the SPL token program, since it is so common
-//   and sometimes convenient to use fields as a seed (e.g. Auction house
-//   program). In the case of nested structs/account data, all nested structs
-//   must be defined in the current program as well.
-// - byte string literal (e.g. b"MY_SEED").
-// - byte string literal constant  (e.g. `pub const MY_SEED: [u8; 2] = *b"hi";`).
-// - array constants.
-//
-pub fn parse(
-    ctx: &CrateContext,
-    accounts: &AccountsStruct,
-    acc: &Field,
-    seeds_feature: bool,
-) -> Option {
-    if !seeds_feature {
-        return None;
-    }
-    let pda_parser = PdaParser::new(ctx, accounts);
-    acc.constraints
-        .seeds
-        .as_ref()
-        .map(|s| pda_parser.parse(s))
-        .unwrap_or(None)
-}
-
-struct PdaParser<'a> {
-    ctx: &'a CrateContext,
-    // Accounts context.
-    accounts: &'a AccountsStruct,
-    // Maps var name to var type. These are the instruction arguments in a
-    // given accounts context.
-    ix_args: HashMap,
-    // Constants available in the crate.
-    const_names: Vec,
-    // Constants declared in impl blocks available in the crate
-    impl_const_names: Vec,
-    // All field names of the accounts in the accounts context.
-    account_field_names: Vec,
-}
-
-impl<'a> PdaParser<'a> {
-    fn new(ctx: &'a CrateContext, accounts: &'a AccountsStruct) -> Self {
-        // All the available sources of seeds.
-        let ix_args = accounts.instruction_args().unwrap_or_default();
-        let const_names: Vec = ctx.consts().map(|c| c.ident.to_string()).collect();
-
-        let impl_const_names: Vec = ctx
-            .impl_consts()
-            .map(|(ident, item)| format!("{} :: {}", ident, item.ident))
-            .collect();
-
-        let account_field_names = accounts.field_names();
-
-        Self {
-            ctx,
-            accounts,
-            ix_args,
-            const_names,
-            impl_const_names,
-            account_field_names,
-        }
-    }
-
-    fn parse(&self, seeds_grp: &ConstraintSeedsGroup) -> Option {
-        // Extract the idl seed types from the constraints.
-        let seeds = seeds_grp
-            .seeds
-            .iter()
-            .map(|s| self.parse_seed(s))
-            .collect::>>()?;
-        // Parse the program id from the constraints.
-        let program_id = seeds_grp
-            .program_seed
-            .as_ref()
-            .map(|pid| self.parse_seed(pid))
-            .unwrap_or_default();
-
-        // Done.
-        Some(IdlPda { seeds, program_id })
-    }
-
-    fn parse_seed(&self, seed: &Expr) -> Option {
-        match seed {
-            Expr::MethodCall(_) => {
-                let seed_path = parse_seed_path(seed)?;
-
-                if self.is_instruction(&seed_path) {
-                    self.parse_instruction(&seed_path)
-                } else if self.is_const(&seed_path) {
-                    self.parse_const(&seed_path)
-                } else if self.is_impl_const(&seed_path) {
-                    self.parse_impl_const(&seed_path)
-                } else if self.is_account(&seed_path) {
-                    self.parse_account(&seed_path)
-                } else if self.is_str_literal(&seed_path) {
-                    self.parse_str_literal(&seed_path)
-                } else {
-                    println!("WARNING: unexpected seed category for var: {seed_path:?}");
-                    None
-                }
-            }
-            Expr::Reference(expr_reference) => self.parse_seed(&expr_reference.expr),
-            Expr::Index(_) => {
-                println!("WARNING: auto pda derivation not currently supported for slice literals");
-                None
-            }
-            Expr::Lit(ExprLit {
-                lit: Lit::ByteStr(lit_byte_str),
-                ..
-            }) => {
-                let seed_path: SeedPath = SeedPath(lit_byte_str.token().to_string(), Vec::new());
-                self.parse_str_literal(&seed_path)
-            }
-            Expr::Path(expr_path) => self.parse_const_path(&expr_path.path),
-            // Unknown type. Please file an issue.
-            _ => {
-                println!("WARNING: unexpected seed: {seed:?}");
-                None
-            }
-        }
-    }
-
-    fn parse_instruction(&self, seed_path: &SeedPath) -> Option {
-        let idl_ty = IdlType::from_str(self.ix_args.get(&seed_path.name()).unwrap()).ok()?;
-        Some(IdlSeed::Arg(IdlSeedArg {
-            ty: idl_ty,
-            path: seed_path.path(),
-        }))
-    }
-
-    fn parse_const_path(&self, path: &Path) -> Option {
-        let ident = &path.segments.first().unwrap().ident;
-
-        let const_item = self.ctx.consts().find(|c| c.ident == *ident).unwrap();
-        let idl_ty = IdlType::from_str(&parser::tts_to_string(&const_item.ty)).ok()?;
-
-        let idl_ty_value = parser::tts_to_string(&const_item.expr);
-        let idl_ty_value: String = str_lit_to_array(&idl_ty, &idl_ty_value);
-
-        let seed_path: SeedPath = SeedPath(idl_ty_value, Vec::new());
-
-        if self.is_str_literal(&seed_path) {
-            self.parse_str_literal(&seed_path)
-        } else {
-            println!("WARNING: unexpected constant path value: {seed_path:?}");
-            None
-        }
-    }
-
-    fn parse_const(&self, seed_path: &SeedPath) -> Option {
-        // Pull in the constant value directly into the IDL.
-        assert!(seed_path.components().is_empty());
-        let const_item = self
-            .ctx
-            .consts()
-            .find(|c| c.ident == seed_path.name())
-            .unwrap();
-        let idl_ty = IdlType::from_str(&parser::tts_to_string(&const_item.ty)).ok()?;
-
-        let idl_ty_value = parser::tts_to_string(&const_item.expr);
-        let idl_ty_value = str_lit_to_array(&idl_ty, &idl_ty_value);
-
-        Some(IdlSeed::Const(IdlSeedConst {
-            ty: idl_ty,
-            value: serde_json::from_str(&idl_ty_value).unwrap(),
-        }))
-    }
-
-    fn parse_impl_const(&self, seed_path: &SeedPath) -> Option {
-        // Pull in the constant value directly into the IDL.
-        assert!(seed_path.components().is_empty());
-        let static_item = self
-            .ctx
-            .impl_consts()
-            .find(|(ident, item)| format!("{} :: {}", ident, item.ident) == seed_path.name())
-            .unwrap()
-            .1;
-
-        let idl_ty = IdlType::from_str(&parser::tts_to_string(&static_item.ty)).ok()?;
-
-        let idl_ty_value = parser::tts_to_string(&static_item.expr);
-        let idl_ty_value = str_lit_to_array(&idl_ty, &idl_ty_value);
-
-        Some(IdlSeed::Const(IdlSeedConst {
-            ty: idl_ty,
-            value: serde_json::from_str(&idl_ty_value).unwrap(),
-        }))
-    }
-
-    fn parse_account(&self, seed_path: &SeedPath) -> Option {
-        // Get the anchor account field from the derive accounts struct.
-        let account_field = self
-            .accounts
-            .fields
-            .iter()
-            .find(|field| *field.ident() == seed_path.name())
-            .unwrap();
-
-        // Follow the path to find the seed type.
-        let ty = {
-            let mut path = seed_path.components();
-            match path.len() {
-                0 => IdlType::PublicKey,
-                1 => {
-                    // Name of the account struct.
-                    let account = account_field.ty_name()?;
-                    if account == "TokenAccount" {
-                        assert!(path.len() == 1);
-                        match path[0].as_str() {
-                            "mint" => IdlType::PublicKey,
-                            "amount" => IdlType::U64,
-                            "authority" => IdlType::PublicKey,
-                            "delegated_amount" => IdlType::U64,
-                            _ => {
-                                println!("WARNING: token field isn't supported: {}", &path[0]);
-                                return None;
-                            }
-                        }
-                    } else {
-                        // Get the rust representation of the field's struct.
-                        let strct = self.ctx.structs().find(|s| s.ident == account).unwrap();
-                        parse_field_path(self.ctx, strct, &mut path)
-                    }
-                }
-                _ => panic!("invariant violation"),
-            }
-        };
-
-        Some(IdlSeed::Account(IdlSeedAccount {
-            ty,
-            account: account_field.ty_name(),
-            path: seed_path.path(),
-        }))
-    }
-
-    fn parse_str_literal(&self, seed_path: &SeedPath) -> Option {
-        let mut var_name = seed_path.name();
-        // Remove the byte `b` prefix if the string is of the form `b"seed".
-        if var_name.starts_with("b\"") {
-            var_name.remove(0);
-        }
-        let value_string: String = var_name.chars().filter(|c| *c != '"').collect();
-        Some(IdlSeed::Const(IdlSeedConst {
-            value: serde_json::Value::String(value_string),
-            ty: IdlType::String,
-        }))
-    }
-
-    fn is_instruction(&self, seed_path: &SeedPath) -> bool {
-        self.ix_args.contains_key(&seed_path.name())
-    }
-
-    fn is_const(&self, seed_path: &SeedPath) -> bool {
-        self.const_names.contains(&seed_path.name())
-    }
-
-    fn is_impl_const(&self, seed_path: &SeedPath) -> bool {
-        self.impl_const_names.contains(&seed_path.name())
-    }
-
-    fn is_account(&self, seed_path: &SeedPath) -> bool {
-        self.account_field_names.contains(&seed_path.name())
-    }
-
-    fn is_str_literal(&self, seed_path: &SeedPath) -> bool {
-        seed_path.components().is_empty() && seed_path.name().contains('"')
-    }
-}
-
-// SeedPath represents the deconstructed syntax of a single pda seed,
-// consisting of a variable name and a vec of all the sub fields accessed
-// on that variable name. For example, if a seed is `my_field.my_data.as_ref()`,
-// then the field name is `my_field` and the vec of sub fields is `[my_data]`.
-#[derive(Debug)]
-struct SeedPath(String, Vec);
-
-impl SeedPath {
-    fn name(&self) -> String {
-        self.0.clone()
-    }
-
-    // Full path to the data this seed represents.
-    fn path(&self) -> String {
-        match self.1.len() {
-            0 => self.0.clone(),
-            _ => format!("{}.{}", self.name(), self.components().join(".")),
-        }
-    }
-
-    // All path components for the subfields accessed on this seed.
-    fn components(&self) -> &[String] {
-        &self.1
-    }
-}
-
-// Extracts the seed path from a single seed expression.
-fn parse_seed_path(seed: &Expr) -> Option {
-    // Convert the seed into the raw string representation.
-    let seed_str = parser::tts_to_string(seed);
-
-    // Break up the seed into each sub field component.
-    let mut components: Vec<&str> = seed_str.split(" . ").collect();
-    if components.len() <= 1 {
-        println!("WARNING: seeds are in an unexpected format: {seed:?}");
-        return None;
-    }
-
-    // The name of the variable (or field).
-    let name = components.remove(0).to_string();
-
-    // The path to the seed (only if the `name` type is a struct).
-    let mut path = Vec::new();
-    while !components.is_empty() {
-        let c = components.remove(0);
-        if c.contains("()") {
-            break;
-        }
-        path.push(c.to_string());
-    }
-    if path.len() == 1 && (path[0] == "key" || path[0] == "key()") {
-        path = Vec::new();
-    }
-
-    Some(SeedPath(name, path))
-}
-
-fn parse_field_path(ctx: &CrateContext, strct: &syn::ItemStruct, path: &mut &[String]) -> IdlType {
-    let field_name = &path[0];
-    *path = &path[1..];
-
-    // Get the type name for the field.
-    let next_field = strct
-        .fields
-        .iter()
-        .find(|f| &f.ident.clone().unwrap().to_string() == field_name)
-        .unwrap();
-    let next_field_ty_str = parser::tts_to_string(&next_field.ty);
-
-    // The path is empty so this must be a primitive type.
-    if path.is_empty() {
-        return next_field_ty_str.parse().unwrap();
-    }
-
-    // Get the rust representation of hte field's struct.
-    let strct = ctx
-        .structs()
-        .find(|s| s.ident == next_field_ty_str)
-        .unwrap();
-
-    parse_field_path(ctx, strct, path)
-}
-
-fn str_lit_to_array(idl_ty: &IdlType, idl_ty_value: &String) -> String {
-    if let IdlType::Array(_ty, _size) = &idl_ty {
-        // Convert str literal to array.
-        if idl_ty_value.contains("b\"") {
-            let components: Vec<&str> = idl_ty_value.split('b').collect();
-            assert_eq!(components.len(), 2);
-            let mut str_lit = components[1].to_string();
-            str_lit.retain(|c| c != '"');
-            return format!("{:?}", str_lit.as_bytes());
-        }
-    }
-    idl_ty_value.to_string()
-}
diff --git a/lang/syn/src/idl/parse/relations.rs b/lang/syn/src/idl/parse/relations.rs
deleted file mode 100644
index b7276c72a2..0000000000
--- a/lang/syn/src/idl/parse/relations.rs
+++ /dev/null
@@ -1,19 +0,0 @@
-use crate::Field;
-use syn::Expr;
-
-pub fn parse(acc: &Field, seeds_feature: bool) -> Vec {
-    if !seeds_feature {
-        return vec![];
-    }
-    acc.constraints
-        .has_one
-        .iter()
-        .flat_map(|s| match &s.join_target {
-            Expr::Path(path) => path.path.segments.first().map(|l| l.ident.to_string()),
-            _ => {
-                println!("WARNING: unexpected seed: {s:?}");
-                None
-            }
-        })
-        .collect()
-}
diff --git a/lang/syn/src/idl/program.rs b/lang/syn/src/idl/program.rs
new file mode 100644
index 0000000000..dd2666f35d
--- /dev/null
+++ b/lang/syn/src/idl/program.rs
@@ -0,0 +1,177 @@
+use anyhow::{anyhow, Result};
+use heck::CamelCase;
+use proc_macro2::TokenStream;
+use quote::{format_ident, quote};
+
+use super::{
+    common::{gen_print_section, get_idl_module_path, get_no_docs, get_program_path},
+    defined::gen_idl_type,
+};
+use crate::{
+    parser::{context::CrateContext, docs},
+    Program,
+};
+
+/// Generate the IDL build print function for the program module.
+pub fn gen_idl_print_fn_program(program: &Program) -> TokenStream {
+    check_safety_comments().unwrap_or_else(|e| panic!("Safety checks failed: {e}"));
+
+    let idl = get_idl_module_path();
+    let no_docs = get_no_docs();
+
+    let name = program.name.to_string();
+    let docs = match &program.docs {
+        Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
+        _ => quote! { vec![] },
+    };
+
+    let (instructions, defined) = program
+        .ixs
+        .iter()
+        .flat_map(|ix| -> Result<_> {
+            let name = ix.ident.to_string();
+            let name_pascal = format_ident!("{}", name.to_camel_case());
+            let ctx_ident = &ix.anchor_ident;
+
+            let docs = match &ix.docs {
+                Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
+                _ => quote! { vec![] },
+            };
+
+            let (args, mut defined) = ix
+                .args
+                .iter()
+                .map(|arg| {
+                    let name = arg.name.to_string();
+                    let docs = match docs::parse(&arg.raw_arg.attrs) {
+                        Some(docs) if !no_docs => quote! { vec![#(#docs.into()),*] },
+                        _ => quote! { vec![] },
+                    };
+                    let (ty, defined) = gen_idl_type(&arg.raw_arg.ty, &[])?;
+
+                    Ok((
+                        quote! {
+                            #idl::IdlField {
+                                name: #name.into(),
+                                docs: #docs,
+                                ty: #ty,
+                            }
+                        },
+                        defined,
+                    ))
+                })
+                .collect::>>()?
+                .into_iter()
+                .unzip::<_, Vec<_>, Vec<_>, Vec<_>>();
+
+            let returns = match gen_idl_type(&ix.returns.ty, &[]) {
+                Ok((ty, def)) => {
+                    defined.push(def);
+                    quote! { Some(#ty) }
+                }
+                _ => quote! { None },
+            };
+
+            Ok((
+                quote! {
+                    #idl::IdlInstruction {
+                        name: #name.into(),
+                        docs: #docs,
+                        discriminator: crate::instruction::#name_pascal::DISCRIMINATOR.into(),
+                        accounts: #ctx_ident::__anchor_private_gen_idl_accounts(
+                            &mut accounts,
+                            &mut types,
+                        ),
+                        args: vec![#(#args),*],
+                        returns: #returns,
+                    }
+                },
+                defined,
+            ))
+        })
+        .unzip::<_, Vec<_>, Vec<_>, Vec<_>>();
+    let defined = defined.into_iter().flatten().flatten().collect::>();
+
+    let fn_body = gen_print_section(
+        "program",
+        quote! {
+            let mut accounts: std::collections::BTreeMap =
+                std::collections::BTreeMap::new();
+            let mut types: std::collections::BTreeMap =
+                std::collections::BTreeMap::new();
+
+            #(
+                if let Some(ty) = <#defined>::create_type() {
+                    types.insert(<#defined>::get_full_path(), ty);
+                    <#defined>::insert_types(&mut types);
+                }
+            );*
+
+            #idl::Idl {
+                address: Default::default(),
+                metadata: #idl::IdlMetadata {
+                    name: #name.into(),
+                    version: env!("CARGO_PKG_VERSION").into(),
+                    spec: #idl::IDL_SPEC.into(),
+                    description: option_env!("CARGO_PKG_DESCRIPTION")
+                        .filter(|d| !d.is_empty())
+                        .map(|d| d.into()),
+                    repository: option_env!("CARGO_PKG_REPOSITORY")
+                        .filter(|r| !r.is_empty())
+                        .map(|r| r.into()),
+                    dependencies: Default::default(),
+                    contact: Default::default(),
+                    deployments: Default::default(),
+                },
+                docs: #docs,
+                instructions: vec![#(#instructions),*],
+                accounts: accounts.into_values().collect(),
+                events: Default::default(),
+                errors: Default::default(),
+                types: types.into_values().collect(),
+                constants: Default::default(),
+            }
+        },
+    );
+
+    quote! {
+        #[test]
+        pub fn __anchor_private_print_idl_program() {
+            #fn_body
+        }
+    }
+}
+
+/// Check safety comments.
+fn check_safety_comments() -> Result<()> {
+    let skip_lint = option_env!("ANCHOR_IDL_BUILD_SKIP_LINT")
+        .map(|val| val == "TRUE")
+        .unwrap_or_default();
+    if skip_lint {
+        return Ok(());
+    }
+
+    let program_path = get_program_path();
+    if program_path.is_err() {
+        // Getting the program path can fail in the following scenarios:
+        //
+        // - Anchor CLI version is incompatible with the current version
+        // - The error is coming from Rust Analyzer when the user has `idl-build` feature enabled,
+        // likely due to enabling all features (https://github.com/coral-xyz/anchor/issues/3042)
+        //
+        // For the first case, we have a warning when the user is using different versions of the
+        // lang and CLI crate. For the second case, users would either have to disable the
+        // `idl-build` feature, or define the program path environment variable in Rust Analyzer
+        // settings.
+        //
+        // Given this feature is not a critical one, and it works by default with `anchor build`,
+        // we can fail silently in the case of an error rather than panicking.
+        return Ok(());
+    }
+
+    program_path
+        .map(|path| path.join("src").join("lib.rs"))
+        .map(CrateContext::parse)?
+        .map_err(|e| anyhow!("Failed to parse crate: {e}"))?
+        .safety_checks()
+}
diff --git a/lang/syn/src/idl/types.rs b/lang/syn/src/idl/types.rs
deleted file mode 100644
index 0aa2956997..0000000000
--- a/lang/syn/src/idl/types.rs
+++ /dev/null
@@ -1,232 +0,0 @@
-use serde::{Deserialize, Serialize};
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct Idl {
-    pub version: String,
-    pub name: String,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub docs: Option>,
-    #[serde(skip_serializing_if = "Vec::is_empty", default)]
-    pub constants: Vec,
-    pub instructions: Vec,
-    #[serde(skip_serializing_if = "Vec::is_empty", default)]
-    pub accounts: Vec,
-    #[serde(skip_serializing_if = "Vec::is_empty", default)]
-    pub types: Vec,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub events: Option>,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub errors: Option>,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub metadata: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlConst {
-    pub name: String,
-    #[serde(rename = "type")]
-    pub ty: IdlType,
-    pub value: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlState {
-    #[serde(rename = "struct")]
-    pub strct: IdlTypeDefinition,
-    pub methods: Vec,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlInstruction {
-    pub name: String,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub docs: Option>,
-    pub accounts: Vec,
-    pub args: Vec,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub returns: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub struct IdlAccounts {
-    pub name: String,
-    pub accounts: Vec,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(untagged)]
-pub enum IdlAccountItem {
-    IdlAccount(IdlAccount),
-    IdlAccounts(IdlAccounts),
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub struct IdlAccount {
-    pub name: String,
-    pub is_mut: bool,
-    pub is_signer: bool,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub is_optional: Option,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub docs: Option>,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub pda: Option,
-    #[serde(skip_serializing_if = "Vec::is_empty", default)]
-    pub relations: Vec,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub struct IdlPda {
-    pub seeds: Vec,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub program_id: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase", tag = "kind")]
-pub enum IdlSeed {
-    Const(IdlSeedConst),
-    Arg(IdlSeedArg),
-    Account(IdlSeedAccount),
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub struct IdlSeedAccount {
-    #[serde(rename = "type")]
-    pub ty: IdlType,
-    // account_ty points to the entry in the "accounts" section.
-    // Some only if the `Account` type is used.
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub account: Option,
-    pub path: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub struct IdlSeedArg {
-    #[serde(rename = "type")]
-    pub ty: IdlType,
-    pub path: String,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub struct IdlSeedConst {
-    #[serde(rename = "type")]
-    pub ty: IdlType,
-    pub value: serde_json::Value,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlField {
-    pub name: String,
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub docs: Option>,
-    #[serde(rename = "type")]
-    pub ty: IdlType,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlEvent {
-    pub name: String,
-    pub fields: Vec,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlEventField {
-    pub name: String,
-    #[serde(rename = "type")]
-    pub ty: IdlType,
-    pub index: bool,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlTypeDefinition {
-    /// - `idl-parse`: always the name of the type
-    /// - `idl-build`: full path if there is a name conflict, otherwise the name of the type
-    pub name: String,
-    /// Documentation comments
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub docs: Option>,
-    /// Generics, only supported with `idl-build`
-    #[serde(skip_serializing_if = "Option::is_none")]
-    pub generics: Option>,
-    /// Type definition, `struct` or `enum`
-    #[serde(rename = "type")]
-    pub ty: IdlTypeDefinitionTy,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "lowercase", tag = "kind")]
-pub enum IdlTypeDefinitionTy {
-    Struct { fields: Vec },
-    Enum { variants: Vec },
-    Alias { value: IdlType },
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-pub struct IdlEnumVariant {
-    pub name: String,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub fields: Option,
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(untagged)]
-pub enum EnumFields {
-    Named(Vec),
-    Tuple(Vec),
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub enum IdlType {
-    Bool,
-    U8,
-    I8,
-    U16,
-    I16,
-    U32,
-    I32,
-    F32,
-    U64,
-    I64,
-    F64,
-    U128,
-    I128,
-    U256,
-    I256,
-    Bytes,
-    String,
-    PublicKey,
-    Defined(String),
-    Option(Box),
-    Vec(Box),
-    Array(Box, usize),
-    GenericLenArray(Box, String),
-    Generic(String),
-    DefinedWithTypeArgs {
-        name: String,
-        args: Vec,
-    },
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
-#[serde(rename_all = "camelCase")]
-pub enum IdlDefinedTypeArg {
-    Generic(String),
-    Value(String),
-    Type(IdlType),
-}
-
-#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
-pub struct IdlErrorCode {
-    pub code: u32,
-    pub name: String,
-    #[serde(skip_serializing_if = "Option::is_none", default)]
-    pub msg: Option,
-}
diff --git a/lang/syn/src/lib.rs b/lang/syn/src/lib.rs
index 7249d4dc3c..3f87e8b4e0 100644
--- a/lang/syn/src/lib.rs
+++ b/lang/syn/src/lib.rs
@@ -3,7 +3,7 @@
 pub mod codegen;
 pub mod parser;
 
-#[cfg(feature = "idl-types")]
+#[cfg(feature = "idl-build")]
 pub mod idl;
 
 #[cfg(feature = "hash")]
@@ -11,7 +11,6 @@ pub mod hash;
 #[cfg(not(feature = "hash"))]
 pub(crate) mod hash;
 
-use crate::parser::tts_to_string;
 use codegen::accounts as accounts_codegen;
 use codegen::program as program_codegen;
 use parser::accounts as accounts_parser;
@@ -26,6 +25,7 @@ use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult}
 use syn::punctuated::Punctuated;
 use syn::spanned::Spanned;
 use syn::token::Comma;
+use syn::Lit;
 use syn::{
     Expr, Generics, Ident, ItemEnum, ItemFn, ItemMod, ItemStruct, LitInt, PatType, Token, Type,
     TypePath,
@@ -69,7 +69,58 @@ pub struct Ix {
     // The ident for the struct deriving Accounts.
     pub anchor_ident: Ident,
     // The discriminator based on the `#[interface]` attribute.
+    // TODO: Remove and use `overrides`
     pub interface_discriminator: Option<[u8; 8]>,
+    /// Overrides coming from the `#[instruction]` attribute
+    pub overrides: Option,
+}
+
+/// Common overrides for the `#[instruction]`, `#[account]` and `#[event]` attributes
+#[derive(Debug, Default)]
+pub struct Overrides {
+    /// Override the default 8-byte discriminator
+    pub discriminator: Option,
+}
+
+impl Parse for Overrides {
+    fn parse(input: ParseStream) -> ParseResult {
+        let mut attr = Self::default();
+        let args = input.parse_terminated::<_, Comma>(NamedArg::parse)?;
+        for arg in args {
+            match arg.name.to_string().as_str() {
+                "discriminator" => {
+                    let value = match &arg.value {
+                        // Allow `discriminator = 42`
+                        Expr::Lit(lit) if matches!(lit.lit, Lit::Int(_)) => quote! { &[#lit] },
+                        // Allow `discriminator = [0, 1, 2, 3]`
+                        Expr::Array(arr) => quote! { &#arr },
+                        expr => expr.to_token_stream(),
+                    };
+                    attr.discriminator.replace(value)
+                }
+                _ => return Err(ParseError::new(arg.name.span(), "Invalid argument")),
+            };
+        }
+
+        Ok(attr)
+    }
+}
+
+struct NamedArg {
+    name: Ident,
+    #[allow(dead_code)]
+    eq_token: Token![=],
+    value: Expr,
+}
+
+impl Parse for NamedArg {
+    fn parse(input: ParseStream) -> ParseResult {
+        Ok(Self {
+            name: input.parse()?,
+            eq_token: input.parse()?,
+            value: input.parse()?,
+        })
+    }
 }
 
 #[derive(Debug)]
@@ -175,7 +226,7 @@ impl AccountsStruct {
         let matching_field = self
             .fields
             .iter()
-            .find(|f| *f.ident() == tts_to_string(field));
+            .find(|f| *f.ident() == parser::tts_to_string(field));
         if let Some(matching_field) = matching_field {
             matching_field.is_optional()
         } else {
@@ -681,6 +732,21 @@ pub enum ConstraintToken {
     Realloc(Context),
     ReallocPayer(Context),
     ReallocZero(Context),
+    // extensions
+    ExtensionGroupPointerAuthority(Context),
+    ExtensionGroupPointerGroupAddress(Context),
+    ExtensionGroupMemberPointerAuthority(Context),
+    ExtensionGroupMemberPointerMemberAddress(
+        Context,
+    ),
+    ExtensionMetadataPointerAuthority(Context),
+    ExtensionMetadataPointerMetadataAddress(
+        Context,
+    ),
+    ExtensionCloseAuthority(Context),
+    ExtensionTokenHookAuthority(Context),
+    ExtensionTokenHookProgramId(Context),
+    ExtensionPermanentDelegate(Context),
 }
 
 impl Parse for ConstraintToken {
@@ -797,6 +863,37 @@ pub struct ConstraintSpace {
     pub space: Expr,
 }
 
+// extension constraints
+#[derive(Debug, Clone)]
+pub struct ConstraintExtensionAuthority {
+    pub authority: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintExtensionGroupPointerGroupAddress {
+    pub group_address: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintExtensionGroupMemberPointerMemberAddress {
+    pub member_address: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintExtensionMetadataPointerMetadataAddress {
+    pub metadata_address: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintExtensionTokenHookProgramId {
+    pub program_id: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintExtensionPermanentDelegate {
+    pub permanent_delegate: Expr,
+}
+
 #[derive(Debug, Clone)]
 #[allow(clippy::large_enum_variant)]
 pub enum InitKind {
@@ -823,6 +920,17 @@ pub enum InitKind {
         freeze_authority: Option,
         decimals: Expr,
         token_program: Option,
+        // extensions
+        group_pointer_authority: Option,
+        group_pointer_group_address: Option,
+        group_member_pointer_authority: Option,
+        group_member_pointer_member_address: Option,
+        metadata_pointer_authority: Option,
+        metadata_pointer_metadata_address: Option,
+        close_authority: Option,
+        permanent_delegate: Option,
+        transfer_hook_authority: Option,
+        transfer_hook_program_id: Option,
     },
 }
 
@@ -836,6 +944,46 @@ pub struct ConstraintTokenMint {
     pub mint: Expr,
 }
 
+#[derive(Debug, Clone)]
+pub struct ConstraintMintConfidentialTransferData {
+    pub confidential_transfer_data: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintMintMetadata {
+    pub token_metadata: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintMintTokenGroupData {
+    pub token_group_data: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintMintTokenGroupMemberData {
+    pub token_group_member_data: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintMintMetadataPointerData {
+    pub metadata_pointer_data: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintMintGroupPointerData {
+    pub group_pointer_data: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintMintGroupMemberPointerData {
+    pub group_member_pointer_data: Expr,
+}
+
+#[derive(Debug, Clone)]
+pub struct ConstraintMintCloseAuthority {
+    pub close_authority: Expr,
+}
+
 #[derive(Debug, Clone)]
 pub struct ConstraintTokenAuthority {
     pub auth: Expr,
@@ -891,6 +1039,16 @@ pub struct ConstraintTokenMintGroup {
     pub mint_authority: Option,
     pub freeze_authority: Option,
     pub token_program: Option,
+    pub group_pointer_authority: Option,
+    pub group_pointer_group_address: Option,
+    pub group_member_pointer_authority: Option,
+    pub group_member_pointer_member_address: Option,
+    pub metadata_pointer_authority: Option,
+    pub metadata_pointer_metadata_address: Option,
+    pub close_authority: Option,
+    pub permanent_delegate: Option,
+    pub transfer_hook_authority: Option,
+    pub transfer_hook_program_id: Option,
 }
 
 // Syntaxt context object for preserving metadata about the inner item.
diff --git a/lang/syn/src/parser/accounts/constraints.rs b/lang/syn/src/parser/accounts/constraints.rs
index 151abefda2..89fe224464 100644
--- a/lang/syn/src/parser/accounts/constraints.rs
+++ b/lang/syn/src/parser/accounts/constraints.rs
@@ -1,10 +1,6 @@
 use crate::*;
-use syn::ext::IdentExt;
-use syn::parse::{Error as ParseError, Parse, ParseStream, Result as ParseResult};
-use syn::punctuated::Punctuated;
-use syn::spanned::Spanned;
-use syn::token::Comma;
-use syn::{bracketed, Expr, Ident, Token};
+use syn::parse::{Error as ParseError, Result as ParseResult};
+use syn::{bracketed, Token};
 
 pub fn parse(f: &syn::Field, f_ty: Option<&Ty>) -> ParseResult {
     let mut constraints = ConstraintGroupBuilder::new(f_ty);
@@ -93,6 +89,177 @@ pub fn parse_token(stream: ParseStream) -> ParseResult {
                 _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
             }
         }
+        "extensions" => {
+            stream.parse::()?;
+            stream.parse::()?;
+            let kw = stream.call(Ident::parse_any)?.to_string();
+
+            match kw.as_str() {
+                "group_pointer" => {
+                    stream.parse::()?;
+                    stream.parse::()?;
+                    let kw = stream.call(Ident::parse_any)?.to_string();
+                    stream.parse::()?;
+
+                    let span = ident
+                        .span()
+                        .join(stream.span())
+                        .unwrap_or_else(|| ident.span());
+
+                    match kw.as_str() {
+                        "authority" => {
+                            ConstraintToken::ExtensionGroupPointerAuthority(Context::new(
+                                span,
+                                ConstraintExtensionAuthority {
+                                    authority: stream.parse()?,
+                                },
+                            ))
+                        }
+                        "group_address" => {
+                            ConstraintToken::ExtensionGroupPointerGroupAddress(Context::new(
+                                span,
+                                ConstraintExtensionGroupPointerGroupAddress {
+                                    group_address: stream.parse()?,
+                                },
+                            ))
+                        }
+                        _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
+                    }
+                }
+                "group_member_pointer" => {
+                    stream.parse::()?;
+                    stream.parse::()?;
+                    let kw = stream.call(Ident::parse_any)?.to_string();
+                    stream.parse::()?;
+
+                    let span = ident
+                        .span()
+                        .join(stream.span())
+                        .unwrap_or_else(|| ident.span());
+
+                    match kw.as_str() {
+                        "authority" => {
+                            ConstraintToken::ExtensionGroupMemberPointerAuthority(Context::new(
+                                span,
+                                ConstraintExtensionAuthority {
+                                    authority: stream.parse()?,
+                                },
+                            ))
+                        }
+                        "member_address" => {
+                            ConstraintToken::ExtensionGroupMemberPointerMemberAddress(Context::new(
+                                span,
+                                ConstraintExtensionGroupMemberPointerMemberAddress {
+                                    member_address: stream.parse()?,
+                                },
+                            ))
+                        }
+                        _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
+                    }
+                }
+                "metadata_pointer" => {
+                    stream.parse::()?;
+                    stream.parse::()?;
+                    let kw = stream.call(Ident::parse_any)?.to_string();
+                    stream.parse::()?;
+
+                    let span = ident
+                        .span()
+                        .join(stream.span())
+                        .unwrap_or_else(|| ident.span());
+
+                    match kw.as_str() {
+                        "authority" => {
+                            ConstraintToken::ExtensionMetadataPointerAuthority(Context::new(
+                                span,
+                                ConstraintExtensionAuthority {
+                                    authority: stream.parse()?,
+                                },
+                            ))
+                        }
+                        "metadata_address" => {
+                            ConstraintToken::ExtensionMetadataPointerMetadataAddress(Context::new(
+                                span,
+                                ConstraintExtensionMetadataPointerMetadataAddress {
+                                    metadata_address: stream.parse()?,
+                                },
+                            ))
+                        }
+                        _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
+                    }
+                }
+                "close_authority" => {
+                    stream.parse::()?;
+                    stream.parse::()?;
+                    let kw = stream.call(Ident::parse_any)?.to_string();
+                    stream.parse::()?;
+
+                    let span = ident
+                        .span()
+                        .join(stream.span())
+                        .unwrap_or_else(|| ident.span());
+
+                    match kw.as_str() {
+                        "authority" => ConstraintToken::ExtensionCloseAuthority(Context::new(
+                            span,
+                            ConstraintExtensionAuthority {
+                                authority: stream.parse()?,
+                            },
+                        )),
+                        _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
+                    }
+                }
+                "permanent_delegate" => {
+                    stream.parse::()?;
+                    stream.parse::()?;
+                    let kw = stream.call(Ident::parse_any)?.to_string();
+                    stream.parse::()?;
+
+                    let span = ident
+                        .span()
+                        .join(stream.span())
+                        .unwrap_or_else(|| ident.span());
+
+                    match kw.as_str() {
+                        "delegate" => ConstraintToken::ExtensionPermanentDelegate(Context::new(
+                            span,
+                            ConstraintExtensionPermanentDelegate {
+                                permanent_delegate: stream.parse()?,
+                            },
+                        )),
+                        _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
+                    }
+                }
+                "transfer_hook" => {
+                    stream.parse::()?;
+                    stream.parse::()?;
+                    let kw = stream.call(Ident::parse_any)?.to_string();
+                    stream.parse::()?;
+
+                    let span = ident
+                        .span()
+                        .join(stream.span())
+                        .unwrap_or_else(|| ident.span());
+
+                    match kw.as_str() {
+                        "authority" => ConstraintToken::ExtensionTokenHookAuthority(Context::new(
+                            span,
+                            ConstraintExtensionAuthority {
+                                authority: stream.parse()?,
+                            },
+                        )),
+                        "program_id" => ConstraintToken::ExtensionTokenHookProgramId(Context::new(
+                            span,
+                            ConstraintExtensionTokenHookProgramId {
+                                program_id: stream.parse()?,
+                            },
+                        )),
+                        _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
+                    }
+                }
+                _ => return Err(ParseError::new(ident.span(), "Invalid attribute")),
+            }
+        }
         "token" => {
             stream.parse::()?;
             stream.parse::()?;
@@ -358,6 +525,19 @@ pub struct ConstraintGroupBuilder<'ty> {
     pub mint_freeze_authority: Option>,
     pub mint_decimals: Option>,
     pub mint_token_program: Option>,
+    pub extension_group_pointer_authority: Option>,
+    pub extension_group_pointer_group_address:
+        Option>,
+    pub extension_group_member_pointer_authority: Option>,
+    pub extension_group_member_pointer_member_address:
+        Option>,
+    pub extension_metadata_pointer_authority: Option>,
+    pub extension_metadata_pointer_metadata_address:
+        Option>,
+    pub extension_close_authority: Option>,
+    pub extension_transfer_hook_authority: Option>,
+    pub extension_transfer_hook_program_id: Option>,
+    pub extension_permanent_delegate: Option>,
     pub bump: Option>,
     pub program_seed: Option>,
     pub realloc: Option>,
@@ -393,6 +573,16 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             mint_freeze_authority: None,
             mint_decimals: None,
             mint_token_program: None,
+            extension_group_pointer_authority: None,
+            extension_group_pointer_group_address: None,
+            extension_group_member_pointer_authority: None,
+            extension_group_member_pointer_member_address: None,
+            extension_metadata_pointer_authority: None,
+            extension_metadata_pointer_metadata_address: None,
+            extension_close_authority: None,
+            extension_transfer_hook_authority: None,
+            extension_transfer_hook_program_id: None,
+            extension_permanent_delegate: None,
             bump: None,
             program_seed: None,
             realloc: None,
@@ -595,6 +785,16 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             mint_freeze_authority,
             mint_decimals,
             mint_token_program,
+            extension_group_pointer_authority,
+            extension_group_pointer_group_address,
+            extension_group_member_pointer_authority,
+            extension_group_member_pointer_member_address,
+            extension_metadata_pointer_authority,
+            extension_metadata_pointer_metadata_address,
+            extension_close_authority,
+            extension_transfer_hook_authority,
+            extension_transfer_hook_program_id,
+            extension_permanent_delegate,
             bump,
             program_seed,
             realloc,
@@ -684,8 +884,33 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             &mint_authority,
             &mint_freeze_authority,
             &mint_token_program,
+            &extension_group_pointer_authority,
+            &extension_group_pointer_group_address,
+            &extension_group_member_pointer_authority,
+            &extension_group_member_pointer_member_address,
+            &extension_metadata_pointer_authority,
+            &extension_metadata_pointer_metadata_address,
+            &extension_close_authority,
+            &extension_transfer_hook_authority,
+            &extension_transfer_hook_program_id,
+            &extension_permanent_delegate,
         ) {
-            (None, None, None, None) => None,
+            (
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+                None,
+            ) => None,
             _ => Some(ConstraintTokenMintGroup {
                 decimals: mint_decimals
                     .as_ref()
@@ -699,6 +924,37 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                 token_program: mint_token_program
                     .as_ref()
                     .map(|a| a.clone().into_inner().token_program),
+                // extensions
+                group_pointer_authority: extension_group_pointer_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().authority),
+                group_pointer_group_address: extension_group_pointer_group_address
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().group_address),
+                group_member_pointer_authority: extension_group_member_pointer_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().authority),
+                group_member_pointer_member_address: extension_group_member_pointer_member_address
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().member_address),
+                metadata_pointer_authority: extension_metadata_pointer_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().authority),
+                metadata_pointer_metadata_address: extension_metadata_pointer_metadata_address
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().metadata_address),
+                close_authority: extension_close_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().authority),
+                permanent_delegate: extension_permanent_delegate
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().permanent_delegate),
+                transfer_hook_authority: extension_transfer_hook_authority
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().authority),
+                transfer_hook_program_id: extension_transfer_hook_program_id
+                    .as_ref()
+                    .map(|a| a.clone().into_inner().program_id),
             }),
         };
 
@@ -738,6 +994,17 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
                         },
                         freeze_authority: mint_freeze_authority.map(|fa| fa.into_inner().mint_freeze_auth),
                         token_program: mint_token_program.map(|tp| tp.into_inner().token_program),
+                        // extensions
+                        group_pointer_authority: extension_group_pointer_authority.map(|gpa| gpa.into_inner().authority),
+                        group_pointer_group_address: extension_group_pointer_group_address.map(|gpga| gpga.into_inner().group_address),
+                        group_member_pointer_authority: extension_group_member_pointer_authority.map(|gmpa| gmpa.into_inner().authority),
+                        group_member_pointer_member_address: extension_group_member_pointer_member_address.map(|gmpma| gmpma.into_inner().member_address),
+                        metadata_pointer_authority: extension_metadata_pointer_authority.map(|mpa| mpa.into_inner().authority),
+                        metadata_pointer_metadata_address: extension_metadata_pointer_metadata_address.map(|mpma| mpma.into_inner().metadata_address),
+                        close_authority: extension_close_authority.map(|ca| ca.into_inner().authority),
+                        permanent_delegate: extension_permanent_delegate.map(|pd| pd.into_inner().permanent_delegate),
+                        transfer_hook_authority: extension_transfer_hook_authority.map(|tha| tha.into_inner().authority),
+                        transfer_hook_program_id: extension_transfer_hook_program_id.map(|thpid| thpid.into_inner().program_id),
                     }
                 } else {
                     InitKind::Program {
@@ -800,6 +1067,32 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
             ConstraintToken::Realloc(c) => self.add_realloc(c),
             ConstraintToken::ReallocPayer(c) => self.add_realloc_payer(c),
             ConstraintToken::ReallocZero(c) => self.add_realloc_zero(c),
+            ConstraintToken::ExtensionGroupPointerAuthority(c) => {
+                self.add_extension_group_pointer_authority(c)
+            }
+            ConstraintToken::ExtensionGroupPointerGroupAddress(c) => {
+                self.add_extension_group_pointer_group_address(c)
+            }
+            ConstraintToken::ExtensionGroupMemberPointerAuthority(c) => {
+                self.add_extension_group_member_pointer_authority(c)
+            }
+            ConstraintToken::ExtensionGroupMemberPointerMemberAddress(c) => {
+                self.add_extension_group_member_pointer_member_address(c)
+            }
+            ConstraintToken::ExtensionMetadataPointerAuthority(c) => {
+                self.add_extension_metadata_pointer_authority(c)
+            }
+            ConstraintToken::ExtensionMetadataPointerMetadataAddress(c) => {
+                self.add_extension_metadata_pointer_metadata_address(c)
+            }
+            ConstraintToken::ExtensionCloseAuthority(c) => self.add_extension_close_authority(c),
+            ConstraintToken::ExtensionTokenHookAuthority(c) => self.add_extension_authority(c),
+            ConstraintToken::ExtensionTokenHookProgramId(c) => {
+                self.add_extension_transfer_hook_program_id(c)
+            }
+            ConstraintToken::ExtensionPermanentDelegate(c) => {
+                self.add_extension_permanent_delegate(c)
+            }
         }
     }
 
@@ -881,6 +1174,15 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
         if self.init.is_some() {
             return Err(ParseError::new(c.span(), "init already provided"));
         }
+
+        // Require a known account type that implements the `Discriminator` trait so that we can
+        // get the discriminator length dynamically
+        if !matches!(&self.f_ty, Some(Ty::Account(_) | Ty::AccountLoader(_))) {
+            return Err(ParseError::new(
+                c.span(),
+                "`zero` constraint requires the type to implement the `Discriminator` trait",
+            ));
+        }
         self.zeroed.replace(c);
         Ok(())
     }
@@ -1225,4 +1527,147 @@ impl<'ty> ConstraintGroupBuilder<'ty> {
         self.space.replace(c);
         Ok(())
     }
+
+    // extensions
+
+    fn add_extension_group_pointer_authority(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_group_pointer_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension group pointer authority already provided",
+            ));
+        }
+        self.extension_group_pointer_authority.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_group_pointer_group_address(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_group_pointer_group_address.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension group pointer group address already provided",
+            ));
+        }
+        self.extension_group_pointer_group_address.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_group_member_pointer_authority(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_group_member_pointer_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension group member pointer authority already provided",
+            ));
+        }
+        self.extension_group_member_pointer_authority.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_group_member_pointer_member_address(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_group_member_pointer_member_address.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension group member pointer member address already provided",
+            ));
+        }
+        self.extension_group_member_pointer_member_address
+            .replace(c);
+        Ok(())
+    }
+
+    fn add_extension_metadata_pointer_authority(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_metadata_pointer_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension metadata pointer authority already provided",
+            ));
+        }
+        self.extension_metadata_pointer_authority.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_metadata_pointer_metadata_address(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_metadata_pointer_metadata_address.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension metadata pointer metadata address already provided",
+            ));
+        }
+        self.extension_metadata_pointer_metadata_address.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_close_authority(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_close_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension close authority already provided",
+            ));
+        }
+        self.extension_close_authority.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_authority(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_transfer_hook_authority.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension transfer hook authority already provided",
+            ));
+        }
+        self.extension_transfer_hook_authority.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_transfer_hook_program_id(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_transfer_hook_program_id.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension transfer hook program id already provided",
+            ));
+        }
+        self.extension_transfer_hook_program_id.replace(c);
+        Ok(())
+    }
+
+    fn add_extension_permanent_delegate(
+        &mut self,
+        c: Context,
+    ) -> ParseResult<()> {
+        if self.extension_permanent_delegate.is_some() {
+            return Err(ParseError::new(
+                c.span(),
+                "extension permanent delegate already provided",
+            ));
+        }
+        self.extension_permanent_delegate.replace(c);
+        Ok(())
+    }
 }
diff --git a/lang/syn/src/parser/accounts/mod.rs b/lang/syn/src/parser/accounts/mod.rs
index 1da0e52126..f2958f8bcd 100644
--- a/lang/syn/src/parser/accounts/mod.rs
+++ b/lang/syn/src/parser/accounts/mod.rs
@@ -5,10 +5,6 @@ pub mod event_cpi;
 use crate::parser::docs;
 use crate::*;
 use syn::parse::{Error as ParseError, Result as ParseResult};
-use syn::punctuated::Punctuated;
-use syn::spanned::Spanned;
-use syn::token::Comma;
-use syn::Expr;
 use syn::Path;
 
 pub fn parse(accounts_struct: &syn::ItemStruct) -> ParseResult {
diff --git a/lang/syn/src/parser/context.rs b/lang/syn/src/parser/context.rs
index 502c71a429..ea0e4ee077 100644
--- a/lang/syn/src/parser/context.rs
+++ b/lang/syn/src/parser/context.rs
@@ -1,4 +1,4 @@
-use anyhow::anyhow;
+use anyhow::{anyhow, Result};
 use std::collections::BTreeMap;
 use std::path::{Path, PathBuf};
 use syn::parse::{Error as ParseError, Result as ParseResult};
@@ -12,6 +12,12 @@ pub struct CrateContext {
 }
 
 impl CrateContext {
+    pub fn parse(root: impl AsRef) -> Result {
+        Ok(CrateContext {
+            modules: ParsedModule::parse_recursive(root.as_ref())?,
+        })
+    }
+
     pub fn consts(&self) -> impl Iterator {
         self.modules.iter().flat_map(|(_, ctx)| ctx.consts())
     }
@@ -42,16 +48,10 @@ impl CrateContext {
         }
     }
 
-    pub fn parse(root: impl AsRef) -> Result {
-        Ok(CrateContext {
-            modules: ParsedModule::parse_recursive(root.as_ref())?,
-        })
-    }
-
     // Perform Anchor safety checks on the parsed create
-    pub fn safety_checks(&self) -> Result<(), anyhow::Error> {
+    pub fn safety_checks(&self) -> Result<()> {
         // Check all structs for unsafe field types, i.e. AccountInfo and UncheckedAccount.
-        for (_, ctx) in self.modules.iter() {
+        for ctx in self.modules.values() {
             for unsafe_field in ctx.unsafe_struct_fields() {
                 // Check if unsafe field type has been documented with a /// SAFETY: doc string.
                 let is_documented = unsafe_field.attrs.iter().any(|attr| {
@@ -104,8 +104,15 @@ struct ParsedModule {
     items: Vec,
 }
 
+struct UnparsedModule {
+    file: PathBuf,
+    path: String,
+    name: String,
+    item: syn::ItemMod,
+}
+
 impl ParsedModule {
-    fn parse_recursive(root: &Path) -> Result, anyhow::Error> {
+    fn parse_recursive(root: &Path) -> Result> {
         let mut modules = BTreeMap::new();
 
         let root_content = std::fs::read_to_string(root)?;
@@ -117,35 +124,13 @@ impl ParsedModule {
             root_file.items,
         );
 
-        struct UnparsedModule {
-            file: PathBuf,
-            path: String,
-            name: String,
-            item: syn::ItemMod,
-        }
-
-        let mut unparsed = root_mod
-            .submodules()
-            .map(|item| UnparsedModule {
-                file: root_mod.file.clone(),
-                path: root_mod.path.clone(),
-                name: item.ident.to_string(),
-                item: item.clone(),
-            })
-            .collect::>();
-
+        let mut unparsed = root_mod.unparsed_submodules();
         while let Some(to_parse) = unparsed.pop() {
             let path = format!("{}::{}", to_parse.path, to_parse.name);
-            let name = to_parse.name;
             let module = Self::from_item_mod(&to_parse.file, &path, to_parse.item)?;
 
-            unparsed.extend(module.submodules().map(|item| UnparsedModule {
-                item: item.clone(),
-                file: module.file.clone(),
-                path: module.path.clone(),
-                name: item.ident.to_string(),
-            }));
-            modules.insert(format!("{}{}", module.path.clone(), name.clone()), module);
+            unparsed.extend(module.unparsed_submodules());
+            modules.insert(format!("{}{}", module.path, to_parse.name), module);
         }
 
         modules.insert(root_mod.name.clone(), root_mod);
@@ -209,6 +194,17 @@ impl ParsedModule {
         }
     }
 
+    fn unparsed_submodules(&self) -> Vec {
+        self.submodules()
+            .map(|item| UnparsedModule {
+                file: self.file.clone(),
+                path: self.path.clone(),
+                name: item.ident.to_string(),
+                item: item.clone(),
+            })
+            .collect()
+    }
+
     fn submodules(&self) -> impl Iterator {
         self.items.iter().filter_map(|i| match i {
             syn::Item::Mod(item) => Some(item),
@@ -259,6 +255,13 @@ impl ParsedModule {
         })
     }
 
+    fn type_aliases(&self) -> impl Iterator {
+        self.items.iter().filter_map(|i| match i {
+            syn::Item::Type(item) => Some(item),
+            _ => None,
+        })
+    }
+
     fn consts(&self) -> impl Iterator {
         self.items.iter().filter_map(|i| match i {
             syn::Item::Const(item) => Some(item),
@@ -297,11 +300,4 @@ impl ParsedModule {
             })
             .flatten()
     }
-
-    fn type_aliases(&self) -> impl Iterator {
-        self.items.iter().filter_map(|i| match i {
-            syn::Item::Type(item) => Some(item),
-            _ => None,
-        })
-    }
 }
diff --git a/lang/syn/src/parser/mod.rs b/lang/syn/src/parser/mod.rs
index b586eaf819..6106d1175f 100644
--- a/lang/syn/src/parser/mod.rs
+++ b/lang/syn/src/parser/mod.rs
@@ -6,7 +6,5 @@ pub mod program;
 pub mod spl_interface;
 
 pub fn tts_to_string(item: T) -> String {
-    let mut tts = proc_macro2::TokenStream::new();
-    item.to_tokens(&mut tts);
-    tts.to_string()
+    item.to_token_stream().to_string()
 }
diff --git a/lang/syn/src/parser/program/instructions.rs b/lang/syn/src/parser/program/instructions.rs
index b90ac8e1ee..37da23fb78 100644
--- a/lang/syn/src/parser/program/instructions.rs
+++ b/lang/syn/src/parser/program/instructions.rs
@@ -1,7 +1,7 @@
 use crate::parser::docs;
 use crate::parser::program::ctx_accounts_ident;
 use crate::parser::spl_interface;
-use crate::{FallbackFn, Ix, IxArg, IxReturn};
+use crate::{FallbackFn, Ix, IxArg, IxReturn, Overrides};
 use syn::parse::{Error as ParseError, Result as ParseResult};
 use syn::spanned::Spanned;
 
@@ -25,6 +25,7 @@ pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec, Option ParseResult<(Vec, Option>>()?;
@@ -71,6 +73,18 @@ pub fn parse(program_mod: &syn::ItemMod) -> ParseResult<(Vec, Option ParseResult> {
+    attrs
+        .iter()
+        .find(|attr| match attr.path.segments.last() {
+            Some(seg) => seg.ident == "instruction",
+            _ => false,
+        })
+        .map(|attr| attr.parse_args())
+        .transpose()
+}
+
 pub fn parse_args(method: &syn::ItemFn) -> ParseResult<(IxArg, Vec)> {
     let mut args: Vec = method
         .sig
diff --git a/lang/tests/macros.rs b/lang/tests/macros.rs
new file mode 100644
index 0000000000..894ecf0e31
--- /dev/null
+++ b/lang/tests/macros.rs
@@ -0,0 +1,28 @@
+use core::str::FromStr;
+
+use anchor_lang::solana_program::pubkey::Pubkey;
+
+mod id {
+    anchor_lang::declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
+}
+
+#[test]
+fn test_declare_id() {
+    let good = Pubkey::from_str("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS").unwrap();
+    let bad = Pubkey::from_str("A7yUYJNEVYRLE4QWsnc9rE9JRsm7DfqEmLscQVwkffAk").unwrap();
+    assert_eq!(good, id::ID);
+    assert_eq!(good, id::id());
+    assert!(id::check_id(&good));
+    assert!(!id::check_id(&bad));
+}
+
+mod pk {
+    pub(super) const PUBKEY: anchor_lang::solana_program::pubkey::Pubkey =
+        anchor_lang::pubkey!("A7yUYJNEVYRLE4QWsnc9rE9JRsm7DfqEmLscQVwkffAk");
+}
+
+#[test]
+fn test_pubkey() {
+    let want = Pubkey::from_str("A7yUYJNEVYRLE4QWsnc9rE9JRsm7DfqEmLscQVwkffAk");
+    assert_eq!(want.unwrap(), pk::PUBKEY);
+}
diff --git a/lang/tests/serialization.rs b/lang/tests/serialization.rs
index 9a93e4f4e2..23e86c905c 100644
--- a/lang/tests/serialization.rs
+++ b/lang/tests/serialization.rs
@@ -9,7 +9,7 @@ fn test_instruction_data() {
         bar: String,
     }
     impl Discriminator for MyType {
-        const DISCRIMINATOR: [u8; 8] = [1, 2, 3, 4, 5, 6, 7, 8];
+        const DISCRIMINATOR: &'static [u8] = &[1, 2, 3, 4, 5, 6, 7, 8];
     }
     impl InstructionData for MyType {}
 
@@ -25,7 +25,7 @@ fn test_instruction_data() {
     instance.write_to(&mut write);
 
     // Check that one is correct and that they are equal (implies other is correct)
-    let correct_disc = data[0..8] == MyType::DISCRIMINATOR;
+    let correct_disc = &data[0..8] == MyType::DISCRIMINATOR;
     let correct_data = MyType::deserialize(&mut &data[8..]).is_ok_and(|result| result == instance);
     let correct_serialization = correct_disc & correct_data;
     assert!(correct_serialization, "serialization was not correct");
diff --git a/lang/tests/space.rs b/lang/tests/space.rs
index 74c03321d2..571bb78b49 100644
--- a/lang/tests/space.rs
+++ b/lang/tests/space.rs
@@ -43,7 +43,7 @@ pub struct TestBasicVarAccount {
 
 #[account]
 #[derive(InitSpace)]
-pub struct TestComplexeVarAccount {
+pub struct TestComplexVarAccount {
     pub test_key: Pubkey,
     #[max_len(10)]
     pub test_vec: Vec,
@@ -97,6 +97,18 @@ pub struct TestConst {
     pub test_array: [u8; MAX_LEN as usize],
 }
 
+#[derive(InitSpace)]
+pub struct TestUnnamedStruct(
+    pub u8,
+    #[max_len(4)] pub Vec,
+    #[max_len(10)] pub String,
+    pub ChildStruct,
+    pub TestBasicEnum,
+);
+
+#[derive(InitSpace)]
+pub struct TestUnitStruct;
+
 #[test]
 fn test_empty_struct() {
     assert_eq!(TestEmptyAccount::INIT_SPACE, 0);
@@ -108,9 +120,9 @@ fn test_basic_struct() {
 }
 
 #[test]
-fn test_complexe_struct() {
+fn test_complex_struct() {
     assert_eq!(
-        TestComplexeVarAccount::INIT_SPACE,
+        TestComplexVarAccount::INIT_SPACE,
         32 + 4 + 10 + (4 + 10) + 3
     )
 }
@@ -147,3 +159,16 @@ fn test_full_path() {
 fn test_const() {
     assert_eq!(TestConst::INIT_SPACE, (4 + 10) + 10)
 }
+
+#[test]
+fn test_unnamed_struct() {
+    assert_eq!(
+        TestUnnamedStruct::INIT_SPACE,
+        1 + 4 + 4 * 4 + 4 + 10 + ChildStruct::INIT_SPACE + TestBasicEnum::INIT_SPACE
+    )
+}
+
+#[test]
+fn test_unit_struct() {
+    assert_eq!(TestUnitStruct::INIT_SPACE, 0)
+}
diff --git a/setup-tests.sh b/setup-tests.sh
index de485982de..6907314e04 100755
--- a/setup-tests.sh
+++ b/setup-tests.sh
@@ -1,12 +1,13 @@
 #!/bin/bash
 
 active_version=$(solana -V | awk '{print $2}')
-if [ "$active_version" != "1.17.0" ]; then
-  solana-install init 1.17.0
+if [ "$active_version" != "1.18.17" ]; then
+  solana-install init 1.18.17
 fi
 
 git submodule update --init --recursive --depth 1
 cd ts/packages/borsh && yarn --frozen-lockfile && yarn build && yarn link --force && cd ../../../
+cd ts/packages/anchor-errors && yarn --frozen-lockfile && yarn build && yarn link --force && cd ../../../
 cd ts/packages/anchor && yarn --frozen-lockfile && yarn build:node && yarn link && cd ../../../
 cd ts/packages/spl-associated-token-account && yarn --frozen-lockfile && yarn build:node && yarn link && cd ../../../
 cd ts/packages/spl-token && yarn --frozen-lockfile && yarn build:node && yarn link && cd ../../../
diff --git a/spl/Cargo.toml b/spl/Cargo.toml
index 0e80cd6454..a6c7802dca 100644
--- a/spl/Cargo.toml
+++ b/spl/Cargo.toml
@@ -1,8 +1,7 @@
 [package]
 name = "anchor-spl"
-version = "0.29.0"
+version = "0.30.1"
 authors = ["Anchor Maintainers "]
-rust-version = "1.60"
 edition = "2021"
 license = "Apache-2.0"
 description = "CPI clients for SPL programs"
@@ -12,7 +11,7 @@ all-features = true
 rustdoc-args = ["--cfg", "docsrs"]
 
 [features]
-default = ["associated_token", "mint", "token", "token_2022"]
+default = ["associated_token", "mint", "token", "token_2022", "token_2022_extensions"]
 associated_token = ["spl-associated-token-account"]
 dex = ["serum_dex"]
 devnet = []
@@ -24,18 +23,17 @@ mint = []
 stake = ["borsh"]
 token = ["spl-token"]
 token_2022 = ["spl-token-2022"]
+token_2022_extensions = ["spl-token-2022", "spl-token-group-interface", "spl-token-metadata-interface", "spl-pod"]
 
 [dependencies]
-anchor-lang = { path = "../lang", version = "0.29.0", features = ["derive"] }
+anchor-lang = { path = "../lang", version = "0.30.1", features = ["derive"] }
 borsh = { version = ">=0.9, <0.11", optional = true }
-mpl-token-metadata = { version = "3.1.0", optional = true }
+mpl-token-metadata = { version = "4", optional = true }
 serum_dex = { git = "https://github.com/openbook-dex/program/", rev = "1be91f2", version = "0.4.0", features = ["no-entrypoint"], optional = true }
-solana-program = ">=1.16, <1.18"
-spl-associated-token-account = { version = "2.2", features = ["no-entrypoint"], optional = true }
+spl-associated-token-account = { version = "3", features = ["no-entrypoint"], optional = true }
 spl-memo = { version = "4", features = ["no-entrypoint"], optional = true }
 spl-token = { version = "4", features = ["no-entrypoint"], optional = true }
-spl-token-2022 = { version = "0.9", features = ["no-entrypoint"], optional = true }
-
-# TODO: Remove after https://github.com/coral-xyz/anchor/pull/2795 is merged.
-# `toml_edit 0.21.1` has MSRV of `1.69.0` which is above `1.68.0` that comes from `solana-cli 1.17`.
-toml_edit = "=0.21.0"
+spl-token-2022 = { version = "3", features = ["no-entrypoint"], optional = true }
+spl-token-group-interface = { version = "0.2.3", optional = true }
+spl-token-metadata-interface = { version = "0.3.3", optional = true }
+spl-pod = { version = "0.2.2", optional = true }
diff --git a/spl/src/associated_token.rs b/spl/src/associated_token.rs
index 51ff96fea3..5b5036677c 100644
--- a/spl/src/associated_token.rs
+++ b/spl/src/associated_token.rs
@@ -3,6 +3,7 @@ use anchor_lang::solana_program::pubkey::Pubkey;
 use anchor_lang::Result;
 use anchor_lang::{context::CpiContext, Accounts};
 
+pub use spl_associated_token_account;
 pub use spl_associated_token_account::{
     get_associated_token_address, get_associated_token_address_with_program_id, ID,
 };
@@ -14,7 +15,7 @@ pub fn create<'info>(ctx: CpiContext<'_, '_, '_, 'info, Create<'info>>) -> Resul
         ctx.accounts.mint.key,
         ctx.accounts.token_program.key,
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.payer,
@@ -38,7 +39,7 @@ pub fn create_idempotent<'info>(
         ctx.accounts.mint.key,
         ctx.accounts.token_program.key,
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.payer,
diff --git a/spl/src/dex.rs b/spl/src/dex.rs
index 7a1cc990db..0d1df95086 100644
--- a/spl/src/dex.rs
+++ b/spl/src/dex.rs
@@ -9,10 +9,10 @@ use std::num::NonZeroU64;
 pub use serum_dex;
 
 #[cfg(not(feature = "devnet"))]
-anchor_lang::solana_program::declare_id!("srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX");
+anchor_lang::declare_id!("srmqPvymJeFKQ4zGQed1GFppgkRHL9kaELCbyksJtPX");
 
 #[cfg(feature = "devnet")]
-anchor_lang::solana_program::declare_id!("EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj");
+anchor_lang::declare_id!("EoTcMgcDRTJVZDMZWBoU6rhYHZfkNTVEAfz3uUJRcYGj");
 
 #[allow(clippy::too_many_arguments)]
 pub fn new_order_v3<'info>(
@@ -52,7 +52,7 @@ pub fn new_order_v3<'info>(
         max_native_pc_qty_including_fees,
     )
     .map_err(|pe| ProgramError::from(pe))?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -77,7 +77,7 @@ pub fn cancel_order_v2<'info>(
         order_id,
     )
     .map_err(|pe| ProgramError::from(pe))?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -101,7 +101,7 @@ pub fn settle_funds<'info>(ctx: CpiContext<'_, '_, '_, 'info, SettleFunds<'info>
         ctx.accounts.vault_signer.key,
     )
     .map_err(|pe| ProgramError::from(pe))?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -120,7 +120,7 @@ pub fn init_open_orders<'info>(
         ctx.remaining_accounts.first().map(|acc| acc.key),
     )
     .map_err(|pe| ProgramError::from(pe))?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -139,7 +139,7 @@ pub fn close_open_orders<'info>(
         ctx.accounts.market.key,
     )
     .map_err(|pe| ProgramError::from(pe))?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -158,7 +158,7 @@ pub fn sweep_fees<'info>(ctx: CpiContext<'_, '_, '_, 'info, SweepFees<'info>>) -
         ctx.accounts.token_program.key,
     )
     .map_err(|pe| ProgramError::from(pe))?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -194,7 +194,7 @@ pub fn initialize_market<'info>(
         pc_dust_threshold,
     )
     .map_err(|pe| ProgramError::from(pe))?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
diff --git a/spl/src/governance.rs b/spl/src/governance.rs
index 351351529d..91676f91fb 100644
--- a/spl/src/governance.rs
+++ b/spl/src/governance.rs
@@ -12,7 +12,7 @@ macro_rules! vote_weight_record {
                 let vwr: spl_governance_addin_api::voter_weight::VoterWeightRecord =
                     anchor_lang::AnchorDeserialize::deserialize(&mut data)
                         .map_err(|_| anchor_lang::error::ErrorCode::AccountDidNotDeserialize)?;
-                if !solana_program::program_pack::IsInitialized::is_initialized(&vwr) {
+                if !anchor_lang::solana_program::program_pack::IsInitialized::is_initialized(&vwr) {
                     return Err(anchor_lang::error::ErrorCode::AccountDidNotSerialize.into());
                 }
                 Ok(VoterWeightRecord(vwr))
@@ -57,5 +57,10 @@ macro_rules! vote_weight_record {
 
         #[cfg(feature = "idl-build")]
         impl anchor_lang::IdlBuild for VoterWeightRecord {}
+
+        #[cfg(feature = "idl-build")]
+        impl anchor_lang::Discriminator for VoterWeightRecord {
+            const DISCRIMINATOR: &'static [u8] = &[];
+        }
     };
 }
diff --git a/spl/src/idl_build.rs b/spl/src/idl_build.rs
new file mode 100644
index 0000000000..b7ca0d8c46
--- /dev/null
+++ b/spl/src/idl_build.rs
@@ -0,0 +1,32 @@
+/// Crate a default [`anchor_lang::IdlBuild`] implementation for the given type.
+///
+/// This is used in order to make wrapper accounts of `anchor-spl` work with `idl-build` feature.
+macro_rules! impl_idl_build {
+    ($ty: ty) => {
+        impl anchor_lang::IdlBuild for $ty {}
+
+        // This is not used for the IDL generation since default `IdlBuild` impl doesn't include
+        // the type in the IDL but it stil needs to be added in order to make compilation work.
+        //
+        // TODO: Find a better way to handle discriminators of wrapped external accounts.
+        impl anchor_lang::Discriminator for $ty {
+            const DISCRIMINATOR: &'static [u8] = &[];
+        }
+    };
+}
+
+#[cfg(feature = "metadata")]
+impl_idl_build!(crate::metadata::MetadataAccount);
+#[cfg(feature = "metadata")]
+impl_idl_build!(crate::metadata::MasterEditionAccount);
+#[cfg(feature = "metadata")]
+impl_idl_build!(crate::metadata::TokenRecordAccount);
+
+#[cfg(feature = "stake")]
+impl_idl_build!(crate::stake::StakeAccount);
+
+impl_idl_build!(crate::token::Mint);
+impl_idl_build!(crate::token::TokenAccount);
+
+impl_idl_build!(crate::token_interface::Mint);
+impl_idl_build!(crate::token_interface::TokenAccount);
diff --git a/spl/src/lib.rs b/spl/src/lib.rs
index 5e2a01c610..12cca5d128 100644
--- a/spl/src/lib.rs
+++ b/spl/src/lib.rs
@@ -14,6 +14,9 @@ pub mod token;
 #[cfg(feature = "token_2022")]
 pub mod token_2022;
 
+#[cfg(feature = "token_2022_extensions")]
+pub mod token_2022_extensions;
+
 #[cfg(feature = "token_2022")]
 pub mod token_interface;
 
@@ -31,3 +34,6 @@ pub mod metadata;
 
 #[cfg(feature = "memo")]
 pub mod memo;
+
+#[cfg(feature = "idl-build")]
+mod idl_build;
diff --git a/spl/src/memo.rs b/spl/src/memo.rs
index e7030855e0..fceabca7a8 100644
--- a/spl/src/memo.rs
+++ b/spl/src/memo.rs
@@ -13,8 +13,12 @@ pub fn build_memo<'info>(ctx: CpiContext<'_, '_, '_, 'info, BuildMemo>, memo: &[
             .map(|account| account.key)
             .collect::>(),
     );
-    solana_program::program::invoke_signed(&ix, &ctx.remaining_accounts, ctx.signer_seeds)
-        .map_err(Into::into)
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &ctx.remaining_accounts,
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
 }
 
 #[derive(Accounts)]
diff --git a/spl/src/metadata.rs b/spl/src/metadata.rs
index 8be64cff1b..394b08cb8c 100644
--- a/spl/src/metadata.rs
+++ b/spl/src/metadata.rs
@@ -1,9 +1,9 @@
 use anchor_lang::context::CpiContext;
 use anchor_lang::error::ErrorCode;
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::solana_program::sysvar;
 use anchor_lang::{system_program, Accounts, Result, ToAccountInfos};
-use solana_program::account_info::AccountInfo;
-use solana_program::pubkey::Pubkey;
-use solana_program::sysvar;
 use std::ops::Deref;
 
 pub use mpl_token_metadata;
@@ -23,7 +23,7 @@ pub fn approve_collection_authority<'info>(
         update_authority: *ctx.accounts.update_authority.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -48,7 +48,7 @@ pub fn bubblegum_set_collection_size<'info>(
             set_collection_size_args: mpl_token_metadata::types::SetCollectionSizeArgs { size },
         },
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -72,7 +72,7 @@ pub fn burn_edition_nft<'info>(
         spl_token_program: *ctx.accounts.spl_token.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -80,6 +80,21 @@ pub fn burn_edition_nft<'info>(
     .map_err(Into::into)
 }
 
+/// Burn an NFT by closing its token, metadata and edition accounts.
+///
+/// The lamports of the closed accounts will be transferred to the owner.
+///
+/// # Note
+///
+/// This instruction takes an optional `collection_metadata` argument, if this argument is
+/// `Some`, the `ctx` argument should also include the `collection_metadata` account in its
+/// remaining accounts, otherwise the CPI will fail because [`BurnNft`] only includes required
+/// accounts.
+///
+/// ```ignore
+/// CpiContext::new(program, BurnNft { .. })
+///     .with_remaining_accounts(vec![ctx.accounts.collection_metadata]);
+/// ```
 pub fn burn_nft<'info>(
     ctx: CpiContext<'_, '_, '_, 'info, BurnNft<'info>>,
     collection_metadata: Option,
@@ -94,7 +109,7 @@ pub fn burn_nft<'info>(
         token_account: *ctx.accounts.token.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -128,7 +143,7 @@ pub fn create_metadata_accounts_v3<'info>(
             is_mutable,
         },
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -155,7 +170,7 @@ pub fn update_metadata_accounts_v2<'info>(
             is_mutable,
         },
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -181,7 +196,7 @@ pub fn create_master_edition_v3<'info>(
     .instruction(
         mpl_token_metadata::instructions::CreateMasterEditionV3InstructionArgs { max_supply },
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -215,7 +230,7 @@ pub fn mint_new_edition_from_master_edition_via_token<'info>(
                 mpl_token_metadata::types::MintNewEditionFromMasterEditionViaTokenArgs { edition },
         },
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -234,7 +249,7 @@ pub fn revoke_collection_authority<'info>(
         revoke_authority: *ctx.accounts.revoke_authority.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -258,7 +273,7 @@ pub fn set_collection_size<'info>(
             set_collection_size_args: mpl_token_metadata::types::SetCollectionSizeArgs { size },
         },
     );
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -280,7 +295,7 @@ pub fn verify_collection<'info>(
         payer: *ctx.accounts.payer.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -302,7 +317,7 @@ pub fn verify_sized_collection_item<'info>(
         payer: *ctx.accounts.payer.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -325,7 +340,7 @@ pub fn set_and_verify_collection<'info>(
         update_authority: *ctx.accounts.update_authority.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -348,7 +363,7 @@ pub fn set_and_verify_sized_collection_item<'info>(
         update_authority: *ctx.accounts.update_authority.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -367,7 +382,7 @@ pub fn freeze_delegated_account<'info>(
         token_program: *ctx.accounts.token_program.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -386,7 +401,7 @@ pub fn thaw_delegated_account<'info>(
         token_program: *ctx.accounts.token_program.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -403,7 +418,7 @@ pub fn update_primary_sale_happened_via_token<'info>(
         token: *ctx.accounts.token.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -422,7 +437,7 @@ pub fn set_token_standard<'info>(
         update_authority: *ctx.accounts.update_authority.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -436,7 +451,7 @@ pub fn sign_metadata<'info>(ctx: CpiContext<'_, '_, '_, 'info, SignMetadata<'inf
         metadata: *ctx.accounts.metadata.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -452,7 +467,7 @@ pub fn remove_creator_verification<'info>(
         metadata: *ctx.accounts.metadata.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -480,7 +495,7 @@ pub fn utilize<'info>(
         use_authority_record,
     }
     .instruction(mpl_token_metadata::instructions::UtilizeInstructionArgs { number_of_uses });
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -501,7 +516,7 @@ pub fn unverify_collection<'info>(
         metadata: *ctx.accounts.metadata.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -523,7 +538,7 @@ pub fn unverify_sized_collection_item<'info>(
         payer: *ctx.accounts.payer.key,
     }
     .instruction();
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &ToAccountInfos::to_account_infos(&ctx),
         ctx.signer_seeds,
@@ -795,9 +810,6 @@ impl Deref for MetadataAccount {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for MetadataAccount {}
-
 #[derive(Clone, Debug, PartialEq)]
 pub struct MasterEditionAccount(mpl_token_metadata::accounts::MasterEdition);
 
@@ -831,9 +843,6 @@ impl anchor_lang::Owner for MasterEditionAccount {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for MasterEditionAccount {}
-
 #[derive(Clone, Debug, PartialEq)]
 pub struct TokenRecordAccount(mpl_token_metadata::accounts::TokenRecord);
 
@@ -870,9 +879,6 @@ impl Deref for TokenRecordAccount {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for TokenRecordAccount {}
-
 #[derive(Clone)]
 pub struct Metadata;
 
diff --git a/spl/src/mint.rs b/spl/src/mint.rs
index 0444becc8d..adfac9d0b2 100644
--- a/spl/src/mint.rs
+++ b/spl/src/mint.rs
@@ -1,4 +1,4 @@
-use anchor_lang::solana_program::declare_id;
+use anchor_lang::declare_id;
 
 pub use srm::ID as SRM;
 mod srm {
diff --git a/spl/src/stake.rs b/spl/src/stake.rs
index 0bdc6d32ed..c776974da7 100644
--- a/spl/src/stake.rs
+++ b/spl/src/stake.rs
@@ -36,7 +36,7 @@ pub fn authorize<'info>(
     if let Some(c) = custodian {
         account_infos.push(c);
     }
-    solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
+    anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
         .map_err(Into::into)
 }
 
@@ -62,7 +62,7 @@ pub fn withdraw<'info>(
     if let Some(c) = custodian {
         account_infos.push(c);
     }
-    solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
+    anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
         .map_err(Into::into)
 }
 
@@ -70,7 +70,7 @@ pub fn deactivate_stake<'info>(
     ctx: CpiContext<'_, '_, '_, 'info, DeactivateStake<'info>>,
 ) -> Result<()> {
     let ix = stake::instruction::deactivate_stake(ctx.accounts.stake.key, ctx.accounts.staker.key);
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.stake, ctx.accounts.clock, ctx.accounts.staker],
         ctx.signer_seeds,
@@ -156,9 +156,6 @@ impl Deref for StakeAccount {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for StakeAccount {}
-
 #[derive(Clone)]
 pub struct Stake;
 
diff --git a/spl/src/token.rs b/spl/src/token.rs
index 072401f5f5..e91d975621 100644
--- a/spl/src/token.rs
+++ b/spl/src/token.rs
@@ -1,9 +1,8 @@
 use anchor_lang::solana_program::account_info::AccountInfo;
-
 use anchor_lang::solana_program::program_pack::Pack;
 use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
 use anchor_lang::{context::CpiContext, Accounts};
-use anchor_lang::{solana_program, Result};
 use std::ops::Deref;
 
 pub use spl_token;
@@ -21,7 +20,7 @@ pub fn transfer<'info>(
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.from, ctx.accounts.to, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -44,7 +43,7 @@ pub fn transfer_checked<'info>(
         amount,
         decimals,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.from,
@@ -69,7 +68,7 @@ pub fn mint_to<'info>(
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.to, ctx.accounts.mint, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -86,7 +85,7 @@ pub fn burn<'info>(ctx: CpiContext<'_, '_, '_, 'info, Burn<'info>>, amount: u64)
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.from, ctx.accounts.mint, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -106,7 +105,7 @@ pub fn approve<'info>(
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.to,
@@ -133,7 +132,7 @@ pub fn approve_checked<'info>(
         amount,
         decimals,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.to,
@@ -153,7 +152,7 @@ pub fn revoke<'info>(ctx: CpiContext<'_, '_, '_, 'info, Revoke<'info>>) -> Resul
         ctx.accounts.authority.key,
         &[],
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.source, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -170,7 +169,7 @@ pub fn initialize_account<'info>(
         ctx.accounts.mint.key,
         ctx.accounts.authority.key,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.account,
@@ -192,7 +191,7 @@ pub fn initialize_account3<'info>(
         ctx.accounts.mint.key,
         ctx.accounts.authority.key,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.account, ctx.accounts.mint],
         ctx.signer_seeds,
@@ -208,7 +207,7 @@ pub fn close_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, CloseAccount<'inf
         ctx.accounts.authority.key,
         &[], // TODO: support multisig
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.account,
@@ -230,7 +229,7 @@ pub fn freeze_account<'info>(
         ctx.accounts.authority.key,
         &[], // TODO: Support multisig signers.
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.account,
@@ -250,7 +249,7 @@ pub fn thaw_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, ThawAccount<'info>
         ctx.accounts.authority.key,
         &[], // TODO: Support multisig signers.
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.account,
@@ -275,7 +274,7 @@ pub fn initialize_mint<'info>(
         freeze_authority,
         decimals,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.mint, ctx.accounts.rent],
         ctx.signer_seeds,
@@ -296,7 +295,7 @@ pub fn initialize_mint2<'info>(
         freeze_authority,
         decimals,
     )?;
-    solana_program::program::invoke_signed(&ix, &[ctx.accounts.mint], ctx.signer_seeds)
+    anchor_lang::solana_program::program::invoke_signed(&ix, &[ctx.accounts.mint], ctx.signer_seeds)
         .map_err(Into::into)
 }
 
@@ -318,7 +317,7 @@ pub fn set_authority<'info>(
         ctx.accounts.current_authority.key,
         &[], // TODO: Support multisig signers.
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.account_or_mint, ctx.accounts.current_authority],
         ctx.signer_seeds,
@@ -328,8 +327,12 @@ pub fn set_authority<'info>(
 
 pub fn sync_native<'info>(ctx: CpiContext<'_, '_, '_, 'info, SyncNative<'info>>) -> Result<()> {
     let ix = spl_token::instruction::sync_native(&spl_token::ID, ctx.accounts.account.key)?;
-    solana_program::program::invoke_signed(&ix, &[ctx.accounts.account], ctx.signer_seeds)
-        .map_err(Into::into)
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.account],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
 }
 
 #[derive(Accounts)]
@@ -440,7 +443,7 @@ pub struct SyncNative<'info> {
     pub account: AccountInfo<'info>,
 }
 
-#[derive(Clone, Debug, Default, PartialEq)]
+#[derive(Clone, Debug, Default, PartialEq, Copy)]
 pub struct TokenAccount(spl_token::state::Account);
 
 impl TokenAccount {
@@ -471,10 +474,7 @@ impl Deref for TokenAccount {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for TokenAccount {}
-
-#[derive(Clone, Debug, Default, PartialEq)]
+#[derive(Clone, Debug, Default, PartialEq, Copy)]
 pub struct Mint(spl_token::state::Mint);
 
 impl Mint {
@@ -505,9 +505,6 @@ impl Deref for Mint {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for Mint {}
-
 #[derive(Clone)]
 pub struct Token;
 
diff --git a/spl/src/token_2022.rs b/spl/src/token_2022.rs
index 05902f92e8..aa69b3a0cc 100644
--- a/spl/src/token_2022.rs
+++ b/spl/src/token_2022.rs
@@ -1,8 +1,7 @@
 use anchor_lang::solana_program::account_info::AccountInfo;
-
 use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
 use anchor_lang::{context::CpiContext, Accounts};
-use anchor_lang::{solana_program, Result};
 
 pub use spl_token_2022;
 pub use spl_token_2022::ID;
@@ -24,7 +23,7 @@ pub fn transfer<'info>(
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.from, ctx.accounts.to, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -47,7 +46,7 @@ pub fn transfer_checked<'info>(
         amount,
         decimals,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.from,
@@ -72,7 +71,7 @@ pub fn mint_to<'info>(
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.to, ctx.accounts.mint, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -89,7 +88,7 @@ pub fn burn<'info>(ctx: CpiContext<'_, '_, '_, 'info, Burn<'info>>, amount: u64)
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.from, ctx.accounts.mint, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -109,7 +108,7 @@ pub fn approve<'info>(
         &[],
         amount,
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.to,
@@ -128,7 +127,7 @@ pub fn revoke<'info>(ctx: CpiContext<'_, '_, '_, 'info, Revoke<'info>>) -> Resul
         ctx.accounts.authority.key,
         &[],
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.source, ctx.accounts.authority],
         ctx.signer_seeds,
@@ -145,7 +144,7 @@ pub fn initialize_account<'info>(
         ctx.accounts.mint.key,
         ctx.accounts.authority.key,
     )?;
-    solana_program::program::invoke(
+    anchor_lang::solana_program::program::invoke(
         &ix,
         &[
             ctx.accounts.account,
@@ -166,7 +165,7 @@ pub fn initialize_account3<'info>(
         ctx.accounts.mint.key,
         ctx.accounts.authority.key,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.account, ctx.accounts.mint])
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account, ctx.accounts.mint])
         .map_err(Into::into)
 }
 
@@ -178,7 +177,7 @@ pub fn close_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, CloseAccount<'inf
         ctx.accounts.authority.key,
         &[], // TODO: support multisig
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.account,
@@ -200,7 +199,7 @@ pub fn freeze_account<'info>(
         ctx.accounts.authority.key,
         &[], // TODO: Support multisig signers.
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.account,
@@ -220,7 +219,7 @@ pub fn thaw_account<'info>(ctx: CpiContext<'_, '_, '_, 'info, ThawAccount<'info>
         ctx.accounts.authority.key,
         &[], // TODO: Support multisig signers.
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[
             ctx.accounts.account,
@@ -245,7 +244,7 @@ pub fn initialize_mint<'info>(
         freeze_authority,
         decimals,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.mint, ctx.accounts.rent])
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint, ctx.accounts.rent])
         .map_err(Into::into)
 }
 
@@ -262,7 +261,7 @@ pub fn initialize_mint2<'info>(
         freeze_authority,
         decimals,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
 }
 
 pub fn set_authority<'info>(
@@ -283,7 +282,7 @@ pub fn set_authority<'info>(
         ctx.accounts.current_authority.key,
         &[], // TODO: Support multisig signers.
     )?;
-    solana_program::program::invoke_signed(
+    anchor_lang::solana_program::program::invoke_signed(
         &ix,
         &[ctx.accounts.account_or_mint, ctx.accounts.current_authority],
         ctx.signer_seeds,
@@ -293,7 +292,7 @@ pub fn set_authority<'info>(
 
 pub fn sync_native<'info>(ctx: CpiContext<'_, '_, '_, 'info, SyncNative<'info>>) -> Result<()> {
     let ix = spl_token_2022::instruction::sync_native(ctx.program.key, ctx.accounts.account.key)?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
 }
 
 pub fn get_account_data_size<'info>(
@@ -305,15 +304,15 @@ pub fn get_account_data_size<'info>(
         ctx.accounts.mint.key,
         extension_types,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.mint])?;
-    solana_program::program::get_return_data()
-        .ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint])?;
+    anchor_lang::solana_program::program::get_return_data()
+        .ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
         .and_then(|(key, data)| {
             if key != *ctx.program.key {
-                Err(solana_program::program_error::ProgramError::IncorrectProgramId)
+                Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
             } else {
                 data.try_into().map(u64::from_le_bytes).map_err(|_| {
-                    solana_program::program_error::ProgramError::InvalidInstructionData
+                    anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
                 })
             }
         })
@@ -329,7 +328,7 @@ pub fn initialize_mint_close_authority<'info>(
         ctx.accounts.mint.key,
         close_authority,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.mint]).map_err(Into::into)
 }
 
 pub fn initialize_immutable_owner<'info>(
@@ -339,7 +338,7 @@ pub fn initialize_immutable_owner<'info>(
         ctx.program.key,
         ctx.accounts.account.key,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account]).map_err(Into::into)
 }
 
 pub fn amount_to_ui_amount<'info>(
@@ -351,15 +350,15 @@ pub fn amount_to_ui_amount<'info>(
         ctx.accounts.account.key,
         amount,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
-    solana_program::program::get_return_data()
-        .ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
+    anchor_lang::solana_program::program::get_return_data()
+        .ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
         .and_then(|(key, data)| {
             if key != *ctx.program.key {
-                Err(solana_program::program_error::ProgramError::IncorrectProgramId)
+                Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
             } else {
                 String::from_utf8(data).map_err(|_| {
-                    solana_program::program_error::ProgramError::InvalidInstructionData
+                    anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
                 })
             }
         })
@@ -375,15 +374,15 @@ pub fn ui_amount_to_amount<'info>(
         ctx.accounts.account.key,
         ui_amount,
     )?;
-    solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
-    solana_program::program::get_return_data()
-        .ok_or(solana_program::program_error::ProgramError::InvalidInstructionData)
+    anchor_lang::solana_program::program::invoke(&ix, &[ctx.accounts.account])?;
+    anchor_lang::solana_program::program::get_return_data()
+        .ok_or(anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData)
         .and_then(|(key, data)| {
             if key != *ctx.program.key {
-                Err(solana_program::program_error::ProgramError::IncorrectProgramId)
+                Err(anchor_lang::solana_program::program_error::ProgramError::IncorrectProgramId)
             } else {
                 data.try_into().map(u64::from_le_bytes).map_err(|_| {
-                    solana_program::program_error::ProgramError::InvalidInstructionData
+                    anchor_lang::solana_program::program_error::ProgramError::InvalidInstructionData
                 })
             }
         })
@@ -523,7 +522,3 @@ impl anchor_lang::Id for Token2022 {
         ID
     }
 }
-
-// Field parsers to save compute. All account validation is assumed to be done
-// outside of these methods.
-pub use crate::token::accessor;
diff --git a/spl/src/token_2022_extensions/confidential_transfer.rs b/spl/src/token_2022_extensions/confidential_transfer.rs
new file mode 100644
index 0000000000..665ccd2cfc
--- /dev/null
+++ b/spl/src/token_2022_extensions/confidential_transfer.rs
@@ -0,0 +1 @@
+// waiting for labs to merge
diff --git a/spl/src/token_2022_extensions/confidential_transfer_fee.rs b/spl/src/token_2022_extensions/confidential_transfer_fee.rs
new file mode 100644
index 0000000000..665ccd2cfc
--- /dev/null
+++ b/spl/src/token_2022_extensions/confidential_transfer_fee.rs
@@ -0,0 +1 @@
+// waiting for labs to merge
diff --git a/spl/src/token_2022_extensions/cpi_guard.rs b/spl/src/token_2022_extensions/cpi_guard.rs
new file mode 100644
index 0000000000..d0baa12a1e
--- /dev/null
+++ b/spl/src/token_2022_extensions/cpi_guard.rs
@@ -0,0 +1,50 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn cpi_guard_enable<'info>(ctx: CpiContext<'_, '_, '_, 'info, CpiGuard<'info>>) -> Result<()> {
+    let ix = spl_token_2022::extension::cpi_guard::instruction::enable_cpi_guard(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.account.key,
+        ctx.accounts.account.owner,
+        &[],
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.account,
+            ctx.accounts.owner,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+pub fn cpi_guard_disable<'info>(ctx: CpiContext<'_, '_, '_, 'info, CpiGuard<'info>>) -> Result<()> {
+    let ix = spl_token_2022::extension::cpi_guard::instruction::disable_cpi_guard(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.account.key,
+        ctx.accounts.account.owner,
+        &[],
+    )?;
+
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.account,
+            ctx.accounts.owner,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct CpiGuard<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub account: AccountInfo<'info>,
+    pub owner: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/default_account_state.rs b/spl/src/token_2022_extensions/default_account_state.rs
new file mode 100644
index 0000000000..2d722d1536
--- /dev/null
+++ b/spl/src/token_2022_extensions/default_account_state.rs
@@ -0,0 +1,59 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+use spl_token_2022::state::AccountState;
+
+pub fn default_account_state_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, DefaultAccountStateInitialize<'info>>,
+    state: &AccountState,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::default_account_state::instruction::initialize_default_account_state(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        state
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct DefaultAccountStateInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn default_account_state_update<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, DefaultAccountStateUpdate<'info>>,
+    state: &AccountState,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::default_account_state::instruction::update_default_account_state(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.freeze_authority.key,
+        &[],
+        state
+    )?;
+
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.mint,
+            ctx.accounts.freeze_authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct DefaultAccountStateUpdate<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub freeze_authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/group_member_pointer.rs b/spl/src/token_2022_extensions/group_member_pointer.rs
new file mode 100644
index 0000000000..f38df273b6
--- /dev/null
+++ b/spl/src/token_2022_extensions/group_member_pointer.rs
@@ -0,0 +1,59 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn group_member_pointer_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, GroupMemberPointerInitialize<'info>>,
+    authority: Option,
+    member_address: Option,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::group_member_pointer::instruction::initialize(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        authority,
+        member_address,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct GroupMemberPointerInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn group_member_pointer_update<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, GroupMemberPointerUpdate<'info>>,
+    member_address: Option,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::group_member_pointer::instruction::update(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.authority.key,
+        &[],
+        member_address,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.mint,
+            ctx.accounts.authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct GroupMemberPointerUpdate<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/group_pointer.rs b/spl/src/token_2022_extensions/group_pointer.rs
new file mode 100644
index 0000000000..3758fb6c6a
--- /dev/null
+++ b/spl/src/token_2022_extensions/group_pointer.rs
@@ -0,0 +1,55 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn group_pointer_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, GroupPointerInitialize<'info>>,
+    authority: Option,
+    group_address: Option,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::group_pointer::instruction::initialize(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        authority,
+        group_address,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct GroupPointerInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn group_pointer_update<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, GroupPointerUpdate<'info>>,
+    group_address: Option,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::group_pointer::instruction::update(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.authority.key,
+        &[ctx.accounts.authority.key],
+        group_address,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct GroupPointerUpdate<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/immutable_owner.rs b/spl/src/token_2022_extensions/immutable_owner.rs
new file mode 100644
index 0000000000..eb66d8e60b
--- /dev/null
+++ b/spl/src/token_2022_extensions/immutable_owner.rs
@@ -0,0 +1,25 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn immutable_owner_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, ImmutableOwnerInitialize<'info>>,
+) -> Result<()> {
+    let ix = spl_token_2022::instruction::initialize_immutable_owner(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.token_account.key,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.token_account],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct ImmutableOwnerInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub token_account: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/interest_bearing_mint.rs b/spl/src/token_2022_extensions/interest_bearing_mint.rs
new file mode 100644
index 0000000000..214f11a858
--- /dev/null
+++ b/spl/src/token_2022_extensions/interest_bearing_mint.rs
@@ -0,0 +1,59 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn interest_bearing_mint_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, InterestBearingMintInitialize<'info>>,
+    rate_authority: Option,
+    rate: i16,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::interest_bearing_mint::instruction::initialize(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        rate_authority,
+        rate,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct InterestBearingMintInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn interest_bearing_mint_update_rate<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, InterestBearingMintUpdateRate<'info>>,
+    rate: i16,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::interest_bearing_mint::instruction::update_rate(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.rate_authority.key,
+        &[],
+        rate,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.mint,
+            ctx.accounts.rate_authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct InterestBearingMintUpdateRate<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub rate_authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/memo_transfer.rs b/spl/src/token_2022_extensions/memo_transfer.rs
new file mode 100644
index 0000000000..0d0d62fbf1
--- /dev/null
+++ b/spl/src/token_2022_extensions/memo_transfer.rs
@@ -0,0 +1,54 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn memo_transfer_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, MemoTransfer<'info>>,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::memo_transfer::instruction::enable_required_transfer_memos(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.account.key,
+        ctx.accounts.owner.key,
+        &[],
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.account,
+            ctx.accounts.owner,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+pub fn memo_transfer_disable<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, MemoTransfer<'info>>,
+) -> Result<()> {
+    let ix =
+        spl_token_2022::extension::memo_transfer::instruction::disable_required_transfer_memos(
+            ctx.accounts.token_program_id.key,
+            ctx.accounts.account.key,
+            ctx.accounts.owner.key,
+            &[],
+        )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.account,
+            ctx.accounts.owner,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct MemoTransfer<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub account: AccountInfo<'info>,
+    pub owner: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/metadata_pointer.rs b/spl/src/token_2022_extensions/metadata_pointer.rs
new file mode 100644
index 0000000000..fadf2a7525
--- /dev/null
+++ b/spl/src/token_2022_extensions/metadata_pointer.rs
@@ -0,0 +1,29 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn metadata_pointer_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, MetadataPointerInitialize<'info>>,
+    authority: Option,
+    metadata_address: Option,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::metadata_pointer::instruction::initialize(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        authority,
+        metadata_address,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct MetadataPointerInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/mint_close_authority.rs b/spl/src/token_2022_extensions/mint_close_authority.rs
new file mode 100644
index 0000000000..239ed539ac
--- /dev/null
+++ b/spl/src/token_2022_extensions/mint_close_authority.rs
@@ -0,0 +1,27 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn mint_close_authority_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, MintCloseAuthorityInitialize<'info>>,
+    authority: Option<&Pubkey>,
+) -> Result<()> {
+    let ix = spl_token_2022::instruction::initialize_mint_close_authority(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        authority,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct MintCloseAuthorityInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/mod.rs b/spl/src/token_2022_extensions/mod.rs
new file mode 100644
index 0000000000..e0941f9fc6
--- /dev/null
+++ b/spl/src/token_2022_extensions/mod.rs
@@ -0,0 +1,36 @@
+pub mod confidential_transfer;
+pub mod confidential_transfer_fee;
+pub mod cpi_guard;
+pub mod default_account_state;
+pub mod group_member_pointer;
+pub mod group_pointer;
+pub mod immutable_owner;
+pub mod interest_bearing_mint;
+pub mod memo_transfer;
+pub mod metadata_pointer;
+pub mod mint_close_authority;
+pub mod non_transferable;
+pub mod permanent_delegate;
+pub mod token_group;
+pub mod token_metadata;
+pub mod transfer_fee;
+pub mod transfer_hook;
+
+pub use cpi_guard::*;
+pub use default_account_state::*;
+pub use group_member_pointer::*;
+pub use group_pointer::*;
+pub use immutable_owner::*;
+pub use interest_bearing_mint::*;
+pub use memo_transfer::*;
+pub use metadata_pointer::*;
+pub use mint_close_authority::*;
+pub use non_transferable::*;
+pub use permanent_delegate::*;
+pub use token_group::*;
+pub use token_metadata::*;
+pub use transfer_fee::*;
+pub use transfer_hook::*;
+
+pub use spl_pod;
+pub use spl_token_metadata_interface;
diff --git a/spl/src/token_2022_extensions/non_transferable.rs b/spl/src/token_2022_extensions/non_transferable.rs
new file mode 100644
index 0000000000..4f6dda0fe0
--- /dev/null
+++ b/spl/src/token_2022_extensions/non_transferable.rs
@@ -0,0 +1,25 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn non_transferable_mint_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, NonTransferableMintInitialize<'info>>,
+) -> Result<()> {
+    let ix = spl_token_2022::instruction::initialize_non_transferable_mint(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct NonTransferableMintInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/permanent_delegate.rs b/spl/src/token_2022_extensions/permanent_delegate.rs
new file mode 100644
index 0000000000..ee774625d5
--- /dev/null
+++ b/spl/src/token_2022_extensions/permanent_delegate.rs
@@ -0,0 +1,27 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn permanent_delegate_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, PermanentDelegateInitialize<'info>>,
+    permanent_delegate: &Pubkey,
+) -> Result<()> {
+    let ix = spl_token_2022::instruction::initialize_permanent_delegate(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        permanent_delegate,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct PermanentDelegateInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/token_group.rs b/spl/src/token_2022_extensions/token_group.rs
new file mode 100644
index 0000000000..8dff9dea53
--- /dev/null
+++ b/spl/src/token_2022_extensions/token_group.rs
@@ -0,0 +1,74 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn token_group_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TokenGroupInitialize<'info>>,
+    update_authority: Option,
+    max_size: u32,
+) -> Result<()> {
+    let ix = spl_token_group_interface::instruction::initialize_group(
+        ctx.accounts.program_id.key,
+        ctx.accounts.group.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.mint_authority.key,
+        update_authority,
+        max_size,
+    );
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.program_id,
+            ctx.accounts.group,
+            ctx.accounts.mint,
+            ctx.accounts.mint_authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TokenGroupInitialize<'info> {
+    pub program_id: AccountInfo<'info>,
+    pub group: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub mint_authority: AccountInfo<'info>,
+}
+
+pub fn token_member_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TokenMemberInitialize<'info>>,
+) -> Result<()> {
+    let ix = spl_token_group_interface::instruction::initialize_member(
+        ctx.accounts.program_id.key,
+        ctx.accounts.member.key,
+        ctx.accounts.member_mint.key,
+        ctx.accounts.member_mint_authority.key,
+        ctx.accounts.group.key,
+        ctx.accounts.group_update_authority.key,
+    );
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.program_id,
+            ctx.accounts.member,
+            ctx.accounts.member_mint,
+            ctx.accounts.member_mint_authority,
+            ctx.accounts.group,
+            ctx.accounts.group_update_authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TokenMemberInitialize<'info> {
+    pub program_id: AccountInfo<'info>,
+    pub member: AccountInfo<'info>,
+    pub member_mint: AccountInfo<'info>,
+    pub member_mint_authority: AccountInfo<'info>,
+    pub group: AccountInfo<'info>,
+    pub group_update_authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/token_metadata.rs b/spl/src/token_2022_extensions/token_metadata.rs
new file mode 100644
index 0000000000..9573fc74df
--- /dev/null
+++ b/spl/src/token_2022_extensions/token_metadata.rs
@@ -0,0 +1,107 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+use spl_pod::optional_keys::OptionalNonZeroPubkey;
+use spl_token_metadata_interface::state::Field;
+
+pub fn token_metadata_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TokenMetadataInitialize<'info>>,
+    name: String,
+    symbol: String,
+    uri: String,
+) -> Result<()> {
+    let ix = spl_token_metadata_interface::instruction::initialize(
+        ctx.accounts.program_id.key,
+        ctx.accounts.metadata.key,
+        ctx.accounts.update_authority.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.mint_authority.key,
+        name,
+        symbol,
+        uri,
+    );
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.program_id,
+            ctx.accounts.metadata,
+            ctx.accounts.update_authority,
+            ctx.accounts.mint,
+            ctx.accounts.mint_authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TokenMetadataInitialize<'info> {
+    pub program_id: AccountInfo<'info>,
+    pub metadata: AccountInfo<'info>,
+    pub update_authority: AccountInfo<'info>,
+    pub mint_authority: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn token_metadata_update_authority<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TokenMetadataUpdateAuthority<'info>>,
+    new_authority: OptionalNonZeroPubkey,
+) -> Result<()> {
+    let ix = spl_token_metadata_interface::instruction::update_authority(
+        ctx.accounts.program_id.key,
+        ctx.accounts.metadata.key,
+        ctx.accounts.current_authority.key,
+        new_authority,
+    );
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.program_id,
+            ctx.accounts.metadata,
+            ctx.accounts.current_authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TokenMetadataUpdateAuthority<'info> {
+    pub program_id: AccountInfo<'info>,
+    pub metadata: AccountInfo<'info>,
+    pub current_authority: AccountInfo<'info>,
+    pub new_authority: AccountInfo<'info>,
+}
+
+pub fn token_metadata_update_field<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TokenMetadataUpdateField<'info>>,
+    field: Field,
+    value: String,
+) -> Result<()> {
+    let ix = spl_token_metadata_interface::instruction::update_field(
+        ctx.accounts.program_id.key,
+        ctx.accounts.metadata.key,
+        ctx.accounts.update_authority.key,
+        field,
+        value,
+    );
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.program_id,
+            ctx.accounts.metadata,
+            ctx.accounts.update_authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TokenMetadataUpdateField<'info> {
+    pub program_id: AccountInfo<'info>,
+    pub metadata: AccountInfo<'info>,
+    pub update_authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/transfer_fee.rs b/spl/src/token_2022_extensions/transfer_fee.rs
new file mode 100644
index 0000000000..708d905d30
--- /dev/null
+++ b/spl/src/token_2022_extensions/transfer_fee.rs
@@ -0,0 +1,193 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn transfer_fee_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TransferFeeInitialize<'info>>,
+    transfer_fee_config_authority: Option<&Pubkey>,
+    withdraw_withheld_authority: Option<&Pubkey>,
+    transfer_fee_basis_points: u16,
+    maximum_fee: u64,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::transfer_fee::instruction::initialize_transfer_fee_config(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        transfer_fee_config_authority,
+        withdraw_withheld_authority,
+        transfer_fee_basis_points,
+        maximum_fee,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TransferFeeInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn transfer_fee_set<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TransferFeeSetTransferFee<'info>>,
+    transfer_fee_basis_points: u16,
+    maximum_fee: u64,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::transfer_fee::instruction::set_transfer_fee(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.authority.key,
+        &[],
+        transfer_fee_basis_points,
+        maximum_fee,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.mint,
+            ctx.accounts.authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TransferFeeSetTransferFee<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+}
+
+pub fn transfer_checked_with_fee<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TransferCheckedWithFee<'info>>,
+    amount: u64,
+    decimals: u8,
+    fee: u64,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::transfer_fee::instruction::transfer_checked_with_fee(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.source.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.destination.key,
+        ctx.accounts.authority.key,
+        &[],
+        amount,
+        decimals,
+        fee,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.source,
+            ctx.accounts.mint,
+            ctx.accounts.destination,
+            ctx.accounts.authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TransferCheckedWithFee<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub source: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub destination: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+}
+
+pub fn harvest_withheld_tokens_to_mint<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, HarvestWithheldTokensToMint<'info>>,
+    sources: Vec>,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::transfer_fee::instruction::harvest_withheld_tokens_to_mint(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        sources.iter().map(|a| a.key).collect::>().as_slice(),
+    )?;
+
+    let mut account_infos = vec![ctx.accounts.token_program_id, ctx.accounts.mint];
+    account_infos.extend_from_slice(&sources);
+
+    anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
+        .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct HarvestWithheldTokensToMint<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn withdraw_withheld_tokens_from_mint<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, WithdrawWithheldTokensFromMint<'info>>,
+) -> Result<()> {
+    let ix =
+        spl_token_2022::extension::transfer_fee::instruction::withdraw_withheld_tokens_from_mint(
+            ctx.accounts.token_program_id.key,
+            ctx.accounts.mint.key,
+            ctx.accounts.destination.key,
+            ctx.accounts.authority.key,
+            &[],
+        )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.mint,
+            ctx.accounts.destination,
+            ctx.accounts.authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct WithdrawWithheldTokensFromMint<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub destination: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+}
+
+pub fn withdraw_withheld_tokens_from_accounts<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, WithdrawWithheldTokensFromAccounts<'info>>,
+    sources: Vec>,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::transfer_fee::instruction::withdraw_withheld_tokens_from_accounts(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.destination.key,
+        ctx.accounts.authority.key,
+        &[],
+        sources.iter().map(|a| a.key).collect::>().as_slice(),
+    )?;
+
+    let mut account_infos = vec![
+        ctx.accounts.token_program_id,
+        ctx.accounts.mint,
+        ctx.accounts.destination,
+        ctx.accounts.authority,
+    ];
+    account_infos.extend_from_slice(&sources);
+
+    anchor_lang::solana_program::program::invoke_signed(&ix, &account_infos, ctx.signer_seeds)
+        .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct WithdrawWithheldTokensFromAccounts<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub destination: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_2022_extensions/transfer_hook.rs b/spl/src/token_2022_extensions/transfer_hook.rs
new file mode 100644
index 0000000000..af9df215cc
--- /dev/null
+++ b/spl/src/token_2022_extensions/transfer_hook.rs
@@ -0,0 +1,59 @@
+use anchor_lang::solana_program::account_info::AccountInfo;
+use anchor_lang::solana_program::pubkey::Pubkey;
+use anchor_lang::Result;
+use anchor_lang::{context::CpiContext, Accounts};
+
+pub fn transfer_hook_initialize<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TransferHookInitialize<'info>>,
+    authority: Option,
+    transfer_hook_program_id: Option,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::transfer_hook::instruction::initialize(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        authority,
+        transfer_hook_program_id,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[ctx.accounts.token_program_id, ctx.accounts.mint],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TransferHookInitialize<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+}
+
+pub fn transfer_hook_update<'info>(
+    ctx: CpiContext<'_, '_, '_, 'info, TransferHookUpdate<'info>>,
+    transfer_hook_program_id: Option,
+) -> Result<()> {
+    let ix = spl_token_2022::extension::transfer_hook::instruction::update(
+        ctx.accounts.token_program_id.key,
+        ctx.accounts.mint.key,
+        ctx.accounts.authority.key,
+        &[],
+        transfer_hook_program_id,
+    )?;
+    anchor_lang::solana_program::program::invoke_signed(
+        &ix,
+        &[
+            ctx.accounts.token_program_id,
+            ctx.accounts.mint,
+            ctx.accounts.authority,
+        ],
+        ctx.signer_seeds,
+    )
+    .map_err(Into::into)
+}
+
+#[derive(Accounts)]
+pub struct TransferHookUpdate<'info> {
+    pub token_program_id: AccountInfo<'info>,
+    pub mint: AccountInfo<'info>,
+    pub authority: AccountInfo<'info>,
+}
diff --git a/spl/src/token_interface.rs b/spl/src/token_interface.rs
index 59675e13aa..5b1b4db2c6 100644
--- a/spl/src/token_interface.rs
+++ b/spl/src/token_interface.rs
@@ -1,9 +1,19 @@
+use anchor_lang::solana_program::program_pack::Pack;
 use anchor_lang::solana_program::pubkey::Pubkey;
+use spl_token_2022::extension::ExtensionType;
+use spl_token_2022::{
+    extension::{BaseStateWithExtensions, Extension, StateWithExtensions},
+    solana_zk_token_sdk::instruction::Pod,
+};
 use std::ops::Deref;
 
+pub use crate::token_2022::*;
+#[cfg(feature = "token_2022_extensions")]
+pub use crate::token_2022_extensions::*;
+
 static IDS: [Pubkey; 2] = [spl_token::ID, spl_token_2022::ID];
 
-#[derive(Clone, Debug, Default, PartialEq)]
+#[derive(Clone, Debug, Default, PartialEq, Copy)]
 pub struct TokenAccount(spl_token_2022::state::Account);
 
 impl anchor_lang::AccountDeserialize for TokenAccount {
@@ -32,10 +42,7 @@ impl Deref for TokenAccount {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for TokenAccount {}
-
-#[derive(Clone, Debug, Default, PartialEq)]
+#[derive(Clone, Debug, Default, PartialEq, Copy)]
 pub struct Mint(spl_token_2022::state::Mint);
 
 impl anchor_lang::AccountDeserialize for Mint {
@@ -62,9 +69,6 @@ impl Deref for Mint {
     }
 }
 
-#[cfg(feature = "idl-build")]
-impl anchor_lang::IdlBuild for Mint {}
-
 #[derive(Clone)]
 pub struct TokenInterface;
 
@@ -74,4 +78,24 @@ impl anchor_lang::Ids for TokenInterface {
     }
 }
 
-pub use crate::token_2022::*;
+pub type ExtensionsVec = Vec;
+
+pub fn find_mint_account_size(extensions: Option<&ExtensionsVec>) -> anchor_lang::Result {
+    if let Some(extensions) = extensions {
+        Ok(ExtensionType::try_calculate_account_len::<
+            spl_token_2022::state::Mint,
+        >(extensions)?)
+    } else {
+        Ok(spl_token_2022::state::Mint::LEN)
+    }
+}
+
+pub fn get_mint_extension_data(
+    account: &anchor_lang::solana_program::account_info::AccountInfo,
+) -> anchor_lang::Result {
+    let mint_data = account.data.borrow();
+    let mint_with_extension =
+        StateWithExtensions::::unpack(&mint_data)?;
+    let extension_data = *mint_with_extension.get_extension::()?;
+    Ok(extension_data)
+}
diff --git a/tests/anchor-cli-account/package.json b/tests/anchor-cli-account/package.json
index 29b28206f3..690bdc5362 100644
--- a/tests/anchor-cli-account/package.json
+++ b/tests/anchor-cli-account/package.json
@@ -1,6 +1,6 @@
 {
   "name": "anchor-cli-account",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/anchor-cli-account/programs/account-command/Cargo.toml b/tests/anchor-cli-account/programs/account-command/Cargo.toml
index a078db6a90..9ea040e518 100644
--- a/tests/anchor-cli-account/programs/account-command/Cargo.toml
+++ b/tests/anchor-cli-account/programs/account-command/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/anchor-cli-account/tests/account.ts b/tests/anchor-cli-account/tests/account.ts
index 913d8f5d14..c6754cc546 100644
--- a/tests/anchor-cli-account/tests/account.ts
+++ b/tests/anchor-cli-account/tests/account.ts
@@ -55,9 +55,9 @@ describe("Test CLI account commands", () => {
       await sleep(5000);
     }
 
-    assert(output.balance == balance, "Balance deserialized incorrectly");
+    assert(output.balance === balance, "Balance deserialized incorrectly");
     assert(
-      output.delegatePubkey == provider.wallet.publicKey,
+      output.delegate_pubkey === provider.wallet.publicKey.toBase58(),
       "delegatePubkey deserialized incorrectly"
     );
     assert(
diff --git a/tests/anchor-cli-idl/package.json b/tests/anchor-cli-idl/package.json
index 419ee4aff3..4c31edba4c 100644
--- a/tests/anchor-cli-idl/package.json
+++ b/tests/anchor-cli-idl/package.json
@@ -1,6 +1,6 @@
 {
   "name": "anchor-cli-idl",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/anchor-cli-idl/programs/idl-commands-one/Cargo.toml b/tests/anchor-cli-idl/programs/idl-commands-one/Cargo.toml
index 0da2c05f9c..6d54188882 100644
--- a/tests/anchor-cli-idl/programs/idl-commands-one/Cargo.toml
+++ b/tests/anchor-cli-idl/programs/idl-commands-one/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/anchor-cli-idl/programs/idl-commands-two/Cargo.toml b/tests/anchor-cli-idl/programs/idl-commands-two/Cargo.toml
index 94a8ea6c9d..55e6cb8965 100644
--- a/tests/anchor-cli-idl/programs/idl-commands-two/Cargo.toml
+++ b/tests/anchor-cli-idl/programs/idl-commands-two/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/anchor-cli-idl/test.sh b/tests/anchor-cli-idl/test.sh
index 3a351dcf5b..1bf535253b 100755
--- a/tests/anchor-cli-idl/test.sh
+++ b/tests/anchor-cli-idl/test.sh
@@ -8,8 +8,12 @@ RANDOM_DATA=$(openssl rand -base64 $((10*1680)) | sed 's/.*/"&",/')
 
 # Create the JSON object with the "docs" field containing random data
 echo '{
-  "version": "0.1.0",
-  "name": "idl_commands_one",
+  "address": "2uA3amp95zsEHUpo8qnLMhcFAUsiKVEcKHXS1JetFjU5",
+  "metadata": {
+    "name": "idl_commands_one",
+    "version": "0.1.0",
+    "spec": "0.1.0"
+  },
   "instructions": [
     {
       "name": "initialize",
@@ -17,6 +21,7 @@ echo '{
         '"$RANDOM_DATA"'
         "trailing comma begone"
       ],
+      "discriminator": [],
       "accounts": [],
       "args": []
     }
diff --git a/tests/anchor-cli-idl/tests/idl.ts b/tests/anchor-cli-idl/tests/idl.ts
index b50e6d506e..9c7f56f501 100644
--- a/tests/anchor-cli-idl/tests/idl.ts
+++ b/tests/anchor-cli-idl/tests/idl.ts
@@ -24,12 +24,12 @@ describe("Test CLI IDL commands", () => {
 
   it("Can fetch an IDL using the TypeScript client", async () => {
     const idl = await anchor.Program.fetchIdl(programOne.programId, provider);
-    assert.deepEqual(idl, programOne.idl);
+    assert.deepEqual(idl, programOne.rawIdl);
   });
 
   it("Can fetch an IDL via the CLI", async () => {
     const idl = execSync(`anchor idl fetch ${programOne.programId}`).toString();
-    assert.deepEqual(JSON.parse(idl), programOne.idl);
+    assert.deepEqual(JSON.parse(idl), programOne.rawIdl);
   });
 
   it("Can write a new IDL using the upgrade command", async () => {
@@ -39,7 +39,7 @@ describe("Test CLI IDL commands", () => {
       { stdio: "inherit" }
     );
     const idl = await anchor.Program.fetchIdl(programOne.programId, provider);
-    assert.deepEqual(idl, programTwo.idl);
+    assert.deepEqual(idl, programTwo.rawIdl);
   });
 
   it("Can write a new IDL using write-buffer and set-buffer", async () => {
@@ -53,7 +53,7 @@ describe("Test CLI IDL commands", () => {
       { stdio: "inherit" }
     );
     const idl = await anchor.Program.fetchIdl(programOne.programId, provider);
-    assert.deepEqual(idl, programOne.idl);
+    assert.deepEqual(idl, programOne.rawIdl);
   });
 
   it("Can fetch an IDL authority via the CLI", async () => {
diff --git a/tests/auction-house/package.json b/tests/auction-house/package.json
index 6eddf0d3cd..cbc3449b89 100644
--- a/tests/auction-house/package.json
+++ b/tests/auction-house/package.json
@@ -1,6 +1,6 @@
 {
   "name": "auction-house",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/auction-house/programs/auction-house/Cargo.toml b/tests/auction-house/programs/auction-house/Cargo.toml
index d04d6803de..2029f1932c 100644
--- a/tests/auction-house/programs/auction-house/Cargo.toml
+++ b/tests/auction-house/programs/auction-house/Cargo.toml
@@ -14,6 +14,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/auction-house/tests/auction-house.ts b/tests/auction-house/tests/auction-house.ts
index f7bdf1dcca..dfc638a80e 100644
--- a/tests/auction-house/tests/auction-house.ts
+++ b/tests/auction-house/tests/auction-house.ts
@@ -15,7 +15,9 @@ import {
 import { u64, Token, TOKEN_PROGRAM_ID } from "@solana/spl-token";
 import * as metaplex from "@metaplex/js";
 import * as assert from "assert";
-import { IDL, AuctionHouse } from "../target/types/auction_house";
+import { AuctionHouse } from "../target/types/auction_house";
+
+const IDL = require("../target/idl/auction_house.json");
 
 const MetadataDataData = metaplex.programs.metadata.MetadataDataData;
 const CreateMetadata = metaplex.programs.metadata.CreateMetadata;
@@ -127,14 +129,9 @@ describe("auction-house", () => {
   });
 
   it("Creates auction house program clients representing the buyer and seller", async () => {
-    authorityClient = new Program(
-      IDL,
-      AUCTION_HOUSE_PROGRAM_ID,
-      getProvider()
-    );
+    authorityClient = new Program(IDL, getProvider());
     sellerClient = new Program(
       IDL,
-      AUCTION_HOUSE_PROGRAM_ID,
       new AnchorProvider(
         getProvider().connection,
         new Wallet(sellerWallet),
@@ -143,7 +140,6 @@ describe("auction-house", () => {
     );
     buyerClient = new Program(
       IDL,
-      AUCTION_HOUSE_PROGRAM_ID,
       new AnchorProvider(
         getProvider().connection,
         new Wallet(buyerWallet),
diff --git a/tests/bench/bench.json b/tests/bench/bench.json
index 0636ac40c6..d07a4db634 100644
--- a/tests/bench/bench.json
+++ b/tests/bench/bench.json
@@ -557,189 +557,561 @@
       }
     }
   },
+  "0.30.0": {
+    "solanaVersion": "1.18.8",
+    "result": {
+      "binarySize": {
+        "bench": 791008
+      },
+      "computeUnits": {
+        "accountInfo1": 601,
+        "accountInfo2": 923,
+        "accountInfo4": 1583,
+        "accountInfo8": 2975,
+        "accountEmptyInit1": 5034,
+        "accountEmpty1": 652,
+        "accountEmptyInit2": 9687,
+        "accountEmpty2": 1016,
+        "accountEmptyInit4": 18501,
+        "accountEmpty4": 1737,
+        "accountEmptyInit8": 36169,
+        "accountEmpty8": 3186,
+        "accountSizedInit1": 5106,
+        "accountSized1": 668,
+        "accountSizedInit2": 9828,
+        "accountSized2": 1046,
+        "accountSizedInit4": 18837,
+        "accountSized4": 1807,
+        "accountSizedInit8": 36761,
+        "accountSized8": 3326,
+        "accountUnsizedInit1": 5199,
+        "accountUnsized1": 702,
+        "accountUnsizedInit2": 10078,
+        "accountUnsized2": 1116,
+        "accountUnsizedInit4": 19259,
+        "accountUnsized4": 1953,
+        "accountUnsizedInit8": 37331,
+        "accountUnsized8": 3626,
+        "boxedAccountEmptyInit1": 5064,
+        "boxedAccountEmpty1": 671,
+        "boxedAccountEmptyInit2": 9721,
+        "boxedAccountEmpty2": 1052,
+        "boxedAccountEmptyInit4": 18582,
+        "boxedAccountEmpty4": 1811,
+        "boxedAccountEmptyInit8": 36329,
+        "boxedAccountEmpty8": 3357,
+        "boxedAccountSizedInit1": 5119,
+        "boxedAccountSized1": 686,
+        "boxedAccountSizedInit2": 9845,
+        "boxedAccountSized2": 1085,
+        "boxedAccountSizedInit4": 18825,
+        "boxedAccountSized4": 1874,
+        "boxedAccountSizedInit8": 36824,
+        "boxedAccountSized8": 3490,
+        "boxedAccountUnsizedInit1": 5207,
+        "boxedAccountUnsized1": 721,
+        "boxedAccountUnsizedInit2": 10015,
+        "boxedAccountUnsized2": 1157,
+        "boxedAccountUnsizedInit4": 19160,
+        "boxedAccountUnsized4": 2019,
+        "boxedAccountUnsizedInit8": 37496,
+        "boxedAccountUnsized8": 3776,
+        "boxedInterfaceAccountMint1": 1372,
+        "boxedInterfaceAccountMint2": 2293,
+        "boxedInterfaceAccountMint4": 4121,
+        "boxedInterfaceAccountMint8": 7811,
+        "boxedInterfaceAccountToken1": 2056,
+        "boxedInterfaceAccountToken2": 3660,
+        "boxedInterfaceAccountToken4": 6858,
+        "boxedInterfaceAccountToken8": 13284,
+        "interfaceAccountMint1": 1472,
+        "interfaceAccountMint2": 2631,
+        "interfaceAccountMint4": 4951,
+        "interfaceAccountMint8": 9588,
+        "interfaceAccountToken1": 2130,
+        "interfaceAccountToken2": 3928,
+        "interfaceAccountToken4": 7521,
+        "interface1": 600,
+        "interface2": 745,
+        "interface4": 1033,
+        "interface8": 1616,
+        "program1": 596,
+        "program2": 737,
+        "program4": 1019,
+        "program8": 1584,
+        "signer1": 580,
+        "signer2": 872,
+        "signer4": 1454,
+        "signer8": 2618,
+        "systemAccount1": 592,
+        "systemAccount2": 894,
+        "systemAccount4": 1497,
+        "systemAccount8": 2707,
+        "uncheckedAccount1": 563,
+        "uncheckedAccount2": 836,
+        "uncheckedAccount4": 1378,
+        "uncheckedAccount8": 2468
+      },
+      "stackMemory": {
+        "account_info1": 144,
+        "account_info2": 144,
+        "account_info4": 144,
+        "account_info8": 144,
+        "account_empty_init1": 144,
+        "account_empty_init2": 144,
+        "account_empty_init4": 192,
+        "account_empty_init8": 224,
+        "account_empty1": 144,
+        "account_empty2": 144,
+        "account_empty4": 144,
+        "account_empty8": 144,
+        "account_sized_init1": 176,
+        "account_sized_init2": 192,
+        "account_sized_init4": 224,
+        "account_sized_init8": 288,
+        "account_sized1": 144,
+        "account_sized2": 144,
+        "account_sized4": 144,
+        "account_sized8": 144,
+        "account_unsized_init1": 192,
+        "account_unsized_init2": 224,
+        "account_unsized_init4": 288,
+        "account_unsized_init8": 416,
+        "account_unsized1": 144,
+        "account_unsized2": 144,
+        "account_unsized4": 144,
+        "account_unsized8": 144,
+        "boxed_account_empty_init1": 144,
+        "boxed_account_empty_init2": 144,
+        "boxed_account_empty_init4": 192,
+        "boxed_account_empty_init8": 224,
+        "boxed_account_empty1": 144,
+        "boxed_account_empty2": 144,
+        "boxed_account_empty4": 144,
+        "boxed_account_empty8": 144,
+        "boxed_account_sized_init1": 144,
+        "boxed_account_sized_init2": 144,
+        "boxed_account_sized_init4": 192,
+        "boxed_account_sized_init8": 224,
+        "boxed_account_sized1": 144,
+        "boxed_account_sized2": 144,
+        "boxed_account_sized4": 144,
+        "boxed_account_sized8": 144,
+        "boxed_account_unsized_init1": 144,
+        "boxed_account_unsized_init2": 144,
+        "boxed_account_unsized_init4": 192,
+        "boxed_account_unsized_init8": 224,
+        "boxed_account_unsized1": 144,
+        "boxed_account_unsized2": 144,
+        "boxed_account_unsized4": 144,
+        "boxed_account_unsized8": 144,
+        "boxed_interface_account_mint1": 144,
+        "boxed_interface_account_mint2": 144,
+        "boxed_interface_account_mint4": 144,
+        "boxed_interface_account_mint8": 144,
+        "boxed_interface_account_token1": 144,
+        "boxed_interface_account_token2": 144,
+        "boxed_interface_account_token4": 144,
+        "boxed_interface_account_token8": 144,
+        "interface_account_mint1": 144,
+        "interface_account_mint2": 144,
+        "interface_account_mint4": 144,
+        "interface_account_mint8": 144,
+        "interface_account_token1": 144,
+        "interface_account_token2": 144,
+        "interface_account_token4": 144,
+        "interface1": 144,
+        "interface2": 144,
+        "interface4": 144,
+        "interface8": 144,
+        "program1": 144,
+        "program2": 144,
+        "program4": 144,
+        "program8": 144,
+        "signer1": 144,
+        "signer2": 144,
+        "signer4": 144,
+        "signer8": 144,
+        "system_account1": 144,
+        "system_account2": 144,
+        "system_account4": 144,
+        "system_account8": 144,
+        "unchecked_account1": 144,
+        "unchecked_account2": 144,
+        "unchecked_account4": 144,
+        "unchecked_account8": 144
+      }
+    }
+  },
+  "0.30.1": {
+    "solanaVersion": "1.18.17",
+    "result": {
+      "binarySize": {
+        "bench": 791008
+      },
+      "computeUnits": {
+        "accountInfo1": 601,
+        "accountInfo2": 923,
+        "accountInfo4": 1583,
+        "accountInfo8": 2975,
+        "accountEmptyInit1": 5034,
+        "accountEmpty1": 652,
+        "accountEmptyInit2": 9687,
+        "accountEmpty2": 1016,
+        "accountEmptyInit4": 18501,
+        "accountEmpty4": 1737,
+        "accountEmptyInit8": 36169,
+        "accountEmpty8": 3186,
+        "accountSizedInit1": 5106,
+        "accountSized1": 668,
+        "accountSizedInit2": 9828,
+        "accountSized2": 1046,
+        "accountSizedInit4": 18837,
+        "accountSized4": 1807,
+        "accountSizedInit8": 36761,
+        "accountSized8": 3326,
+        "accountUnsizedInit1": 5199,
+        "accountUnsized1": 702,
+        "accountUnsizedInit2": 10078,
+        "accountUnsized2": 1116,
+        "accountUnsizedInit4": 19259,
+        "accountUnsized4": 1953,
+        "accountUnsizedInit8": 37331,
+        "accountUnsized8": 3626,
+        "boxedAccountEmptyInit1": 5064,
+        "boxedAccountEmpty1": 671,
+        "boxedAccountEmptyInit2": 9721,
+        "boxedAccountEmpty2": 1052,
+        "boxedAccountEmptyInit4": 18582,
+        "boxedAccountEmpty4": 1811,
+        "boxedAccountEmptyInit8": 36329,
+        "boxedAccountEmpty8": 3357,
+        "boxedAccountSizedInit1": 5119,
+        "boxedAccountSized1": 686,
+        "boxedAccountSizedInit2": 9845,
+        "boxedAccountSized2": 1085,
+        "boxedAccountSizedInit4": 18825,
+        "boxedAccountSized4": 1874,
+        "boxedAccountSizedInit8": 36824,
+        "boxedAccountSized8": 3490,
+        "boxedAccountUnsizedInit1": 5207,
+        "boxedAccountUnsized1": 721,
+        "boxedAccountUnsizedInit2": 10015,
+        "boxedAccountUnsized2": 1157,
+        "boxedAccountUnsizedInit4": 19160,
+        "boxedAccountUnsized4": 2019,
+        "boxedAccountUnsizedInit8": 37496,
+        "boxedAccountUnsized8": 3776,
+        "boxedInterfaceAccountMint1": 1372,
+        "boxedInterfaceAccountMint2": 2293,
+        "boxedInterfaceAccountMint4": 4121,
+        "boxedInterfaceAccountMint8": 7811,
+        "boxedInterfaceAccountToken1": 2056,
+        "boxedInterfaceAccountToken2": 3660,
+        "boxedInterfaceAccountToken4": 6858,
+        "boxedInterfaceAccountToken8": 13284,
+        "interfaceAccountMint1": 1472,
+        "interfaceAccountMint2": 2631,
+        "interfaceAccountMint4": 4951,
+        "interfaceAccountMint8": 9588,
+        "interfaceAccountToken1": 2130,
+        "interfaceAccountToken2": 3928,
+        "interfaceAccountToken4": 7521,
+        "interface1": 600,
+        "interface2": 745,
+        "interface4": 1033,
+        "interface8": 1616,
+        "program1": 596,
+        "program2": 737,
+        "program4": 1019,
+        "program8": 1584,
+        "signer1": 580,
+        "signer2": 872,
+        "signer4": 1454,
+        "signer8": 2618,
+        "systemAccount1": 592,
+        "systemAccount2": 894,
+        "systemAccount4": 1497,
+        "systemAccount8": 2707,
+        "uncheckedAccount1": 563,
+        "uncheckedAccount2": 836,
+        "uncheckedAccount4": 1378,
+        "uncheckedAccount8": 2468
+      },
+      "stackMemory": {
+        "account_info1": 144,
+        "account_info2": 144,
+        "account_info4": 144,
+        "account_info8": 144,
+        "account_empty_init1": 144,
+        "account_empty_init2": 144,
+        "account_empty_init4": 192,
+        "account_empty_init8": 224,
+        "account_empty1": 144,
+        "account_empty2": 144,
+        "account_empty4": 144,
+        "account_empty8": 144,
+        "account_sized_init1": 176,
+        "account_sized_init2": 192,
+        "account_sized_init4": 224,
+        "account_sized_init8": 288,
+        "account_sized1": 144,
+        "account_sized2": 144,
+        "account_sized4": 144,
+        "account_sized8": 144,
+        "account_unsized_init1": 192,
+        "account_unsized_init2": 224,
+        "account_unsized_init4": 288,
+        "account_unsized_init8": 416,
+        "account_unsized1": 144,
+        "account_unsized2": 144,
+        "account_unsized4": 144,
+        "account_unsized8": 144,
+        "boxed_account_empty_init1": 144,
+        "boxed_account_empty_init2": 144,
+        "boxed_account_empty_init4": 192,
+        "boxed_account_empty_init8": 224,
+        "boxed_account_empty1": 144,
+        "boxed_account_empty2": 144,
+        "boxed_account_empty4": 144,
+        "boxed_account_empty8": 144,
+        "boxed_account_sized_init1": 144,
+        "boxed_account_sized_init2": 144,
+        "boxed_account_sized_init4": 192,
+        "boxed_account_sized_init8": 224,
+        "boxed_account_sized1": 144,
+        "boxed_account_sized2": 144,
+        "boxed_account_sized4": 144,
+        "boxed_account_sized8": 144,
+        "boxed_account_unsized_init1": 144,
+        "boxed_account_unsized_init2": 144,
+        "boxed_account_unsized_init4": 192,
+        "boxed_account_unsized_init8": 224,
+        "boxed_account_unsized1": 144,
+        "boxed_account_unsized2": 144,
+        "boxed_account_unsized4": 144,
+        "boxed_account_unsized8": 144,
+        "boxed_interface_account_mint1": 144,
+        "boxed_interface_account_mint2": 144,
+        "boxed_interface_account_mint4": 144,
+        "boxed_interface_account_mint8": 144,
+        "boxed_interface_account_token1": 144,
+        "boxed_interface_account_token2": 144,
+        "boxed_interface_account_token4": 144,
+        "boxed_interface_account_token8": 144,
+        "interface_account_mint1": 144,
+        "interface_account_mint2": 144,
+        "interface_account_mint4": 144,
+        "interface_account_mint8": 144,
+        "interface_account_token1": 144,
+        "interface_account_token2": 144,
+        "interface_account_token4": 144,
+        "interface1": 144,
+        "interface2": 144,
+        "interface4": 144,
+        "interface8": 144,
+        "program1": 144,
+        "program2": 144,
+        "program4": 144,
+        "program8": 144,
+        "signer1": 144,
+        "signer2": 144,
+        "signer4": 144,
+        "signer8": 144,
+        "system_account1": 144,
+        "system_account2": 144,
+        "system_account4": 144,
+        "system_account8": 144,
+        "unchecked_account1": 144,
+        "unchecked_account2": 144,
+        "unchecked_account4": 144,
+        "unchecked_account8": 144
+      }
+    }
+  },
   "unreleased": {
-    "solanaVersion": "1.17.0",
+    "solanaVersion": "1.18.17",
     "result": {
       "binarySize": {
-        "bench": 743208
+        "bench": 787968
       },
       "computeUnits": {
-        "accountInfo1": 695,
-        "accountInfo2": 1035,
-        "accountInfo4": 1730,
-        "accountInfo8": 3342,
-        "accountEmptyInit1": 5552,
-        "accountEmpty1": 819,
-        "accountEmptyInit2": 10421,
-        "accountEmpty2": 1275,
-        "accountEmptyInit4": 19803,
-        "accountEmpty4": 2177,
-        "accountEmptyInit8": 38609,
-        "accountEmpty8": 3990,
-        "accountSizedInit1": 5647,
-        "accountSized1": 843,
-        "accountSizedInit2": 10607,
-        "accountSized2": 1317,
-        "accountSizedInit4": 20225,
-        "accountSized4": 2274,
-        "accountSizedInit8": 39376,
-        "accountSized8": 4185,
-        "accountUnsizedInit1": 5740,
-        "accountUnsized1": 870,
-        "accountUnsizedInit2": 10856,
-        "accountUnsized2": 1379,
-        "accountUnsizedInit4": 20652,
-        "accountUnsized4": 2411,
-        "accountUnsizedInit8": 39969,
-        "accountUnsized8": 4478,
-        "boxedAccountEmptyInit1": 5605,
-        "boxedAccountEmpty1": 856,
-        "boxedAccountEmptyInit2": 10522,
-        "boxedAccountEmpty2": 1347,
-        "boxedAccountEmptyInit4": 20002,
-        "boxedAccountEmpty4": 2324,
-        "boxedAccountEmptyInit8": 39002,
-        "boxedAccountEmpty8": 4311,
-        "boxedAccountSizedInit1": 5686,
-        "boxedAccountSized1": 878,
-        "boxedAccountSizedInit2": 10690,
-        "boxedAccountSized2": 1394,
-        "boxedAccountSizedInit4": 20338,
-        "boxedAccountSized4": 2413,
-        "boxedAccountSizedInit8": 39670,
-        "boxedAccountSized8": 4493,
-        "boxedAccountUnsizedInit1": 5774,
-        "boxedAccountUnsized1": 908,
-        "boxedAccountUnsizedInit2": 10866,
-        "boxedAccountUnsized2": 1457,
-        "boxedAccountUnsizedInit4": 20688,
-        "boxedAccountUnsized4": 2546,
-        "boxedAccountUnsizedInit8": 40375,
-        "boxedAccountUnsized8": 4759,
-        "boxedInterfaceAccountMint1": 2196,
-        "boxedInterfaceAccountMint2": 3847,
-        "boxedInterfaceAccountMint4": 7132,
-        "boxedInterfaceAccountMint8": 13743,
-        "boxedInterfaceAccountToken1": 2126,
-        "boxedInterfaceAccountToken2": 3706,
-        "boxedInterfaceAccountToken4": 6853,
-        "boxedInterfaceAccountToken8": 13184,
-        "interfaceAccountMint1": 2285,
-        "interfaceAccountMint2": 4178,
-        "interfaceAccountMint4": 7964,
-        "interfaceAccountMint8": 15538,
-        "interfaceAccountToken1": 2212,
-        "interfaceAccountToken2": 4030,
-        "interfaceAccountToken4": 7663,
-        "interface1": 741,
-        "interface2": 934,
-        "interface4": 1315,
-        "interface8": 2086,
-        "program1": 741,
-        "program2": 934,
-        "program4": 1317,
-        "program8": 2086,
-        "signer1": 675,
-        "signer2": 987,
-        "signer4": 1606,
-        "signer8": 2846,
-        "systemAccount1": 729,
-        "systemAccount2": 1093,
-        "systemAccount4": 1817,
-        "systemAccount8": 3271,
-        "uncheckedAccount1": 657,
-        "uncheckedAccount2": 949,
-        "uncheckedAccount4": 1526,
-        "uncheckedAccount8": 2688
+        "accountInfo1": 573,
+        "accountInfo2": 899,
+        "accountInfo4": 1561,
+        "accountInfo8": 2957,
+        "accountEmptyInit1": 4976,
+        "accountEmpty1": 649,
+        "accountEmptyInit2": 9590,
+        "accountEmpty2": 1015,
+        "accountEmptyInit4": 18323,
+        "accountEmpty4": 1740,
+        "accountEmptyInit8": 35827,
+        "accountEmpty8": 3193,
+        "accountSizedInit1": 5070,
+        "accountSized1": 690,
+        "accountSizedInit2": 9750,
+        "accountSized2": 1069,
+        "accountSizedInit4": 18677,
+        "accountSized4": 1834,
+        "accountSizedInit8": 36426,
+        "accountSized8": 3357,
+        "accountUnsizedInit1": 5190,
+        "accountUnsized1": 747,
+        "accountUnsizedInit2": 10033,
+        "accountUnsized2": 1165,
+        "accountUnsizedInit4": 19134,
+        "accountUnsized4": 2004,
+        "accountUnsizedInit8": 37046,
+        "accountUnsized8": 3679,
+        "boxedAccountEmptyInit1": 5078,
+        "boxedAccountEmpty1": 740,
+        "boxedAccountEmptyInit2": 9697,
+        "boxedAccountEmpty2": 1125,
+        "boxedAccountEmptyInit4": 18477,
+        "boxedAccountEmpty4": 1886,
+        "boxedAccountEmptyInit8": 36059,
+        "boxedAccountEmpty8": 3435,
+        "boxedAccountSizedInit1": 5157,
+        "boxedAccountSized1": 780,
+        "boxedAccountSizedInit2": 9842,
+        "boxedAccountSized2": 1180,
+        "boxedAccountSizedInit4": 18736,
+        "boxedAccountSized4": 1974,
+        "boxedAccountSizedInit8": 36563,
+        "boxedAccountSized8": 3593,
+        "boxedAccountUnsizedInit1": 5271,
+        "boxedAccountUnsized1": 839,
+        "boxedAccountUnsizedInit2": 10040,
+        "boxedAccountUnsized2": 1277,
+        "boxedAccountUnsizedInit4": 19108,
+        "boxedAccountUnsized4": 2142,
+        "boxedAccountUnsizedInit8": 37283,
+        "boxedAccountUnsized8": 3903,
+        "boxedInterfaceAccountMint1": 1502,
+        "boxedInterfaceAccountMint2": 2423,
+        "boxedInterfaceAccountMint4": 4256,
+        "boxedInterfaceAccountMint8": 7950,
+        "boxedInterfaceAccountToken1": 2198,
+        "boxedInterfaceAccountToken2": 3803,
+        "boxedInterfaceAccountToken4": 7004,
+        "boxedInterfaceAccountToken8": 13434,
+        "interfaceAccountMint1": 1626,
+        "interfaceAccountMint2": 2788,
+        "interfaceAccountMint4": 5110,
+        "interfaceAccountMint8": 9749,
+        "interfaceAccountToken1": 2296,
+        "interfaceAccountToken2": 4096,
+        "interfaceAccountToken4": 7692,
+        "interface1": 774,
+        "interface2": 923,
+        "interface4": 1214,
+        "interface8": 1799,
+        "program1": 782,
+        "program2": 927,
+        "program4": 1210,
+        "program8": 1779,
+        "signer1": 779,
+        "signer2": 1074,
+        "signer4": 1657,
+        "signer8": 2826,
+        "systemAccount1": 802,
+        "systemAccount2": 1108,
+        "systemAccount4": 1713,
+        "systemAccount8": 2926,
+        "uncheckedAccount1": 785,
+        "uncheckedAccount2": 1061,
+        "uncheckedAccount4": 1604,
+        "uncheckedAccount8": 2699
       },
       "stackMemory": {
-        "account_info1": 128,
-        "account_info2": 128,
-        "account_info4": 128,
-        "account_info8": 128,
-        "account_empty_init1": 176,
-        "account_empty_init2": 208,
-        "account_empty_init4": 208,
-        "account_empty_init8": 240,
-        "account_empty1": 128,
-        "account_empty2": 128,
-        "account_empty4": 128,
-        "account_empty8": 128,
-        "account_sized_init1": 208,
-        "account_sized_init2": 256,
-        "account_sized_init4": 240,
-        "account_sized_init8": 304,
-        "account_sized1": 128,
-        "account_sized2": 128,
-        "account_sized4": 128,
-        "account_sized8": 128,
-        "account_unsized_init1": 224,
-        "account_unsized_init2": 296,
-        "account_unsized_init4": 304,
-        "account_unsized_init8": 432,
-        "account_unsized1": 128,
+        "account_info1": 144,
+        "account_info2": 144,
+        "account_info4": 144,
+        "account_info8": 144,
+        "account_empty_init1": 144,
+        "account_empty_init2": 144,
+        "account_empty_init4": 192,
+        "account_empty_init8": 224,
+        "account_empty1": 144,
+        "account_empty2": 144,
+        "account_empty4": 144,
+        "account_empty8": 144,
+        "account_sized_init1": 176,
+        "account_sized_init2": 192,
+        "account_sized_init4": 224,
+        "account_sized_init8": 288,
+        "account_sized1": 144,
+        "account_sized2": 144,
+        "account_sized4": 144,
+        "account_sized8": 144,
+        "account_unsized_init1": 192,
+        "account_unsized_init2": 224,
+        "account_unsized_init4": 288,
+        "account_unsized_init8": 416,
+        "account_unsized1": 144,
         "account_unsized2": 144,
-        "account_unsized4": 128,
-        "account_unsized8": 128,
-        "boxed_account_empty_init1": 176,
-        "boxed_account_empty_init2": 208,
-        "boxed_account_empty_init4": 208,
-        "boxed_account_empty_init8": 240,
-        "boxed_account_empty1": 128,
-        "boxed_account_empty2": 128,
+        "account_unsized4": 144,
+        "account_unsized8": 144,
+        "boxed_account_empty_init1": 144,
+        "boxed_account_empty_init2": 144,
+        "boxed_account_empty_init4": 192,
+        "boxed_account_empty_init8": 224,
+        "boxed_account_empty1": 144,
+        "boxed_account_empty2": 144,
         "boxed_account_empty4": 144,
         "boxed_account_empty8": 144,
-        "boxed_account_sized_init1": 176,
-        "boxed_account_sized_init2": 208,
-        "boxed_account_sized_init4": 208,
-        "boxed_account_sized_init8": 240,
-        "boxed_account_sized1": 128,
-        "boxed_account_sized2": 128,
+        "boxed_account_sized_init1": 144,
+        "boxed_account_sized_init2": 144,
+        "boxed_account_sized_init4": 192,
+        "boxed_account_sized_init8": 224,
+        "boxed_account_sized1": 144,
+        "boxed_account_sized2": 144,
         "boxed_account_sized4": 144,
         "boxed_account_sized8": 144,
-        "boxed_account_unsized_init1": 176,
-        "boxed_account_unsized_init2": 208,
-        "boxed_account_unsized_init4": 208,
-        "boxed_account_unsized_init8": 240,
-        "boxed_account_unsized1": 128,
+        "boxed_account_unsized_init1": 144,
+        "boxed_account_unsized_init2": 144,
+        "boxed_account_unsized_init4": 192,
+        "boxed_account_unsized_init8": 224,
+        "boxed_account_unsized1": 144,
         "boxed_account_unsized2": 144,
-        "boxed_account_unsized4": 128,
-        "boxed_account_unsized8": 128,
-        "boxed_interface_account_mint1": 128,
-        "boxed_interface_account_mint2": 128,
+        "boxed_account_unsized4": 144,
+        "boxed_account_unsized8": 144,
+        "boxed_interface_account_mint1": 144,
+        "boxed_interface_account_mint2": 144,
         "boxed_interface_account_mint4": 144,
         "boxed_interface_account_mint8": 144,
-        "boxed_interface_account_token1": 128,
-        "boxed_interface_account_token2": 128,
+        "boxed_interface_account_token1": 144,
+        "boxed_interface_account_token2": 144,
         "boxed_interface_account_token4": 144,
         "boxed_interface_account_token8": 144,
-        "interface_account_mint1": 128,
-        "interface_account_mint2": 128,
-        "interface_account_mint4": 128,
-        "interface_account_mint8": 128,
-        "interface_account_token1": 128,
-        "interface_account_token2": 128,
-        "interface_account_token4": 128,
-        "interface1": 128,
-        "interface2": 128,
-        "interface4": 128,
-        "interface8": 128,
-        "program1": 128,
-        "program2": 128,
-        "program4": 128,
-        "program8": 128,
-        "signer1": 128,
-        "signer2": 128,
-        "signer4": 128,
-        "signer8": 128,
-        "system_account1": 128,
-        "system_account2": 128,
-        "system_account4": 128,
-        "system_account8": 128,
-        "unchecked_account1": 128,
-        "unchecked_account2": 128,
-        "unchecked_account4": 128,
-        "unchecked_account8": 128
+        "interface_account_mint1": 144,
+        "interface_account_mint2": 144,
+        "interface_account_mint4": 144,
+        "interface_account_mint8": 144,
+        "interface_account_token1": 144,
+        "interface_account_token2": 144,
+        "interface_account_token4": 144,
+        "interface1": 144,
+        "interface2": 144,
+        "interface4": 144,
+        "interface8": 144,
+        "program1": 144,
+        "program2": 144,
+        "program4": 144,
+        "program8": 144,
+        "signer1": 144,
+        "signer2": 144,
+        "signer4": 144,
+        "signer8": 144,
+        "system_account1": 144,
+        "system_account2": 144,
+        "system_account4": 144,
+        "system_account8": 144,
+        "unchecked_account1": 144,
+        "unchecked_account2": 144,
+        "unchecked_account4": 144,
+        "unchecked_account8": 144
       }
     }
   }
diff --git a/tests/bench/locks/0.30.0.lock b/tests/bench/locks/0.30.0.lock
new file mode 100644
index 0000000000..3a1e2f352f
--- /dev/null
+++ b/tests/bench/locks/0.30.0.lock
@@ -0,0 +1,2662 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aead"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "aes"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+ "opaque-debug",
+]
+
+[[package]]
+name = "aes-gcm-siv"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "polyval",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "ahash"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
+dependencies = [
+ "getrandom 0.2.14",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anchor-attribute-access-control"
+version = "0.30.0"
+dependencies = [
+ "anchor-syn",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-account"
+version = "0.30.0"
+dependencies = [
+ "anchor-syn",
+ "bs58 0.5.1",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-constant"
+version = "0.30.0"
+dependencies = [
+ "anchor-syn",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-error"
+version = "0.30.0"
+dependencies = [
+ "anchor-syn",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-event"
+version = "0.30.0"
+dependencies = [
+ "anchor-syn",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-program"
+version = "0.30.0"
+dependencies = [
+ "anchor-lang-idl",
+ "anchor-syn",
+ "anyhow",
+ "bs58 0.5.1",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "serde_json",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-derive-accounts"
+version = "0.30.0"
+dependencies = [
+ "anchor-syn",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-derive-serde"
+version = "0.30.0"
+dependencies = [
+ "anchor-syn",
+ "borsh-derive-internal 0.10.3",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-derive-space"
+version = "0.30.0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-lang"
+version = "0.30.0"
+dependencies = [
+ "anchor-attribute-access-control",
+ "anchor-attribute-account",
+ "anchor-attribute-constant",
+ "anchor-attribute-error",
+ "anchor-attribute-event",
+ "anchor-attribute-program",
+ "anchor-derive-accounts",
+ "anchor-derive-serde",
+ "anchor-derive-space",
+ "anchor-lang-idl",
+ "arrayref",
+ "base64 0.21.7",
+ "bincode",
+ "borsh 0.10.3",
+ "bytemuck",
+ "getrandom 0.2.14",
+ "solana-program",
+ "thiserror",
+]
+
+[[package]]
+name = "anchor-lang-idl"
+version = "0.1.0"
+dependencies = [
+ "anchor-syn",
+ "anyhow",
+ "regex",
+ "serde",
+ "serde_json",
+]
+
+[[package]]
+name = "anchor-spl"
+version = "0.30.0"
+dependencies = [
+ "anchor-lang",
+ "spl-associated-token-account",
+ "spl-pod",
+ "spl-token",
+ "spl-token-2022",
+ "spl-token-group-interface",
+ "spl-token-metadata-interface",
+]
+
+[[package]]
+name = "anchor-syn"
+version = "0.30.0"
+dependencies = [
+ "anyhow",
+ "bs58 0.5.1",
+ "cargo_toml",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "sha2 0.10.8",
+ "syn 1.0.109",
+ "thiserror",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.82"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f538837af36e6f6a9be0faa67f9a314f8119e4e4b5867c6ab40ed60360142519"
+
+[[package]]
+name = "ark-bn254"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f"
+dependencies = [
+ "ark-ec",
+ "ark-ff",
+ "ark-std",
+]
+
+[[package]]
+name = "ark-ec"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba"
+dependencies = [
+ "ark-ff",
+ "ark-poly",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "hashbrown 0.13.2",
+ "itertools",
+ "num-traits",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba"
+dependencies = [
+ "ark-ff-asm",
+ "ark-ff-macros",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "digest 0.10.7",
+ "itertools",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "rustc_version",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-poly"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf"
+dependencies = [
+ "ark-ff",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "hashbrown 0.13.2",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5"
+dependencies = [
+ "ark-serialize-derive",
+ "ark-std",
+ "digest 0.10.7",
+ "num-bigint",
+]
+
+[[package]]
+name = "ark-serialize-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
+dependencies = [
+ "num-traits",
+ "rand 0.8.5",
+]
+
+[[package]]
+name = "arrayref"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+
+[[package]]
+name = "assert_matches"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
+
+[[package]]
+name = "base64"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+
+[[package]]
+name = "base64"
+version = "0.21.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+
+[[package]]
+name = "bench"
+version = "0.1.0"
+dependencies = [
+ "anchor-lang",
+ "anchor-spl",
+]
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.3.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
+
+[[package]]
+name = "bitflags"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bitmaps"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "blake3"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "block-padding",
+ "generic-array",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
+
+[[package]]
+name = "borsh"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa"
+dependencies = [
+ "borsh-derive 0.9.3",
+ "hashbrown 0.11.2",
+]
+
+[[package]]
+name = "borsh"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
+dependencies = [
+ "borsh-derive 0.10.3",
+ "hashbrown 0.13.2",
+]
+
+[[package]]
+name = "borsh"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0901fc8eb0aca4c83be0106d6f2db17d86a08dfc2c25f0e84464bf381158add6"
+dependencies = [
+ "borsh-derive 1.4.0",
+ "cfg_aliases",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775"
+dependencies = [
+ "borsh-derive-internal 0.9.3",
+ "borsh-schema-derive-internal 0.9.3",
+ "proc-macro-crate 0.1.5",
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
+dependencies = [
+ "borsh-derive-internal 0.10.3",
+ "borsh-schema-derive-internal 0.10.3",
+ "proc-macro-crate 0.1.5",
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "51670c3aa053938b0ee3bd67c3817e471e626151131b934038e83c5bf8de48f5"
+dependencies = [
+ "once_cell",
+ "proc-macro-crate 3.1.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+ "syn_derive",
+]
+
+[[package]]
+name = "borsh-derive-internal"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-derive-internal"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-schema-derive-internal"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-schema-derive-internal"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "bs58"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
+
+[[package]]
+name = "bs58"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "bv"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340"
+dependencies = [
+ "feature-probe",
+ "serde",
+]
+
+[[package]]
+name = "bytemuck"
+version = "1.15.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5d6d68c57235a3a081186990eca2867354726650f42f7516ca50c28d6281fd15"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4da9a32f3fed317401fa3c862968128267c3106685286e15d5aaa3d7389c2f60"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cargo_toml"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be"
+dependencies = [
+ "serde",
+ "toml 0.8.12",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.94"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17f6e324229dc011159fcc089755d1e2e216a90d43a7dea6853ca740b84f35e7"
+dependencies = [
+ "jobserver",
+ "libc",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e"
+
+[[package]]
+name = "chrono"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "cipher"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "console_log"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f"
+dependencies = [
+ "log",
+ "web-sys",
+]
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345"
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "crypto-mac"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
+dependencies = [
+ "generic-array",
+ "subtle",
+]
+
+[[package]]
+name = "ctr"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
+dependencies = [
+ "byteorder",
+ "digest 0.9.0",
+ "rand_core 0.5.1",
+ "serde",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "54e36fcd13ed84ffdfda6f5be89b31287cbb80c439841fe69e04841435464391"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c2cf1c23a687a1feeb728783b993c4e1ad83d99f351801977dd809b48d0a70f"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a668eda54683121533a393014d8692171709ff57a7d61f187b6e782719f8933f"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "derivation-path"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0"
+
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer 0.10.4",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "ed25519"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+dependencies = [
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "rand 0.7.3",
+ "serde",
+ "sha2 0.9.9",
+ "zeroize",
+]
+
+[[package]]
+name = "ed25519-dalek-bip32"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908"
+dependencies = [
+ "derivation-path",
+ "ed25519-dalek",
+ "hmac 0.12.1",
+ "sha2 0.10.8",
+]
+
+[[package]]
+name = "either"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a47c1c47d2f5964e29c61246e81db715514cd532db6b5116a25ea3c03d6780a2"
+
+[[package]]
+name = "env_logger"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "feature-probe"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "serde",
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94b22e06ecb0110981051723910cbf0b5f5e09a2062dd7663334ee79a9d1286c"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+dependencies = [
+ "ahash 0.7.8",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash 0.8.11",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hmac"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
+dependencies = [
+ "crypto-mac",
+ "digest 0.9.0",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "hmac-drbg"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1"
+dependencies = [
+ "digest 0.9.0",
+ "generic-array",
+ "hmac 0.8.1",
+]
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "im"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9"
+dependencies = [
+ "bitmaps",
+ "rand_core 0.6.4",
+ "rand_xoshiro",
+ "rayon",
+ "serde",
+ "sized-chunks",
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.3",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "jobserver"
+version = "0.1.30"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "685a7d121ee3f65ae4fddd72b25a04bb36b6af81bc0828f7d5434c0fe60fa3a2"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "keccak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
+dependencies = [
+ "cpufeatures",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.153"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
+
+[[package]]
+name = "libsecp256k1"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73"
+dependencies = [
+ "arrayref",
+ "base64 0.12.3",
+ "digest 0.9.0",
+ "hmac-drbg",
+ "libsecp256k1-core",
+ "libsecp256k1-gen-ecmult",
+ "libsecp256k1-gen-genmult",
+ "rand 0.7.3",
+ "serde",
+ "sha2 0.9.9",
+ "typenum",
+]
+
+[[package]]
+name = "libsecp256k1-core"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80"
+dependencies = [
+ "crunchy",
+ "digest 0.9.0",
+ "subtle",
+]
+
+[[package]]
+name = "libsecp256k1-gen-ecmult"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3"
+dependencies = [
+ "libsecp256k1-core",
+]
+
+[[package]]
+name = "libsecp256k1-gen-genmult"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d"
+dependencies = [
+ "libsecp256k1-core",
+]
+
+[[package]]
+name = "light-poseidon"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee"
+dependencies = [
+ "ark-bn254",
+ "ark-ff",
+ "num-bigint",
+ "thiserror",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+
+[[package]]
+name = "memchr"
+version = "2.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c8640c5d730cb13ebd907d8d04b52f55ac9a2eec55b440c8892f40d56c76c1d"
+
+[[package]]
+name = "memmap2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "merlin"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d"
+dependencies = [
+ "byteorder",
+ "keccak",
+ "rand_core 0.6.4",
+ "zeroize",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0"
+dependencies = [
+ "autocfg",
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
+dependencies = [
+ "proc-macro-crate 3.1.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c"
+
+[[package]]
+name = "pbkdf2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd"
+dependencies = [
+ "crypto-mac",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "polyval"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "proc-macro-crate"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
+dependencies = [
+ "toml 0.5.11",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
+dependencies = [
+ "toml_edit 0.21.1",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.80"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56dea16b0a29e94408b9aa5e2940a4eedbd128a1ba20e8f7ae60fd3d465af0e"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "qstring"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "qualifier_attr"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom 0.1.16",
+ "libc",
+ "rand_chacha 0.2.2",
+ "rand_core 0.5.1",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom 0.1.16",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.14",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_xoshiro"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rayon"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
+dependencies = [
+ "bitflags 1.3.2",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "80af6f9131f277a45a3fba6ce8e2258037bb0477a67e610d3c1fe046ab31de47"
+
+[[package]]
+name = "ryu"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e86697c916019a8588c99b5fac3cead74ec0b4b819707a682fd4d23fa0ce1ba1"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "semver"
+version = "1.0.22"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca"
+
+[[package]]
+name = "serde"
+version = "1.0.197"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.197"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.115"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "12dc5c46daa8e9fdf4f5e71b6cf9a53f2487da0e86e55808e2d35539666497dd"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eb3622f419d1296904700073ea6cc23ad690adbd66f13ea683df73298736f0c1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_with"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe"
+dependencies = [
+ "serde",
+ "serde_with_macros",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "sha2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.9.0",
+ "opaque-debug",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha3"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
+dependencies = [
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "keccak",
+ "opaque-debug",
+]
+
+[[package]]
+name = "sha3"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
+dependencies = [
+ "digest 0.10.7",
+ "keccak",
+]
+
+[[package]]
+name = "signature"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "sized-chunks"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e"
+dependencies = [
+ "bitmaps",
+ "typenum",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "solana-frozen-abi"
+version = "1.18.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3b8177685ab2bc8cc8b3bf63aa1eaa0580d5af850ecefac323ca1c2473085d77"
+dependencies = [
+ "block-buffer 0.10.4",
+ "bs58 0.4.0",
+ "bv",
+ "either",
+ "generic-array",
+ "im",
+ "lazy_static",
+ "log",
+ "memmap2",
+ "rustc_version",
+ "serde",
+ "serde_bytes",
+ "serde_derive",
+ "sha2 0.10.8",
+ "solana-frozen-abi-macro",
+ "subtle",
+ "thiserror",
+]
+
+[[package]]
+name = "solana-frozen-abi-macro"
+version = "1.18.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a68241cad17b74c6034a68ba4890632d409a2c886e7bead9c1e1432befdb7c9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "solana-logger"
+version = "1.18.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea560989ef67ba4a1a0fd62a248721f1aa5bac8fa5ede9ccf4fe9ee484ccadf"
+dependencies = [
+ "env_logger",
+ "lazy_static",
+ "log",
+]
+
+[[package]]
+name = "solana-program"
+version = "1.18.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8bddf573103c890b4ab8f9a6641d4f969d4148bce9a451c263f4a62afa949fae"
+dependencies = [
+ "ark-bn254",
+ "ark-ec",
+ "ark-ff",
+ "ark-serialize",
+ "base64 0.21.7",
+ "bincode",
+ "bitflags 2.5.0",
+ "blake3",
+ "borsh 0.10.3",
+ "borsh 0.9.3",
+ "borsh 1.4.0",
+ "bs58 0.4.0",
+ "bv",
+ "bytemuck",
+ "cc",
+ "console_error_panic_hook",
+ "console_log",
+ "curve25519-dalek",
+ "getrandom 0.2.14",
+ "itertools",
+ "js-sys",
+ "lazy_static",
+ "libc",
+ "libsecp256k1",
+ "light-poseidon",
+ "log",
+ "memoffset",
+ "num-bigint",
+ "num-derive",
+ "num-traits",
+ "parking_lot",
+ "rand 0.8.5",
+ "rustc_version",
+ "rustversion",
+ "serde",
+ "serde_bytes",
+ "serde_derive",
+ "serde_json",
+ "sha2 0.10.8",
+ "sha3 0.10.8",
+ "solana-frozen-abi",
+ "solana-frozen-abi-macro",
+ "solana-sdk-macro",
+ "thiserror",
+ "tiny-bip39",
+ "wasm-bindgen",
+ "zeroize",
+]
+
+[[package]]
+name = "solana-sdk"
+version = "1.18.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08b24b06fa176209ddb2a2f8172a00b07e8a3b18229fbfc49f1eb3ce6ad11ff1"
+dependencies = [
+ "assert_matches",
+ "base64 0.21.7",
+ "bincode",
+ "bitflags 2.5.0",
+ "borsh 1.4.0",
+ "bs58 0.4.0",
+ "bytemuck",
+ "byteorder",
+ "chrono",
+ "derivation-path",
+ "digest 0.10.7",
+ "ed25519-dalek",
+ "ed25519-dalek-bip32",
+ "generic-array",
+ "hmac 0.12.1",
+ "itertools",
+ "js-sys",
+ "lazy_static",
+ "libsecp256k1",
+ "log",
+ "memmap2",
+ "num-derive",
+ "num-traits",
+ "num_enum",
+ "pbkdf2 0.11.0",
+ "qstring",
+ "qualifier_attr",
+ "rand 0.7.3",
+ "rand 0.8.5",
+ "rustc_version",
+ "rustversion",
+ "serde",
+ "serde_bytes",
+ "serde_derive",
+ "serde_json",
+ "serde_with",
+ "sha2 0.10.8",
+ "sha3 0.10.8",
+ "siphasher",
+ "solana-frozen-abi",
+ "solana-frozen-abi-macro",
+ "solana-logger",
+ "solana-program",
+ "solana-sdk-macro",
+ "thiserror",
+ "uriparse",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "solana-sdk-macro"
+version = "1.18.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "869483c05f18d37d4d95a08d9e05e00a4f76a8c8349aeedeee9ba2d013cbacde"
+dependencies = [
+ "bs58 0.4.0",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "solana-security-txt"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183"
+
+[[package]]
+name = "solana-zk-token-sdk"
+version = "1.18.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "459c27f7b954798677d8243aa53b8080cfb314ecfecbf8889a5a65c91ad11fee"
+dependencies = [
+ "aes-gcm-siv",
+ "base64 0.21.7",
+ "bincode",
+ "bytemuck",
+ "byteorder",
+ "curve25519-dalek",
+ "getrandom 0.1.16",
+ "itertools",
+ "lazy_static",
+ "merlin",
+ "num-derive",
+ "num-traits",
+ "rand 0.7.3",
+ "serde",
+ "serde_json",
+ "sha3 0.9.1",
+ "solana-program",
+ "solana-sdk",
+ "subtle",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
+name = "spl-associated-token-account"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2e688554bac5838217ffd1fab7845c573ff106b6336bf7d290db7c98d5a8efd"
+dependencies = [
+ "assert_matches",
+ "borsh 1.4.0",
+ "num-derive",
+ "num-traits",
+ "solana-program",
+ "spl-token",
+ "spl-token-2022",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-discriminator"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34d1814406e98b08c5cd02c1126f83fd407ad084adce0b05fda5730677822eac"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator-derive",
+]
+
+[[package]]
+name = "spl-discriminator-derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750"
+dependencies = [
+ "quote",
+ "spl-discriminator-syn",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "spl-discriminator-syn"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "sha2 0.10.8",
+ "syn 2.0.59",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-memo"
+version = "4.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58e9bae02de3405079a057fe244c867a08f92d48327d231fc60da831f94caf0a"
+dependencies = [
+ "solana-program",
+]
+
+[[package]]
+name = "spl-pod"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "046ce669f48cf2eca1ec518916d8725596bfb655beb1c74374cf71dc6cb773c9"
+dependencies = [
+ "borsh 1.4.0",
+ "bytemuck",
+ "solana-program",
+ "solana-zk-token-sdk",
+ "spl-program-error",
+]
+
+[[package]]
+name = "spl-program-error"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5528f4dfa2a905012007999526955c79162c09668c69ad3c3f2ddfbd0b2984a4"
+dependencies = [
+ "num-derive",
+ "num-traits",
+ "solana-program",
+ "spl-program-error-derive",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-program-error-derive"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "641aa3116b1d58481e921b5d41dafc26a67bd488cb288330dbde004641764dd4"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "sha2 0.10.8",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "spl-tlv-account-resolution"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cace91ba08984a41556efe49cbf2edca4db2f577b649da7827d3621161784bf8"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+ "spl-type-length-value",
+]
+
+[[package]]
+name = "spl-token"
+version = "4.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95ae123223633a389f95d1da9d49c2d0a50d499e7060b9624626a69e536ad2a4"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "num-derive",
+ "num-traits",
+ "num_enum",
+ "solana-program",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-token-2022"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5412f99ae7ee6e0afde00defaa354e6228e47e30c0e3adf553e2e01e6abb584"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "num-derive",
+ "num-traits",
+ "num_enum",
+ "solana-program",
+ "solana-security-txt",
+ "solana-zk-token-sdk",
+ "spl-memo",
+ "spl-pod",
+ "spl-token",
+ "spl-token-group-interface",
+ "spl-token-metadata-interface",
+ "spl-transfer-hook-interface",
+ "spl-type-length-value",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-token-group-interface"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d419b5cfa3ee8e0f2386fd7e02a33b3ec8a7db4a9c7064a2ea24849dc4a273b6"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+]
+
+[[package]]
+name = "spl-token-metadata-interface"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30179c47e93625680dabb620c6e7931bd12d62af390f447bc7beb4a3a9b5feee"
+dependencies = [
+ "borsh 1.4.0",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+ "spl-type-length-value",
+]
+
+[[package]]
+name = "spl-transfer-hook-interface"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66a98359769cd988f7b35c02558daa56d496a7e3bd8626e61f90a7c757eedb9b"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+ "spl-tlv-account-resolution",
+ "spl-type-length-value",
+]
+
+[[package]]
+name = "spl-type-length-value"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "422ce13429dbd41d2cee8a73931c05fda0b0c8ca156a8b0c19445642550bb61a"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+]
+
+[[package]]
+name = "strsim"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623"
+
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.59"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4a6531ffc7b071655e4ce2e04bd464c4830bb585a61cabb96cf808f05172615a"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "03468839009160513471e86a034bb2c5c0e4baae3b43f79ffc55c4a5427b3297"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.58"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c61f3ba182994efc43764a46c018c347bc492c79f024e705f46567b418f6d4f7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "tiny-bip39"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d"
+dependencies = [
+ "anyhow",
+ "hmac 0.8.1",
+ "once_cell",
+ "pbkdf2 0.4.0",
+ "rand 0.7.3",
+ "rustc-hash",
+ "sha2 0.9.9",
+ "thiserror",
+ "unicode-normalization",
+ "wasm-bindgen",
+ "zeroize",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e9dd1545e8208b4a5af1aa9bbd0b4cf7e9ea08fabc5d0a5c67fcaafa17433aa3"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit 0.22.9",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e40bb779c5187258fd7aad0eb68cb8706a0a81fa712fbea808ab43c4b8374c4"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow 0.6.6",
+]
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+
+[[package]]
+name = "universal-hash"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
+dependencies = [
+ "generic-array",
+ "subtle",
+]
+
+[[package]]
+name = "uriparse"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff"
+dependencies = [
+ "fnv",
+ "lazy_static",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+
+[[package]]
+name = "web-sys"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596"
+dependencies = [
+ "winapi",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-targets"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.48.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538"
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winnow"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f0c976aaaa0e1f90dbb21e9587cdaf1d9679a1cde8875c0d6bd83ab96a208352"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.32"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.59",
+]
diff --git a/tests/bench/locks/0.30.1.lock b/tests/bench/locks/0.30.1.lock
new file mode 100644
index 0000000000..ac2e1327f1
--- /dev/null
+++ b/tests/bench/locks/0.30.1.lock
@@ -0,0 +1,2682 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "aead"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "aes"
+version = "0.7.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8"
+dependencies = [
+ "cfg-if",
+ "cipher",
+ "cpufeatures",
+ "opaque-debug",
+]
+
+[[package]]
+name = "aes-gcm-siv"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc"
+dependencies = [
+ "aead",
+ "aes",
+ "cipher",
+ "ctr",
+ "polyval",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "ahash"
+version = "0.7.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9"
+dependencies = [
+ "getrandom 0.2.15",
+ "once_cell",
+ "version_check",
+]
+
+[[package]]
+name = "ahash"
+version = "0.8.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89da841a80418a9b391ebaea17f5c112ffaaa96f621d2c285b5174da76b9011"
+dependencies = [
+ "cfg-if",
+ "once_cell",
+ "version_check",
+ "zerocopy",
+]
+
+[[package]]
+name = "aho-corasick"
+version = "1.1.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "anchor-attribute-access-control"
+version = "0.30.1"
+dependencies = [
+ "anchor-syn",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-account"
+version = "0.30.1"
+dependencies = [
+ "anchor-syn",
+ "bs58 0.5.1",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-constant"
+version = "0.30.1"
+dependencies = [
+ "anchor-syn",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-error"
+version = "0.30.1"
+dependencies = [
+ "anchor-syn",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-event"
+version = "0.30.1"
+dependencies = [
+ "anchor-syn",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-attribute-program"
+version = "0.30.1"
+dependencies = [
+ "anchor-lang-idl",
+ "anchor-syn",
+ "anyhow",
+ "bs58 0.5.1",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "serde_json",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-derive-accounts"
+version = "0.30.1"
+dependencies = [
+ "anchor-syn",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-derive-serde"
+version = "0.30.1"
+dependencies = [
+ "anchor-syn",
+ "borsh-derive-internal 0.10.3",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-derive-space"
+version = "0.30.1"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "anchor-lang"
+version = "0.30.1"
+dependencies = [
+ "anchor-attribute-access-control",
+ "anchor-attribute-account",
+ "anchor-attribute-constant",
+ "anchor-attribute-error",
+ "anchor-attribute-event",
+ "anchor-attribute-program",
+ "anchor-derive-accounts",
+ "anchor-derive-serde",
+ "anchor-derive-space",
+ "anchor-lang-idl",
+ "arrayref",
+ "base64 0.21.7",
+ "bincode",
+ "borsh 0.10.3",
+ "bytemuck",
+ "getrandom 0.2.15",
+ "solana-program",
+ "thiserror",
+]
+
+[[package]]
+name = "anchor-lang-idl"
+version = "0.1.1"
+dependencies = [
+ "anchor-lang-idl-spec",
+ "anyhow",
+ "heck",
+ "regex",
+ "serde",
+ "serde_json",
+ "sha2 0.10.8",
+]
+
+[[package]]
+name = "anchor-lang-idl-spec"
+version = "0.1.0"
+dependencies = [
+ "anyhow",
+ "serde",
+]
+
+[[package]]
+name = "anchor-spl"
+version = "0.30.1"
+dependencies = [
+ "anchor-lang",
+ "spl-associated-token-account",
+ "spl-pod",
+ "spl-token",
+ "spl-token-2022",
+ "spl-token-group-interface",
+ "spl-token-metadata-interface",
+]
+
+[[package]]
+name = "anchor-syn"
+version = "0.30.1"
+dependencies = [
+ "anyhow",
+ "bs58 0.5.1",
+ "cargo_toml",
+ "heck",
+ "proc-macro2",
+ "quote",
+ "serde",
+ "serde_json",
+ "sha2 0.10.8",
+ "syn 1.0.109",
+ "thiserror",
+]
+
+[[package]]
+name = "anyhow"
+version = "1.0.86"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da"
+
+[[package]]
+name = "ark-bn254"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f"
+dependencies = [
+ "ark-ec",
+ "ark-ff",
+ "ark-std",
+]
+
+[[package]]
+name = "ark-ec"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba"
+dependencies = [
+ "ark-ff",
+ "ark-poly",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "hashbrown 0.13.2",
+ "itertools",
+ "num-traits",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba"
+dependencies = [
+ "ark-ff-asm",
+ "ark-ff-macros",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "digest 0.10.7",
+ "itertools",
+ "num-bigint",
+ "num-traits",
+ "paste",
+ "rustc_version",
+ "zeroize",
+]
+
+[[package]]
+name = "ark-ff-asm"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348"
+dependencies = [
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-ff-macros"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565"
+dependencies = [
+ "num-bigint",
+ "num-traits",
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-poly"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf"
+dependencies = [
+ "ark-ff",
+ "ark-serialize",
+ "ark-std",
+ "derivative",
+ "hashbrown 0.13.2",
+]
+
+[[package]]
+name = "ark-serialize"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5"
+dependencies = [
+ "ark-serialize-derive",
+ "ark-std",
+ "digest 0.10.7",
+ "num-bigint",
+]
+
+[[package]]
+name = "ark-serialize-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "ark-std"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94893f1e0c6eeab764ade8dc4c0db24caf4fe7cbbaafc0eba0a9030f447b5185"
+dependencies = [
+ "num-traits",
+ "rand 0.8.5",
+]
+
+[[package]]
+name = "arrayref"
+version = "0.3.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545"
+
+[[package]]
+name = "arrayvec"
+version = "0.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711"
+
+[[package]]
+name = "assert_matches"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9b34d609dfbaf33d6889b2b7106d3ca345eacad44200913df5ba02bfd31d2ba9"
+
+[[package]]
+name = "atty"
+version = "0.2.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8"
+dependencies = [
+ "hermit-abi",
+ "libc",
+ "winapi",
+]
+
+[[package]]
+name = "autocfg"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
+
+[[package]]
+name = "base64"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3441f0f7b02788e948e47f457ca01f1d7e6d92c693bc132c22b087d3141c03ff"
+
+[[package]]
+name = "base64"
+version = "0.21.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
+
+[[package]]
+name = "bench"
+version = "0.1.0"
+dependencies = [
+ "anchor-lang",
+ "anchor-spl",
+]
+
+[[package]]
+name = "bincode"
+version = "1.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bitflags"
+version = "2.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "bitmaps"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "031043d04099746d8db04daf1fa424b2bc8bd69d92b25962dcde24da39ab64a2"
+dependencies = [
+ "typenum",
+]
+
+[[package]]
+name = "blake3"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30cca6d3674597c30ddf2c587bf8d9d65c9a84d2326d941cc79c9842dfe0ef52"
+dependencies = [
+ "arrayref",
+ "arrayvec",
+ "cc",
+ "cfg-if",
+ "constant_time_eq",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"
+dependencies = [
+ "block-padding",
+ "generic-array",
+]
+
+[[package]]
+name = "block-buffer"
+version = "0.10.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "block-padding"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8d696c370c750c948ada61c69a0ee2cbbb9c50b1019ddb86d9317157a99c2cae"
+
+[[package]]
+name = "borsh"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa"
+dependencies = [
+ "borsh-derive 0.9.3",
+ "hashbrown 0.11.2",
+]
+
+[[package]]
+name = "borsh"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b"
+dependencies = [
+ "borsh-derive 0.10.3",
+ "hashbrown 0.13.2",
+]
+
+[[package]]
+name = "borsh"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a6362ed55def622cddc70a4746a68554d7b687713770de539e59a739b249f8ed"
+dependencies = [
+ "borsh-derive 1.5.1",
+ "cfg_aliases",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775"
+dependencies = [
+ "borsh-derive-internal 0.9.3",
+ "borsh-schema-derive-internal 0.9.3",
+ "proc-macro-crate 0.1.5",
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7"
+dependencies = [
+ "borsh-derive-internal 0.10.3",
+ "borsh-schema-derive-internal 0.10.3",
+ "proc-macro-crate 0.1.5",
+ "proc-macro2",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-derive"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c3ef8005764f53cd4dca619f5bf64cafd4664dada50ece25e4d81de54c80cc0b"
+dependencies = [
+ "once_cell",
+ "proc-macro-crate 3.1.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+ "syn_derive",
+]
+
+[[package]]
+name = "borsh-derive-internal"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-derive-internal"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "afb438156919598d2c7bad7e1c0adf3d26ed3840dbc010db1a882a65583ca2fb"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-schema-derive-internal"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "borsh-schema-derive-internal"
+version = "0.10.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "bs58"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "771fe0050b883fcc3ea2359b1a96bcfbc090b7116eae7c3c512c7a083fdf23d3"
+
+[[package]]
+name = "bs58"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bf88ba1141d185c399bee5288d850d63b8369520c1eafc32a0430b5b6c287bf4"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "bumpalo"
+version = "3.16.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c"
+
+[[package]]
+name = "bv"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8834bb1d8ee5dc048ee3124f2c7c1afcc6bc9aed03f11e9dfd8c69470a5db340"
+dependencies = [
+ "feature-probe",
+ "serde",
+]
+
+[[package]]
+name = "bytemuck"
+version = "1.16.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b236fc92302c97ed75b38da1f4917b5cdda4984745740f153a5d3059e48d725e"
+dependencies = [
+ "bytemuck_derive",
+]
+
+[[package]]
+name = "bytemuck_derive"
+version = "1.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1ee891b04274a59bd38b412188e24b849617b2e45a0fd8d057deb63e7403761b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "byteorder"
+version = "1.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
+
+[[package]]
+name = "cargo_toml"
+version = "0.19.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a98356df42a2eb1bd8f1793ae4ee4de48e384dd974ce5eac8eee802edb7492be"
+dependencies = [
+ "serde",
+ "toml 0.8.14",
+]
+
+[[package]]
+name = "cc"
+version = "1.0.99"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "96c51067fd44124faa7f870b4b1c969379ad32b2ba805aa959430ceaa384f695"
+dependencies = [
+ "jobserver",
+ "libc",
+ "once_cell",
+]
+
+[[package]]
+name = "cfg-if"
+version = "1.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
+
+[[package]]
+name = "cfg_aliases"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724"
+
+[[package]]
+name = "chrono"
+version = "0.4.38"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a21f936df1771bf62b77f047b726c4625ff2e8aa607c01ec06e5a05bd8463401"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "cipher"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "console_error_panic_hook"
+version = "0.1.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "console_log"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e89f72f65e8501878b8a004d5a1afb780987e2ce2b4532c562e367a72c57499f"
+dependencies = [
+ "log",
+ "web-sys",
+]
+
+[[package]]
+name = "constant_time_eq"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2"
+
+[[package]]
+name = "cpufeatures"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "crossbeam-deque"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d"
+dependencies = [
+ "crossbeam-epoch",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-epoch"
+version = "0.9.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e"
+dependencies = [
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "crossbeam-utils"
+version = "0.8.20"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
+
+[[package]]
+name = "crunchy"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7"
+
+[[package]]
+name = "crypto-common"
+version = "0.1.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
+dependencies = [
+ "generic-array",
+ "typenum",
+]
+
+[[package]]
+name = "crypto-mac"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b584a330336237c1eecd3e94266efb216c56ed91225d634cb2991c5f3fd1aeab"
+dependencies = [
+ "generic-array",
+ "subtle",
+]
+
+[[package]]
+name = "ctr"
+version = "0.8.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea"
+dependencies = [
+ "cipher",
+]
+
+[[package]]
+name = "curve25519-dalek"
+version = "3.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0"
+dependencies = [
+ "byteorder",
+ "digest 0.9.0",
+ "rand_core 0.5.1",
+ "serde",
+ "subtle",
+ "zeroize",
+]
+
+[[package]]
+name = "darling"
+version = "0.20.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83b2eb4d90d12bdda5ed17de686c2acb4c57914f8f921b8da7e112b5a36f3fe1"
+dependencies = [
+ "darling_core",
+ "darling_macro",
+]
+
+[[package]]
+name = "darling_core"
+version = "0.20.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "622687fe0bac72a04e5599029151f5796111b90f1baaa9b544d807a5e31cd120"
+dependencies = [
+ "fnv",
+ "ident_case",
+ "proc-macro2",
+ "quote",
+ "strsim",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "darling_macro"
+version = "0.20.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "733cabb43482b1a1b53eee8583c2b9e8684d592215ea83efd305dd31bc2f0178"
+dependencies = [
+ "darling_core",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "derivation-path"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6e5c37193a1db1d8ed868c03ec7b152175f26160a5b740e5e484143877e0adf0"
+
+[[package]]
+name = "derivative"
+version = "2.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fcc3dd5e9e9c0b295d6e1e4d811fb6f157d5ffd784b8d202fc62eac8035a770b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
+[[package]]
+name = "digest"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"
+dependencies = [
+ "generic-array",
+]
+
+[[package]]
+name = "digest"
+version = "0.10.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
+dependencies = [
+ "block-buffer 0.10.4",
+ "crypto-common",
+ "subtle",
+]
+
+[[package]]
+name = "ed25519"
+version = "1.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7"
+dependencies = [
+ "signature",
+]
+
+[[package]]
+name = "ed25519-dalek"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d"
+dependencies = [
+ "curve25519-dalek",
+ "ed25519",
+ "rand 0.7.3",
+ "serde",
+ "sha2 0.9.9",
+ "zeroize",
+]
+
+[[package]]
+name = "ed25519-dalek-bip32"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908"
+dependencies = [
+ "derivation-path",
+ "ed25519-dalek",
+ "hmac 0.12.1",
+ "sha2 0.10.8",
+]
+
+[[package]]
+name = "either"
+version = "1.12.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3dca9240753cf90908d7e4aac30f630662b02aebaa1b58a3cadabdb23385b58b"
+
+[[package]]
+name = "env_logger"
+version = "0.9.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a12e6657c4c97ebab115a42dcee77225f7f482cdd841cf7088c657a42e9e00e7"
+dependencies = [
+ "atty",
+ "humantime",
+ "log",
+ "regex",
+ "termcolor",
+]
+
+[[package]]
+name = "equivalent"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5"
+
+[[package]]
+name = "feature-probe"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da"
+
+[[package]]
+name = "fnv"
+version = "1.0.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1"
+
+[[package]]
+name = "generic-array"
+version = "0.14.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
+dependencies = [
+ "serde",
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.1.16"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.9.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "getrandom"
+version = "0.2.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7"
+dependencies = [
+ "cfg-if",
+ "js-sys",
+ "libc",
+ "wasi 0.11.0+wasi-snapshot-preview1",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.11.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e"
+dependencies = [
+ "ahash 0.7.8",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
+dependencies = [
+ "ahash 0.8.11",
+]
+
+[[package]]
+name = "hashbrown"
+version = "0.14.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1"
+
+[[package]]
+name = "heck"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d621efb26863f0e9924c6ac577e8275e5e6b77455db64ffa6c65c904e9e132c"
+dependencies = [
+ "unicode-segmentation",
+]
+
+[[package]]
+name = "hermit-abi"
+version = "0.1.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "hmac"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "126888268dcc288495a26bf004b38c5fdbb31682f992c84ceb046a1f0fe38840"
+dependencies = [
+ "crypto-mac",
+ "digest 0.9.0",
+]
+
+[[package]]
+name = "hmac"
+version = "0.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "hmac-drbg"
+version = "0.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "17ea0a1394df5b6574da6e0c1ade9e78868c9fb0a4e5ef4428e32da4676b85b1"
+dependencies = [
+ "digest 0.9.0",
+ "generic-array",
+ "hmac 0.8.1",
+]
+
+[[package]]
+name = "humantime"
+version = "2.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4"
+
+[[package]]
+name = "ident_case"
+version = "1.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39"
+
+[[package]]
+name = "im"
+version = "15.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9"
+dependencies = [
+ "bitmaps",
+ "rand_core 0.6.4",
+ "rand_xoshiro",
+ "rayon",
+ "serde",
+ "sized-chunks",
+ "typenum",
+ "version_check",
+]
+
+[[package]]
+name = "indexmap"
+version = "2.2.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
+dependencies = [
+ "equivalent",
+ "hashbrown 0.14.5",
+]
+
+[[package]]
+name = "itertools"
+version = "0.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b0fd2260e829bddf4cb6ea802289de2f86d6a7a690192fbe91b3f46e0f2c8473"
+dependencies = [
+ "either",
+]
+
+[[package]]
+name = "itoa"
+version = "1.0.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
+
+[[package]]
+name = "jobserver"
+version = "0.1.31"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d2b099aaa34a9751c5bf0878add70444e1ed2dd73f347be99003d4577277de6e"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "js-sys"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "29c15563dc2726973df627357ce0c9ddddbea194836909d655df6a75d2cf296d"
+dependencies = [
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "keccak"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654"
+dependencies = [
+ "cpufeatures",
+]
+
+[[package]]
+name = "lazy_static"
+version = "1.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
+
+[[package]]
+name = "libc"
+version = "0.2.155"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c"
+
+[[package]]
+name = "libsecp256k1"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c9d220bc1feda2ac231cb78c3d26f27676b8cf82c96971f7aeef3d0cf2797c73"
+dependencies = [
+ "arrayref",
+ "base64 0.12.3",
+ "digest 0.9.0",
+ "hmac-drbg",
+ "libsecp256k1-core",
+ "libsecp256k1-gen-ecmult",
+ "libsecp256k1-gen-genmult",
+ "rand 0.7.3",
+ "serde",
+ "sha2 0.9.9",
+ "typenum",
+]
+
+[[package]]
+name = "libsecp256k1-core"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d0f6ab710cec28cef759c5f18671a27dae2a5f952cdaaee1d8e2908cb2478a80"
+dependencies = [
+ "crunchy",
+ "digest 0.9.0",
+ "subtle",
+]
+
+[[package]]
+name = "libsecp256k1-gen-ecmult"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ccab96b584d38fac86a83f07e659f0deafd0253dc096dab5a36d53efe653c5c3"
+dependencies = [
+ "libsecp256k1-core",
+]
+
+[[package]]
+name = "libsecp256k1-gen-genmult"
+version = "0.2.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "67abfe149395e3aa1c48a2beb32b068e2334402df8181f818d3aee2b304c4f5d"
+dependencies = [
+ "libsecp256k1-core",
+]
+
+[[package]]
+name = "light-poseidon"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee"
+dependencies = [
+ "ark-bn254",
+ "ark-ff",
+ "num-bigint",
+ "thiserror",
+]
+
+[[package]]
+name = "lock_api"
+version = "0.4.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
+dependencies = [
+ "autocfg",
+ "scopeguard",
+]
+
+[[package]]
+name = "log"
+version = "0.4.21"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
+
+[[package]]
+name = "memchr"
+version = "2.7.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3"
+
+[[package]]
+name = "memmap2"
+version = "0.5.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83faa42c0a078c393f6b29d5db232d8be22776a891f8f56e5284faee4a20b327"
+dependencies = [
+ "libc",
+]
+
+[[package]]
+name = "memoffset"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "merlin"
+version = "3.0.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58c38e2799fc0978b65dfff8023ec7843e2330bb462f19198840b34b6582397d"
+dependencies = [
+ "byteorder",
+ "keccak",
+ "rand_core 0.6.4",
+ "zeroize",
+]
+
+[[package]]
+name = "num-bigint"
+version = "0.4.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c165a9ab64cf766f73521c0dd2cfdff64f488b8f0b3e621face3462d3db536d7"
+dependencies = [
+ "num-integer",
+ "num-traits",
+]
+
+[[package]]
+name = "num-derive"
+version = "0.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "num-integer"
+version = "0.1.46"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f"
+dependencies = [
+ "num-traits",
+]
+
+[[package]]
+name = "num-traits"
+version = "0.2.19"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
+dependencies = [
+ "autocfg",
+]
+
+[[package]]
+name = "num_enum"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845"
+dependencies = [
+ "num_enum_derive",
+]
+
+[[package]]
+name = "num_enum_derive"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "681030a937600a36906c185595136d26abfebb4aa9c65701cefcaf8578bb982b"
+dependencies = [
+ "proc-macro-crate 3.1.0",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "once_cell"
+version = "1.19.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+
+[[package]]
+name = "opaque-debug"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381"
+
+[[package]]
+name = "parking_lot"
+version = "0.12.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f1bf18183cf54e8d6059647fc3063646a1801cf30896933ec2311622cc4b9a27"
+dependencies = [
+ "lock_api",
+ "parking_lot_core",
+]
+
+[[package]]
+name = "parking_lot_core"
+version = "0.9.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1e401f977ab385c9e4e3ab30627d6f26d00e2c73eef317493c4ec6d468726cf8"
+dependencies = [
+ "cfg-if",
+ "libc",
+ "redox_syscall",
+ "smallvec",
+ "windows-targets",
+]
+
+[[package]]
+name = "paste"
+version = "1.0.15"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a"
+
+[[package]]
+name = "pbkdf2"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd"
+dependencies = [
+ "crypto-mac",
+]
+
+[[package]]
+name = "pbkdf2"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "83a0692ec44e4cf1ef28ca317f14f8f07da2d95ec3fa01f86e4467b725e60917"
+dependencies = [
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "percent-encoding"
+version = "2.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e"
+
+[[package]]
+name = "polyval"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "opaque-debug",
+ "universal-hash",
+]
+
+[[package]]
+name = "ppv-lite86"
+version = "0.2.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
+
+[[package]]
+name = "proc-macro-crate"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785"
+dependencies = [
+ "toml 0.5.11",
+]
+
+[[package]]
+name = "proc-macro-crate"
+version = "3.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284"
+dependencies = [
+ "toml_edit 0.21.1",
+]
+
+[[package]]
+name = "proc-macro-error"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"
+dependencies = [
+ "proc-macro-error-attr",
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro-error-attr"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "version_check",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.85"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "22244ce15aa966053a896d1accb3a6e68469b97c7f33f284b99f0d576879fc23"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "qstring"
+version = "0.7.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d464fae65fff2680baf48019211ce37aaec0c78e9264c84a3e484717f965104e"
+dependencies = [
+ "percent-encoding",
+]
+
+[[package]]
+name = "qualifier_attr"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.36"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "rand"
+version = "0.7.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03"
+dependencies = [
+ "getrandom 0.1.16",
+ "libc",
+ "rand_chacha 0.2.2",
+ "rand_core 0.5.1",
+ "rand_hc",
+]
+
+[[package]]
+name = "rand"
+version = "0.8.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
+dependencies = [
+ "libc",
+ "rand_chacha 0.3.1",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_chacha"
+version = "0.3.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
+dependencies = [
+ "ppv-lite86",
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19"
+dependencies = [
+ "getrandom 0.1.16",
+]
+
+[[package]]
+name = "rand_core"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
+dependencies = [
+ "getrandom 0.2.15",
+]
+
+[[package]]
+name = "rand_hc"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c"
+dependencies = [
+ "rand_core 0.5.1",
+]
+
+[[package]]
+name = "rand_xoshiro"
+version = "0.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f97cdb2a36ed4183de61b2f824cc45c9f1037f28afe0a322e9fff4c108b5aaa"
+dependencies = [
+ "rand_core 0.6.4",
+]
+
+[[package]]
+name = "rayon"
+version = "1.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
+dependencies = [
+ "either",
+ "rayon-core",
+]
+
+[[package]]
+name = "rayon-core"
+version = "1.12.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
+dependencies = [
+ "crossbeam-deque",
+ "crossbeam-utils",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.5.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c82cf8cff14456045f55ec4241383baeff27af886adb72ffb2162f99911de0fd"
+dependencies = [
+ "bitflags",
+]
+
+[[package]]
+name = "regex"
+version = "1.10.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "b91213439dad192326a0d7c6ee3955910425f441d7038e0d6933b0aec5c4517f"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-automata",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-automata"
+version = "0.4.7"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+dependencies = [
+ "aho-corasick",
+ "memchr",
+ "regex-syntax",
+]
+
+[[package]]
+name = "regex-syntax"
+version = "0.8.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+
+[[package]]
+name = "rustc-hash"
+version = "1.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
+
+[[package]]
+name = "rustc_version"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366"
+dependencies = [
+ "semver",
+]
+
+[[package]]
+name = "rustversion"
+version = "1.0.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "955d28af4278de8121b7ebeb796b6a45735dc01436d898801014aced2773a3d6"
+
+[[package]]
+name = "ryu"
+version = "1.0.18"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f"
+
+[[package]]
+name = "scopeguard"
+version = "1.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
+
+[[package]]
+name = "semver"
+version = "1.0.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "61697e0a1c7e512e84a621326239844a24d8207b4669b41bc18b32ea5cbf988b"
+
+[[package]]
+name = "serde"
+version = "1.0.203"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094"
+dependencies = [
+ "serde_derive",
+]
+
+[[package]]
+name = "serde_bytes"
+version = "0.11.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_derive"
+version = "1.0.203"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "serde_json"
+version = "1.0.117"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "455182ea6142b14f93f4bc5320a2b31c1f266b66a4a5c858b013302a5d8cbfc3"
+dependencies = [
+ "itoa",
+ "ryu",
+ "serde",
+]
+
+[[package]]
+name = "serde_spanned"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79e674e01f999af37c49f70a6ede167a8a60b2503e56c5599532a65baa5969a0"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "serde_with"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "07ff71d2c147a7b57362cead5e22f772cd52f6ab31cfcd9edcd7f6aeb2a0afbe"
+dependencies = [
+ "serde",
+ "serde_with_macros",
+]
+
+[[package]]
+name = "serde_with_macros"
+version = "2.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "881b6f881b17d13214e5d494c939ebab463d01264ce1811e9d4ac3a882e7695f"
+dependencies = [
+ "darling",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "sha2"
+version = "0.9.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800"
+dependencies = [
+ "block-buffer 0.9.0",
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.9.0",
+ "opaque-debug",
+]
+
+[[package]]
+name = "sha2"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8"
+dependencies = [
+ "cfg-if",
+ "cpufeatures",
+ "digest 0.10.7",
+]
+
+[[package]]
+name = "sha3"
+version = "0.9.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f81199417d4e5de3f04b1e871023acea7389672c4135918f05aa9cbf2f2fa809"
+dependencies = [
+ "block-buffer 0.9.0",
+ "digest 0.9.0",
+ "keccak",
+ "opaque-debug",
+]
+
+[[package]]
+name = "sha3"
+version = "0.10.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60"
+dependencies = [
+ "digest 0.10.7",
+ "keccak",
+]
+
+[[package]]
+name = "signature"
+version = "1.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c"
+
+[[package]]
+name = "siphasher"
+version = "0.3.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d"
+
+[[package]]
+name = "sized-chunks"
+version = "0.6.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "16d69225bde7a69b235da73377861095455d298f2b970996eec25ddbb42b3d1e"
+dependencies = [
+ "bitmaps",
+ "typenum",
+]
+
+[[package]]
+name = "smallvec"
+version = "1.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3c5e1a9a646d36c3599cd173a41282daf47c44583ad367b8e6837255952e5c67"
+
+[[package]]
+name = "solana-frozen-abi"
+version = "1.18.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4867f66e9527fa44451c861c1dc6d9b2a7c7a668d7c6a297cdefbe39f4395b33"
+dependencies = [
+ "block-buffer 0.10.4",
+ "bs58 0.4.0",
+ "bv",
+ "either",
+ "generic-array",
+ "im",
+ "lazy_static",
+ "log",
+ "memmap2",
+ "rustc_version",
+ "serde",
+ "serde_bytes",
+ "serde_derive",
+ "sha2 0.10.8",
+ "solana-frozen-abi-macro",
+ "subtle",
+ "thiserror",
+]
+
+[[package]]
+name = "solana-frozen-abi-macro"
+version = "1.18.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "168f24d97347b85f05192df58d6be3e3047a4aadc4001bc1b9e711a5ec878eea"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "rustc_version",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "solana-logger"
+version = "1.18.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0511082fc62f2d086520fff5aa1917c389d8c840930c08ad255ae05952c08a2"
+dependencies = [
+ "env_logger",
+ "lazy_static",
+ "log",
+]
+
+[[package]]
+name = "solana-program"
+version = "1.18.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "2bc5a636dc75e5c25651e34f7a36afc9ae60d38166687c5b0375abb580ac81a2"
+dependencies = [
+ "ark-bn254",
+ "ark-ec",
+ "ark-ff",
+ "ark-serialize",
+ "base64 0.21.7",
+ "bincode",
+ "bitflags",
+ "blake3",
+ "borsh 0.10.3",
+ "borsh 0.9.3",
+ "borsh 1.5.1",
+ "bs58 0.4.0",
+ "bv",
+ "bytemuck",
+ "cc",
+ "console_error_panic_hook",
+ "console_log",
+ "curve25519-dalek",
+ "getrandom 0.2.15",
+ "itertools",
+ "js-sys",
+ "lazy_static",
+ "libc",
+ "libsecp256k1",
+ "light-poseidon",
+ "log",
+ "memoffset",
+ "num-bigint",
+ "num-derive",
+ "num-traits",
+ "parking_lot",
+ "rand 0.8.5",
+ "rustc_version",
+ "rustversion",
+ "serde",
+ "serde_bytes",
+ "serde_derive",
+ "serde_json",
+ "sha2 0.10.8",
+ "sha3 0.10.8",
+ "solana-frozen-abi",
+ "solana-frozen-abi-macro",
+ "solana-sdk-macro",
+ "thiserror",
+ "tiny-bip39",
+ "wasm-bindgen",
+ "zeroize",
+]
+
+[[package]]
+name = "solana-sdk"
+version = "1.18.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "df43d3a1e1637397ab43cbc216a5a8f977ec8a3cc3f3ae8c3851c83a3255dbcf"
+dependencies = [
+ "assert_matches",
+ "base64 0.21.7",
+ "bincode",
+ "bitflags",
+ "borsh 1.5.1",
+ "bs58 0.4.0",
+ "bytemuck",
+ "byteorder",
+ "chrono",
+ "derivation-path",
+ "digest 0.10.7",
+ "ed25519-dalek",
+ "ed25519-dalek-bip32",
+ "generic-array",
+ "hmac 0.12.1",
+ "itertools",
+ "js-sys",
+ "lazy_static",
+ "libsecp256k1",
+ "log",
+ "memmap2",
+ "num-derive",
+ "num-traits",
+ "num_enum",
+ "pbkdf2 0.11.0",
+ "qstring",
+ "qualifier_attr",
+ "rand 0.7.3",
+ "rand 0.8.5",
+ "rustc_version",
+ "rustversion",
+ "serde",
+ "serde_bytes",
+ "serde_derive",
+ "serde_json",
+ "serde_with",
+ "sha2 0.10.8",
+ "sha3 0.10.8",
+ "siphasher",
+ "solana-frozen-abi",
+ "solana-frozen-abi-macro",
+ "solana-logger",
+ "solana-program",
+ "solana-sdk-macro",
+ "thiserror",
+ "uriparse",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "solana-sdk-macro"
+version = "1.18.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "86c76414183a325038ff020b22c07d1e9d2da0703ddc0244acfed37ee2921d96"
+dependencies = [
+ "bs58 0.4.0",
+ "proc-macro2",
+ "quote",
+ "rustversion",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "solana-security-txt"
+version = "1.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183"
+
+[[package]]
+name = "solana-zk-token-sdk"
+version = "1.18.17"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "513407f88394e437b4ff5aad892bc5bf51a655ae2401e6e63549734d3695c46f"
+dependencies = [
+ "aes-gcm-siv",
+ "base64 0.21.7",
+ "bincode",
+ "bytemuck",
+ "byteorder",
+ "curve25519-dalek",
+ "getrandom 0.1.16",
+ "itertools",
+ "lazy_static",
+ "merlin",
+ "num-derive",
+ "num-traits",
+ "rand 0.7.3",
+ "serde",
+ "serde_json",
+ "sha3 0.9.1",
+ "solana-program",
+ "solana-sdk",
+ "subtle",
+ "thiserror",
+ "zeroize",
+]
+
+[[package]]
+name = "spl-associated-token-account"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a2e688554bac5838217ffd1fab7845c573ff106b6336bf7d290db7c98d5a8efd"
+dependencies = [
+ "assert_matches",
+ "borsh 1.5.1",
+ "num-derive",
+ "num-traits",
+ "solana-program",
+ "spl-token",
+ "spl-token-2022",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-discriminator"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "34d1814406e98b08c5cd02c1126f83fd407ad084adce0b05fda5730677822eac"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator-derive",
+]
+
+[[package]]
+name = "spl-discriminator-derive"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750"
+dependencies = [
+ "quote",
+ "spl-discriminator-syn",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "spl-discriminator-syn"
+version = "0.2.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8c1f05593b7ca9eac7caca309720f2eafb96355e037e6d373b909a80fe7b69b9"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "sha2 0.10.8",
+ "syn 2.0.66",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-memo"
+version = "4.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "58e9bae02de3405079a057fe244c867a08f92d48327d231fc60da831f94caf0a"
+dependencies = [
+ "solana-program",
+]
+
+[[package]]
+name = "spl-pod"
+version = "0.2.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "046ce669f48cf2eca1ec518916d8725596bfb655beb1c74374cf71dc6cb773c9"
+dependencies = [
+ "borsh 1.5.1",
+ "bytemuck",
+ "solana-program",
+ "solana-zk-token-sdk",
+ "spl-program-error",
+]
+
+[[package]]
+name = "spl-program-error"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49065093ea91f57b9b2bd81493ff705e2ad4e64507a07dbc02b085778e02770e"
+dependencies = [
+ "num-derive",
+ "num-traits",
+ "solana-program",
+ "spl-program-error-derive",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-program-error-derive"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "sha2 0.10.8",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "spl-tlv-account-resolution"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cace91ba08984a41556efe49cbf2edca4db2f577b649da7827d3621161784bf8"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+ "spl-type-length-value",
+]
+
+[[package]]
+name = "spl-token"
+version = "4.0.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "95ae123223633a389f95d1da9d49c2d0a50d499e7060b9624626a69e536ad2a4"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "num-derive",
+ "num-traits",
+ "num_enum",
+ "solana-program",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-token-2022"
+version = "3.0.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e5412f99ae7ee6e0afde00defaa354e6228e47e30c0e3adf553e2e01e6abb584"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "num-derive",
+ "num-traits",
+ "num_enum",
+ "solana-program",
+ "solana-security-txt",
+ "solana-zk-token-sdk",
+ "spl-memo",
+ "spl-pod",
+ "spl-token",
+ "spl-token-group-interface",
+ "spl-token-metadata-interface",
+ "spl-transfer-hook-interface",
+ "spl-type-length-value",
+ "thiserror",
+]
+
+[[package]]
+name = "spl-token-group-interface"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d419b5cfa3ee8e0f2386fd7e02a33b3ec8a7db4a9c7064a2ea24849dc4a273b6"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+]
+
+[[package]]
+name = "spl-token-metadata-interface"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "30179c47e93625680dabb620c6e7931bd12d62af390f447bc7beb4a3a9b5feee"
+dependencies = [
+ "borsh 1.5.1",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+ "spl-type-length-value",
+]
+
+[[package]]
+name = "spl-transfer-hook-interface"
+version = "0.6.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "66a98359769cd988f7b35c02558daa56d496a7e3bd8626e61f90a7c757eedb9b"
+dependencies = [
+ "arrayref",
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+ "spl-tlv-account-resolution",
+ "spl-type-length-value",
+]
+
+[[package]]
+name = "spl-type-length-value"
+version = "0.4.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "422ce13429dbd41d2cee8a73931c05fda0b0c8ca156a8b0c19445642550bb61a"
+dependencies = [
+ "bytemuck",
+ "solana-program",
+ "spl-discriminator",
+ "spl-pod",
+ "spl-program-error",
+]
+
+[[package]]
+name = "strsim"
+version = "0.11.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f"
+
+[[package]]
+name = "subtle"
+version = "2.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601"
+
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.66"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c42f3f41a2de00b01c0aaad383c5a45241efc8b2d1eda5661812fda5f3cdcff5"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "syn_derive"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1329189c02ff984e9736652b1631330da25eaa6bc639089ed4915d25446cbe7b"
+dependencies = [
+ "proc-macro-error",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "termcolor"
+version = "1.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755"
+dependencies = [
+ "winapi-util",
+]
+
+[[package]]
+name = "thiserror"
+version = "1.0.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c546c80d6be4bc6a00c0f01730c08df82eaa7a7a61f11d656526506112cc1709"
+dependencies = [
+ "thiserror-impl",
+]
+
+[[package]]
+name = "thiserror-impl"
+version = "1.0.61"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "46c3384250002a6d5af4d114f2845d37b57521033f30d5c3f46c4d70e1197533"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "tiny-bip39"
+version = "0.8.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d"
+dependencies = [
+ "anyhow",
+ "hmac 0.8.1",
+ "once_cell",
+ "pbkdf2 0.4.0",
+ "rand 0.7.3",
+ "rustc-hash",
+ "sha2 0.9.9",
+ "thiserror",
+ "unicode-normalization",
+ "wasm-bindgen",
+ "zeroize",
+]
+
+[[package]]
+name = "tinyvec"
+version = "1.6.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50"
+dependencies = [
+ "tinyvec_macros",
+]
+
+[[package]]
+name = "tinyvec_macros"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
+
+[[package]]
+name = "toml"
+version = "0.5.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml"
+version = "0.8.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f49eb2ab21d2f26bd6db7bf383edc527a7ebaee412d17af4d40fdccd442f335"
+dependencies = [
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "toml_edit 0.22.14",
+]
+
+[[package]]
+name = "toml_datetime"
+version = "0.6.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4badfd56924ae69bcc9039335b2e017639ce3f9b001c393c1b2d1ef846ce2cbf"
+dependencies = [
+ "serde",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.21.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6a8534fd7f78b5405e860340ad6575217ce99f38d4d5c8f2442cb5ecb50090e1"
+dependencies = [
+ "indexmap",
+ "toml_datetime",
+ "winnow 0.5.40",
+]
+
+[[package]]
+name = "toml_edit"
+version = "0.22.14"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f21c7aaf97f1bd9ca9d4f9e73b0a6c74bd5afef56f2bc931943a6e1c37e04e38"
+dependencies = [
+ "indexmap",
+ "serde",
+ "serde_spanned",
+ "toml_datetime",
+ "winnow 0.6.13",
+]
+
+[[package]]
+name = "typenum"
+version = "1.17.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
+
+[[package]]
+name = "unicode-normalization"
+version = "0.1.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a56d1686db2308d901306f92a263857ef59ea39678a5458e7cb17f01415101f5"
+dependencies = [
+ "tinyvec",
+]
+
+[[package]]
+name = "unicode-segmentation"
+version = "1.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202"
+
+[[package]]
+name = "universal-hash"
+version = "0.4.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05"
+dependencies = [
+ "generic-array",
+ "subtle",
+]
+
+[[package]]
+name = "uriparse"
+version = "0.6.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0200d0fc04d809396c2ad43f3c95da3582a2556eba8d453c1087f4120ee352ff"
+dependencies = [
+ "fnv",
+ "lazy_static",
+]
+
+[[package]]
+name = "version_check"
+version = "0.9.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
+
+[[package]]
+name = "wasi"
+version = "0.9.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
+
+[[package]]
+name = "wasi"
+version = "0.11.0+wasi-snapshot-preview1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
+
+[[package]]
+name = "wasm-bindgen"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4be2531df63900aeb2bca0daaaddec08491ee64ceecbee5076636a3b026795a8"
+dependencies = [
+ "cfg-if",
+ "wasm-bindgen-macro",
+]
+
+[[package]]
+name = "wasm-bindgen-backend"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "614d787b966d3989fa7bb98a654e369c762374fd3213d212cfc0251257e747da"
+dependencies = [
+ "bumpalo",
+ "log",
+ "once_cell",
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-macro"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a1f8823de937b71b9460c0c34e25f3da88250760bec0ebac694b49997550d726"
+dependencies = [
+ "quote",
+ "wasm-bindgen-macro-support",
+]
+
+[[package]]
+name = "wasm-bindgen-macro-support"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e94f17b526d0a461a191c78ea52bbce64071ed5c04c9ffe424dcb38f74171bb7"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+ "wasm-bindgen-backend",
+ "wasm-bindgen-shared",
+]
+
+[[package]]
+name = "wasm-bindgen-shared"
+version = "0.2.92"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "af190c94f2773fdb3729c55b007a722abb5384da03bc0986df4c289bf5567e96"
+
+[[package]]
+name = "web-sys"
+version = "0.3.69"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "77afa9a11836342370f4817622a2f0f418b134426d91a82dfb48f532d2ec13ef"
+dependencies = [
+ "js-sys",
+ "wasm-bindgen",
+]
+
+[[package]]
+name = "winapi"
+version = "0.3.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
+dependencies = [
+ "winapi-i686-pc-windows-gnu",
+ "winapi-x86_64-pc-windows-gnu",
+]
+
+[[package]]
+name = "winapi-i686-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
+
+[[package]]
+name = "winapi-util"
+version = "0.1.8"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4d4cc384e1e73b93bafa6fb4f1df8c41695c8a91cf9c4c64358067d15a7b6c6b"
+dependencies = [
+ "windows-sys",
+]
+
+[[package]]
+name = "winapi-x86_64-pc-windows-gnu"
+version = "0.4.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
+
+[[package]]
+name = "windows-sys"
+version = "0.52.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "6f0713a46559409d202e70e28227288446bf7841d3211583a4b53e3f6d96e7eb"
+dependencies = [
+ "windows_aarch64_gnullvm",
+ "windows_aarch64_msvc",
+ "windows_i686_gnu",
+ "windows_i686_gnullvm",
+ "windows_i686_msvc",
+ "windows_x86_64_gnu",
+ "windows_x86_64_gnullvm",
+ "windows_x86_64_msvc",
+]
+
+[[package]]
+name = "windows_aarch64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "7088eed71e8b8dda258ecc8bac5fb1153c5cffaf2578fc8ff5d61e23578d3263"
+
+[[package]]
+name = "windows_aarch64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "9985fd1504e250c615ca5f281c3f7a6da76213ebd5ccc9561496568a2752afb6"
+
+[[package]]
+name = "windows_i686_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "88ba073cf16d5372720ec942a8ccbf61626074c6d4dd2e745299726ce8b89670"
+
+[[package]]
+name = "windows_i686_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "87f4261229030a858f36b459e748ae97545d6f1ec60e5e0d6a3d32e0dc232ee9"
+
+[[package]]
+name = "windows_i686_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "db3c2bf3d13d5b658be73463284eaf12830ac9a26a90c717b7f771dfe97487bf"
+
+[[package]]
+name = "windows_x86_64_gnu"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4e4246f76bdeff09eb48875a0fd3e2af6aada79d409d33011886d3e1581517d9"
+
+[[package]]
+name = "windows_x86_64_gnullvm"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "852298e482cd67c356ddd9570386e2862b5673c85bd5f88df9ab6802b334c596"
+
+[[package]]
+name = "windows_x86_64_msvc"
+version = "0.52.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "bec47e5bfd1bff0eeaf6d8b485cc1074891a197ab4225d504cb7a1ab88b02bf0"
+
+[[package]]
+name = "winnow"
+version = "0.5.40"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "f593a95398737aeed53e489c785df13f3618e41dbcd6718c6addbf1395aa6876"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "winnow"
+version = "0.6.13"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "59b5e5f6c299a3c7890b876a2a587f3115162487e704907d9b6cd29473052ba1"
+dependencies = [
+ "memchr",
+]
+
+[[package]]
+name = "zerocopy"
+version = "0.7.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ae87e3fcd617500e5d106f0380cf7b77f3c6092aae37191433159dda23cfb087"
+dependencies = [
+ "zerocopy-derive",
+]
+
+[[package]]
+name = "zerocopy-derive"
+version = "0.7.34"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "15e934569e47891f7d9411f1a451d947a60e000ab3bd24fbb970f000387d1b3b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
+
+[[package]]
+name = "zeroize"
+version = "1.3.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd"
+dependencies = [
+ "zeroize_derive",
+]
+
+[[package]]
+name = "zeroize_derive"
+version = "1.4.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 2.0.66",
+]
diff --git a/tests/bench/package.json b/tests/bench/package.json
index b58cba1ea7..0817c9d3be 100644
--- a/tests/bench/package.json
+++ b/tests/bench/package.json
@@ -1,6 +1,6 @@
 {
   "name": "bench",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/bench/programs/bench/Cargo.toml b/tests/bench/programs/bench/Cargo.toml
index d7b162620b..7a349521ae 100644
--- a/tests/bench/programs/bench/Cargo.toml
+++ b/tests/bench/programs/bench/Cargo.toml
@@ -10,6 +10,7 @@ crate-type = ["cdylib", "lib"]
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/bench/tests/binary-size.ts b/tests/bench/tests/binary-size.ts
index 0e60a56697..00f2c081cf 100644
--- a/tests/bench/tests/binary-size.ts
+++ b/tests/bench/tests/binary-size.ts
@@ -1,15 +1,18 @@
 import * as fs from "fs/promises";
 import path from "path";
 
-import { IDL } from "../target/types/bench";
 import { BenchData, BinarySize } from "../scripts/utils";
 
+const IDL = require("../target/idl/bench.json");
+
 describe("Binary size", () => {
   const binarySize: BinarySize = {};
 
   it("Measure binary size", async () => {
-    const stat = await fs.stat(path.join("target", "deploy", `${IDL.name}.so`));
-    binarySize[IDL.name] = stat.size;
+    const stat = await fs.stat(
+      path.join("target", "deploy", `${IDL.metadata.name}.so`)
+    );
+    binarySize[IDL.metadata.name] = stat.size;
   });
 
   after(async () => {
diff --git a/tests/bench/tests/compute-units.ts b/tests/bench/tests/compute-units.ts
index 3465bcf1b8..2a964fdaef 100644
--- a/tests/bench/tests/compute-units.ts
+++ b/tests/bench/tests/compute-units.ts
@@ -1,7 +1,7 @@
 import * as anchor from "@coral-xyz/anchor";
 import * as token from "@coral-xyz/spl-token";
 
-import { Bench, IDL } from "../target/types/bench";
+import { Bench } from "../target/types/bench";
 import { BenchData, ComputeUnits } from "../scripts/utils";
 
 describe("Compute units", () => {
@@ -31,7 +31,7 @@ describe("Compute units", () => {
     for (const accountCount of options.accountCounts) {
       // Check whether the init version of the instruction exists
       const ixNameInit = `${ixName}Init`;
-      const hasInitVersion = IDL.instructions.some((ix) =>
+      const hasInitVersion = program.idl.instructions.some((ix) =>
         ix.name.startsWith(ixNameInit)
       );
 
@@ -53,7 +53,7 @@ describe("Compute units", () => {
           signers.splice(0);
         }
 
-        for (const ix of IDL.instructions) {
+        for (const ix of program.idl.instructions) {
           if (ix.name !== method) continue;
 
           for (const account of ix.accounts) {
@@ -80,7 +80,7 @@ describe("Compute units", () => {
             const keypair = options.generateKeypair(account.name);
             accounts[account.name] = keypair.publicKey;
 
-            if (account.isSigner) {
+            if (account.signer) {
               signers.push(keypair);
             }
           }
diff --git a/tests/bench/tests/stack-memory.ts b/tests/bench/tests/stack-memory.ts
index caad67b643..33e19c733a 100644
--- a/tests/bench/tests/stack-memory.ts
+++ b/tests/bench/tests/stack-memory.ts
@@ -2,7 +2,8 @@ import path from "path";
 import fs from "fs/promises";
 
 import { BenchData, StackMemory, spawn } from "../scripts/utils";
-import { IDL } from "../target/types/bench";
+
+const IDL = require("../target/idl/bench.json");
 
 describe("Stack memory", () => {
   const stackMemory: StackMemory = {};
@@ -10,12 +11,12 @@ describe("Stack memory", () => {
   const STACK_CONTENT = [
     "",
     `let stack_limit: [u16; 2048] = [1; 2048];`,
-    `msg!("{}", stack_limit.len());`,
+    `msg!("{}", stack_limit[2047]);`,
     "",
   ].join("\n\t\t");
 
   it("Measure stack memory usage", async () => {
-    const libPath = path.join("programs", IDL.name, "src", "lib.rs");
+    const libPath = path.join("programs", IDL.metadata.name, "src", "lib.rs");
     const lib = await fs.readFile(libPath, "utf8");
     const indices = [...lib.matchAll(/fn\s[\w\d]+\(/g)]
       .map((match) => match.index)
diff --git a/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/Cargo.toml b/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/Cargo.toml
index 4a81349c7c..50da441ed4 100644
--- a/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/Cargo.toml
+++ b/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/Cargo.toml
@@ -2,7 +2,6 @@
 name = "bpf-upgradeable-state"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs b/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs
index 53fdf43592..9734695285 100644
--- a/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs
+++ b/tests/bpf-upgradeable-state/programs/bpf-upgradeable-state/src/lib.rs
@@ -1,5 +1,7 @@
 use anchor_lang::prelude::*;
 
+use crate::program::BpfUpgradeableState;
+
 declare_id!("Cum9tTyj5HwcEiAmhgaS7Bbj4UczCwsucrCkxRECzM4e");
 
 #[program]
@@ -73,7 +75,7 @@ pub struct SetAdminSettingsUseProgramState<'info> {
     #[account(mut)]
     pub authority: Signer<'info>,
     #[account(constraint = program.programdata_address()? == Some(program_data.key()))]
-    pub program: Program<'info, crate::program::BpfUpgradeableState>,
+    pub program: Program<'info, BpfUpgradeableState>,
     #[account(constraint = program_data.upgrade_authority_address == Some(authority.key()))]
     pub program_data: Account<'info, ProgramData>,
     pub system_program: Program<'info, System>,
diff --git a/tests/cashiers-check/package.json b/tests/cashiers-check/package.json
index c86ab31c63..4c178102ac 100644
--- a/tests/cashiers-check/package.json
+++ b/tests/cashiers-check/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cashiers-check",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/cashiers-check/programs/cashiers-check/Cargo.toml b/tests/cashiers-check/programs/cashiers-check/Cargo.toml
index da6bb2d3cb..ceafc94a9e 100644
--- a/tests/cashiers-check/programs/cashiers-check/Cargo.toml
+++ b/tests/cashiers-check/programs/cashiers-check/Cargo.toml
@@ -2,7 +2,6 @@
 name = "cashiers-check"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/cfo/package.json b/tests/cfo/package.json
index 398053ab87..46ffb91918 100644
--- a/tests/cfo/package.json
+++ b/tests/cfo/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cfo",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/cfo/programs/cfo/Cargo.toml b/tests/cfo/programs/cfo/Cargo.toml
index a5037f19c7..1c5cc1209a 100644
--- a/tests/cfo/programs/cfo/Cargo.toml
+++ b/tests/cfo/programs/cfo/Cargo.toml
@@ -2,7 +2,6 @@
 name = "cfo"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
diff --git a/tests/chat/package.json b/tests/chat/package.json
index aba303c8df..3a552e0021 100644
--- a/tests/chat/package.json
+++ b/tests/chat/package.json
@@ -1,6 +1,6 @@
 {
   "name": "chat",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/chat/programs/chat/Cargo.toml b/tests/chat/programs/chat/Cargo.toml
index 93da0ea8f7..cc2540a3f1 100644
--- a/tests/chat/programs/chat/Cargo.toml
+++ b/tests/chat/programs/chat/Cargo.toml
@@ -2,7 +2,6 @@
 name = "chat"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/composite/package.json b/tests/composite/package.json
index 31e6e74ebf..d937685d5d 100644
--- a/tests/composite/package.json
+++ b/tests/composite/package.json
@@ -1,6 +1,6 @@
 {
   "name": "composite",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/composite/programs/composite/Cargo.toml b/tests/composite/programs/composite/Cargo.toml
index 211064b84f..9e4a7798b6 100644
--- a/tests/composite/programs/composite/Cargo.toml
+++ b/tests/composite/programs/composite/Cargo.toml
@@ -2,7 +2,6 @@
 name = "composite"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -12,6 +11,7 @@ name = "composite"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/cpi-returns/package.json b/tests/cpi-returns/package.json
index c029358db1..69d795796a 100644
--- a/tests/cpi-returns/package.json
+++ b/tests/cpi-returns/package.json
@@ -1,6 +1,6 @@
 {
   "name": "cpi-returns",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/cpi-returns/programs/callee/Cargo.toml b/tests/cpi-returns/programs/callee/Cargo.toml
index c964a4aa4d..6e98dbefdf 100644
--- a/tests/cpi-returns/programs/callee/Cargo.toml
+++ b/tests/cpi-returns/programs/callee/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
diff --git a/tests/cpi-returns/programs/caller/Cargo.toml b/tests/cpi-returns/programs/caller/Cargo.toml
index 2aaa551085..b898da71bd 100644
--- a/tests/cpi-returns/programs/caller/Cargo.toml
+++ b/tests/cpi-returns/programs/caller/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
diff --git a/tests/cpi-returns/tests/cpi-return.ts b/tests/cpi-returns/tests/cpi-return.ts
index 22217577d4..0099ef45a2 100644
--- a/tests/cpi-returns/tests/cpi-return.ts
+++ b/tests/cpi-returns/tests/cpi-return.ts
@@ -159,7 +159,7 @@ describe("CPI return", () => {
       (f) => f.name == "returnStruct"
     );
     assert.deepStrictEqual(returnStructInstruction.returns, {
-      defined: "StructReturn",
+      defined: { name: "structReturn" },
     });
   });
 
diff --git a/tests/custom-coder/package.json b/tests/custom-coder/package.json
index 89ebb28d93..e0c6039f27 100644
--- a/tests/custom-coder/package.json
+++ b/tests/custom-coder/package.json
@@ -1,6 +1,6 @@
 {
   "name": "custom-coder",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/custom-coder/programs/native-system/Cargo.toml b/tests/custom-coder/programs/native-system/Cargo.toml
index ec46d25869..ffc85c5eeb 100644
--- a/tests/custom-coder/programs/native-system/Cargo.toml
+++ b/tests/custom-coder/programs/native-system/Cargo.toml
@@ -2,7 +2,6 @@
 name = "native-system"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -15,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/custom-coder/programs/spl-associated-token/Cargo.toml b/tests/custom-coder/programs/spl-associated-token/Cargo.toml
index 3d58f79d80..bab72f0f1c 100644
--- a/tests/custom-coder/programs/spl-associated-token/Cargo.toml
+++ b/tests/custom-coder/programs/spl-associated-token/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [profile.release]
 overflow-checks = true
diff --git a/tests/custom-coder/programs/spl-token/Cargo.toml b/tests/custom-coder/programs/spl-token/Cargo.toml
index 39ee2c7839..b3cf7af2cb 100644
--- a/tests/custom-coder/programs/spl-token/Cargo.toml
+++ b/tests/custom-coder/programs/spl-token/Cargo.toml
@@ -2,7 +2,6 @@
 name = "spl-token"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -15,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/custom-discriminator/Anchor.toml b/tests/custom-discriminator/Anchor.toml
new file mode 100644
index 0000000000..63df913635
--- /dev/null
+++ b/tests/custom-discriminator/Anchor.toml
@@ -0,0 +1,20 @@
+[workspace]
+exclude = ["programs/ambiguous-discriminator"]
+
+[features]
+resolution = true
+skip-lint = false
+
+[programs.localnet]
+ambiguous-discriminator = "AmbiguousDiscriminator111111111111111111111"
+custom_discriminator = "CustomDiscriminator111111111111111111111111"
+
+[registry]
+url = "https://api.apr.dev"
+
+[provider]
+cluster = "Localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
diff --git a/tests/custom-discriminator/Cargo.toml b/tests/custom-discriminator/Cargo.toml
new file mode 100644
index 0000000000..f397704811
--- /dev/null
+++ b/tests/custom-discriminator/Cargo.toml
@@ -0,0 +1,14 @@
+[workspace]
+members = [
+    "programs/*"
+]
+resolver = "2"
+
+[profile.release]
+overflow-checks = true
+lto = "fat"
+codegen-units = 1
+[profile.release.build-override]
+opt-level = 3
+incremental = false
+codegen-units = 1
diff --git a/tests/custom-discriminator/package.json b/tests/custom-discriminator/package.json
new file mode 100644
index 0000000000..1be7a54505
--- /dev/null
+++ b/tests/custom-discriminator/package.json
@@ -0,0 +1,16 @@
+{
+  "name": "custom-discriminator",
+  "version": "0.30.1",
+  "license": "(MIT OR Apache-2.0)",
+  "homepage": "https://github.com/coral-xyz/anchor#readme",
+  "bugs": {
+    "url": "https://github.com/coral-xyz/anchor/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/coral-xyz/anchor.git"
+  },
+  "engines": {
+    "node": ">=17"
+  }
+}
diff --git a/tests/custom-discriminator/programs/ambiguous-discriminator/Cargo.toml b/tests/custom-discriminator/programs/ambiguous-discriminator/Cargo.toml
new file mode 100644
index 0000000000..beca55827c
--- /dev/null
+++ b/tests/custom-discriminator/programs/ambiguous-discriminator/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "ambiguous-discriminator"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "ambiguous_discriminator"
+
+[features]
+default = []
+cpi = ["no-entrypoint"]
+no-entrypoint = []
+no-idl = []
+no-log-ix-name = []
+idl-build = ["anchor-lang/idl-build"]
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }
diff --git a/tests/custom-discriminator/programs/ambiguous-discriminator/Xargo.toml b/tests/custom-discriminator/programs/ambiguous-discriminator/Xargo.toml
new file mode 100644
index 0000000000..475fb71ed1
--- /dev/null
+++ b/tests/custom-discriminator/programs/ambiguous-discriminator/Xargo.toml
@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []
diff --git a/tests/custom-discriminator/programs/ambiguous-discriminator/src/lib.rs b/tests/custom-discriminator/programs/ambiguous-discriminator/src/lib.rs
new file mode 100644
index 0000000000..fc882d8105
--- /dev/null
+++ b/tests/custom-discriminator/programs/ambiguous-discriminator/src/lib.rs
@@ -0,0 +1,31 @@
+use anchor_lang::prelude::*;
+
+declare_id!("AmbiguousDiscriminator111111111111111111111");
+
+#[program]
+pub mod ambiguous_discriminator {
+    use super::*;
+
+    /// Compilation should error due to ambiguous discriminators.
+    pub fn check_accounts(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct CheckAccounts<'info> {
+    pub some_account: Account<'info, SomeAccount>,
+    pub another_account: Account<'info, AnotherAccount>,
+}
+
+#[account(discriminator = 1)]
+pub struct SomeAccount {
+    pub a: u8,
+    pub b: u16,
+    pub c: u32,
+}
+
+#[account(discriminator = [1, 2, 3, 4])]
+pub struct AnotherAccount {
+    pub a: u32,
+}
diff --git a/tests/idl/programs/idl-build-features/Cargo.toml b/tests/custom-discriminator/programs/custom-discriminator/Cargo.toml
similarity index 79%
rename from tests/idl/programs/idl-build-features/Cargo.toml
rename to tests/custom-discriminator/programs/custom-discriminator/Cargo.toml
index a8577df4cd..ce2801d80c 100644
--- a/tests/idl/programs/idl-build-features/Cargo.toml
+++ b/tests/custom-discriminator/programs/custom-discriminator/Cargo.toml
@@ -1,20 +1,19 @@
 [package]
-name = "idl-build-features"
+name = "custom-discriminator"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
 crate-type = ["cdylib", "lib"]
-name = "idl_build_features"
+name = "custom_discriminator"
 
 [features]
 no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
-idl-build = ["anchor-lang/idl-build"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/idl/programs/client-interactions/Xargo.toml b/tests/custom-discriminator/programs/custom-discriminator/Xargo.toml
similarity index 100%
rename from tests/idl/programs/client-interactions/Xargo.toml
rename to tests/custom-discriminator/programs/custom-discriminator/Xargo.toml
diff --git a/tests/custom-discriminator/programs/custom-discriminator/src/lib.rs b/tests/custom-discriminator/programs/custom-discriminator/src/lib.rs
new file mode 100644
index 0000000000..529ae3fe31
--- /dev/null
+++ b/tests/custom-discriminator/programs/custom-discriminator/src/lib.rs
@@ -0,0 +1,82 @@
+use anchor_lang::prelude::*;
+
+declare_id!("CustomDiscriminator111111111111111111111111");
+
+const CONST_DISC: &'static [u8] = &[55, 66, 77, 88];
+
+const fn get_disc(input: &str) -> &'static [u8] {
+    match input.as_bytes() {
+        b"wow" => &[4 + 5, 55 / 5],
+        _ => unimplemented!(),
+    }
+}
+
+#[program]
+pub mod custom_discriminator {
+    use super::*;
+
+    #[instruction(discriminator = 0)]
+    pub fn int(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    #[instruction(discriminator = [1, 2, 3, 4])]
+    pub fn array(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    #[instruction(discriminator = b"hi")]
+    pub fn byte_str(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    #[instruction(discriminator = CONST_DISC)]
+    pub fn constant(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    #[instruction(discriminator = get_disc("wow"))]
+    pub fn const_fn(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn account(ctx: Context, field: u8) -> Result<()> {
+        ctx.accounts.my_account.field = field;
+        Ok(())
+    }
+
+    pub fn event(_ctx: Context, field: u8) -> Result<()> {
+        emit!(MyEvent { field });
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct DefaultIx<'info> {
+    pub signer: Signer<'info>,
+}
+
+#[derive(Accounts)]
+pub struct CustomAccountIx<'info> {
+    #[account(mut)]
+    pub signer: Signer<'info>,
+    #[account(
+        init,
+        payer = signer,
+        space = MyAccount::DISCRIMINATOR.len() + core::mem::size_of::(),
+        seeds = [b"my_account"],
+        bump
+    )]
+    pub my_account: Account<'info, MyAccount>,
+    pub system_program: Program<'info, System>,
+}
+
+#[account(discriminator = 1)]
+pub struct MyAccount {
+    pub field: u8,
+}
+
+#[event(discriminator = 1)]
+pub struct MyEvent {
+    field: u8,
+}
diff --git a/tests/custom-discriminator/tests/ambiguous-discriminator.ts b/tests/custom-discriminator/tests/ambiguous-discriminator.ts
new file mode 100644
index 0000000000..5f0d22cb34
--- /dev/null
+++ b/tests/custom-discriminator/tests/ambiguous-discriminator.ts
@@ -0,0 +1,22 @@
+import { spawnSync } from "child_process";
+
+describe("ambiguous-discriminator", () => {
+  it("Returns ambiguous discriminator error on builds", () => {
+    const result = spawnSync("anchor", [
+      "idl",
+      "build",
+      "-p",
+      "ambiguous-discriminator",
+    ]);
+    if (result.status === 0) {
+      throw new Error("Ambiguous errors did not make building the IDL fail");
+    }
+
+    const output = result.output.toString();
+    if (!output.includes("Error: Program ambiguous-discriminator not found")) {
+      throw new Error(
+        `Ambiguous discriminators did not return the expected error: "${output}"`
+      );
+    }
+  });
+});
diff --git a/tests/custom-discriminator/tests/custom-discriminator.ts b/tests/custom-discriminator/tests/custom-discriminator.ts
new file mode 100644
index 0000000000..b87e20594a
--- /dev/null
+++ b/tests/custom-discriminator/tests/custom-discriminator.ts
@@ -0,0 +1,72 @@
+import * as anchor from "@coral-xyz/anchor";
+import assert from "assert";
+
+import type { CustomDiscriminator } from "../target/types/custom_discriminator";
+
+describe("custom-discriminator", () => {
+  anchor.setProvider(anchor.AnchorProvider.env());
+  const program: anchor.Program =
+    anchor.workspace.customDiscriminator;
+
+  describe("Instructions", () => {
+    const testCommon = async (ixName: keyof typeof program["methods"]) => {
+      const tx = await program.methods[ixName]().transaction();
+
+      // Verify discriminator
+      const ix = program.idl.instructions.find((ix) => ix.name === ixName)!;
+      assert(ix.discriminator.length < 8);
+      const data = tx.instructions[0].data;
+      assert(data.equals(Buffer.from(ix.discriminator)));
+
+      // Verify tx runs
+      await program.provider.sendAndConfirm!(tx);
+    };
+
+    it("Integer", () => testCommon("int"));
+    it("Array", () => testCommon("array"));
+    it("Byte string", () => testCommon("byteStr"));
+    it("Constant", () => testCommon("constant"));
+    it("Const Fn", () => testCommon("constFn"));
+  });
+
+  describe("Accounts", () => {
+    it("Works", async () => {
+      // Verify discriminator
+      const acc = program.idl.accounts.find((acc) => acc.name === "myAccount")!;
+      assert(acc.discriminator.length < 8);
+
+      // Verify regular `init` ix works
+      const field = 5;
+      const { pubkeys, signature } = await program.methods
+        .account(field)
+        .rpcAndKeys();
+      await program.provider.connection.confirmTransaction(
+        signature,
+        "confirmed"
+      );
+      const myAccount = await program.account.myAccount.fetch(
+        pubkeys.myAccount
+      );
+      assert.strictEqual(myAccount.field, field);
+    });
+  });
+
+  describe("Events", () => {
+    it("Works", async () => {
+      // Verify discriminator
+      const event = program.idl.events.find((acc) => acc.name === "myEvent")!;
+      assert(event.discriminator.length < 8);
+
+      // Verify regular event works
+      await new Promise((res) => {
+        const field = 5;
+        const id = program.addEventListener("myEvent", (ev) => {
+          assert.strictEqual(ev.field, field);
+          program.removeEventListener(id);
+          res();
+        });
+        program.methods.event(field).rpc();
+      });
+    });
+  });
+});
diff --git a/tests/custom-discriminator/tsconfig.json b/tests/custom-discriminator/tsconfig.json
new file mode 100644
index 0000000000..8c893f2d5f
--- /dev/null
+++ b/tests/custom-discriminator/tsconfig.json
@@ -0,0 +1,11 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true,
+    "strict": true,
+    "skipLibCheck": true
+  }
+}
diff --git a/tests/declare-id/package.json b/tests/declare-id/package.json
index 236a71eb02..1fc78018e3 100644
--- a/tests/declare-id/package.json
+++ b/tests/declare-id/package.json
@@ -1,6 +1,6 @@
 {
   "name": "declare-id",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/declare-id/programs/declare-id/Cargo.toml b/tests/declare-id/programs/declare-id/Cargo.toml
index 0bbbab6119..a22cb4601b 100644
--- a/tests/declare-id/programs/declare-id/Cargo.toml
+++ b/tests/declare-id/programs/declare-id/Cargo.toml
@@ -11,6 +11,7 @@ name = "declare_id"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/declare-program/Anchor.toml b/tests/declare-program/Anchor.toml
new file mode 100644
index 0000000000..afa1b300bd
--- /dev/null
+++ b/tests/declare-program/Anchor.toml
@@ -0,0 +1,10 @@
+[programs.localnet]
+declare_program = "Dec1areProgram11111111111111111111111111111"
+external = "Externa111111111111111111111111111111111111"
+
+[provider]
+cluster = "localnet"
+wallet = "~/.config/solana/id.json"
+
+[scripts]
+test = "yarn run ts-mocha -p ./tsconfig.json -t 1000000 tests/**/*.ts"
diff --git a/tests/declare-program/Cargo.toml b/tests/declare-program/Cargo.toml
new file mode 100644
index 0000000000..f397704811
--- /dev/null
+++ b/tests/declare-program/Cargo.toml
@@ -0,0 +1,14 @@
+[workspace]
+members = [
+    "programs/*"
+]
+resolver = "2"
+
+[profile.release]
+overflow-checks = true
+lto = "fat"
+codegen-units = 1
+[profile.release.build-override]
+opt-level = 3
+incremental = false
+codegen-units = 1
diff --git a/tests/declare-program/idls/external.json b/tests/declare-program/idls/external.json
new file mode 100644
index 0000000000..676532e246
--- /dev/null
+++ b/tests/declare-program/idls/external.json
@@ -0,0 +1,233 @@
+{
+  "address": "Externa111111111111111111111111111111111111",
+  "metadata": {
+    "name": "external",
+    "version": "0.1.0",
+    "spec": "0.1.0",
+    "description": "Created with Anchor"
+  },
+  "instructions": [
+    {
+      "name": "init",
+      "discriminator": [
+        220,
+        59,
+        207,
+        236,
+        108,
+        250,
+        47,
+        100
+      ],
+      "accounts": [
+        {
+          "name": "authority",
+          "writable": true,
+          "signer": true
+        },
+        {
+          "name": "my_account",
+          "writable": true,
+          "pda": {
+            "seeds": [
+              {
+                "kind": "account",
+                "path": "authority"
+              }
+            ]
+          }
+        },
+        {
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
+        }
+      ],
+      "args": []
+    },
+    {
+      "name": "test_compilation_defined_type_param",
+      "discriminator": [
+        61,
+        118,
+        87,
+        242,
+        137,
+        97,
+        90,
+        223
+      ],
+      "accounts": [
+        {
+          "name": "signer",
+          "signer": true
+        }
+      ],
+      "args": [
+        {
+          "name": "_my_account",
+          "type": {
+            "defined": {
+              "name": "MyAccount"
+            }
+          }
+        }
+      ]
+    },
+    {
+      "name": "test_compilation_return_type",
+      "discriminator": [
+        174,
+        51,
+        51,
+        121,
+        52,
+        61,
+        38,
+        28
+      ],
+      "accounts": [
+        {
+          "name": "signer",
+          "signer": true
+        }
+      ],
+      "args": [],
+      "returns": "bool"
+    },
+    {
+      "name": "update",
+      "discriminator": [
+        219,
+        200,
+        88,
+        176,
+        158,
+        63,
+        253,
+        127
+      ],
+      "accounts": [
+        {
+          "name": "authority",
+          "signer": true
+        },
+        {
+          "name": "my_account",
+          "writable": true,
+          "pda": {
+            "seeds": [
+              {
+                "kind": "account",
+                "path": "authority"
+              }
+            ]
+          }
+        }
+      ],
+      "args": [
+        {
+          "name": "value",
+          "type": "u32"
+        }
+      ]
+    },
+    {
+      "name": "update_composite",
+      "discriminator": [
+        26,
+        42,
+        201,
+        224,
+        121,
+        60,
+        188,
+        220
+      ],
+      "accounts": [
+        {
+          "name": "update",
+          "accounts": [
+            {
+              "name": "authority",
+              "signer": true
+            },
+            {
+              "name": "my_account",
+              "writable": true,
+              "pda": {
+                "seeds": [
+                  {
+                    "kind": "account",
+                    "path": "authority"
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      ],
+      "args": [
+        {
+          "name": "value",
+          "type": "u32"
+        }
+      ]
+    }
+  ],
+  "accounts": [
+    {
+      "name": "MyAccount",
+      "discriminator": [
+        246,
+        28,
+        6,
+        87,
+        251,
+        45,
+        50,
+        42
+      ]
+    }
+  ],
+  "events": [
+    {
+      "name": "MyEvent",
+      "discriminator": [
+        96,
+        184,
+        197,
+        243,
+        139,
+        2,
+        90,
+        148
+      ]
+    }
+  ],
+  "types": [
+    {
+      "name": "MyAccount",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "field",
+            "type": "u32"
+          }
+        ]
+      }
+    },
+    {
+      "name": "MyEvent",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "value",
+            "type": "u32"
+          }
+        ]
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/declare-program/idls/external_legacy.json b/tests/declare-program/idls/external_legacy.json
new file mode 100644
index 0000000000..20da7a7fa2
--- /dev/null
+++ b/tests/declare-program/idls/external_legacy.json
@@ -0,0 +1,65 @@
+{
+  "version": "0.1.0",
+  "name": "external",
+  "metadata": {
+    "address": "Externa111111111111111111111111111111111111"
+  },
+  "instructions": [
+    {
+      "name": "init",
+      "accounts": [
+        { "name": "authority", "isMut": true, "isSigner": true },
+        { "name": "myAccount", "isMut": true, "isSigner": false },
+        { "name": "systemProgram", "isMut": false, "isSigner": false }
+      ],
+      "args": []
+    },
+    {
+      "name": "update",
+      "accounts": [
+        { "name": "authority", "isMut": false, "isSigner": true },
+        { "name": "myAccount", "isMut": true, "isSigner": false }
+      ],
+      "args": [{ "name": "value", "type": "u32" }]
+    },
+    {
+      "name": "updateComposite",
+      "accounts": [
+        {
+          "name": "update",
+          "accounts": [
+            { "name": "authority", "isMut": false, "isSigner": true },
+            { "name": "myAccount", "isMut": true, "isSigner": false }
+          ]
+        }
+      ],
+      "args": [{ "name": "value", "type": "u32" }]
+    },
+    {
+      "name": "testCompilationDefinedTypeParam",
+      "accounts": [{ "name": "signer", "isMut": false, "isSigner": true }],
+      "args": [{ "name": "myAccount", "type": { "defined": "MyAccount" } }]
+    },
+    {
+      "name": "testCompilationReturnType",
+      "accounts": [{ "name": "signer", "isMut": false, "isSigner": true }],
+      "args": [],
+      "returns": "bool"
+    }
+  ],
+  "accounts": [
+    {
+      "name": "MyAccount",
+      "type": {
+        "kind": "struct",
+        "fields": [{ "name": "field", "type": "u32" }]
+      }
+    }
+  ],
+  "events": [
+    {
+      "name": "MyEvent",
+      "fields": [{ "name": "value", "type": "u32", "index": false }]
+    }
+  ]
+}
diff --git a/tests/declare-program/package.json b/tests/declare-program/package.json
new file mode 100644
index 0000000000..9f4fd26763
--- /dev/null
+++ b/tests/declare-program/package.json
@@ -0,0 +1,16 @@
+{
+  "name": "declare-program",
+  "version": "0.30.1",
+  "license": "(MIT OR Apache-2.0)",
+  "homepage": "https://github.com/coral-xyz/anchor#readme",
+  "bugs": {
+    "url": "https://github.com/coral-xyz/anchor/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/coral-xyz/anchor.git"
+  },
+  "engines": {
+    "node": ">=17"
+  }
+}
diff --git a/tests/declare-program/programs/declare-program/Cargo.toml b/tests/declare-program/programs/declare-program/Cargo.toml
new file mode 100644
index 0000000000..a713247476
--- /dev/null
+++ b/tests/declare-program/programs/declare-program/Cargo.toml
@@ -0,0 +1,19 @@
+[package]
+name = "declare-program"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "declare_program"
+
+[features]
+no-entrypoint = []
+no-idl = []
+cpi = ["no-entrypoint"]
+default = []
+idl-build = ["anchor-lang/idl-build"]
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }
diff --git a/tests/idl/programs/idl-build-features/Xargo.toml b/tests/declare-program/programs/declare-program/Xargo.toml
similarity index 100%
rename from tests/idl/programs/idl-build-features/Xargo.toml
rename to tests/declare-program/programs/declare-program/Xargo.toml
diff --git a/tests/declare-program/programs/declare-program/src/lib.rs b/tests/declare-program/programs/declare-program/src/lib.rs
new file mode 100644
index 0000000000..e3dd6cd18a
--- /dev/null
+++ b/tests/declare-program/programs/declare-program/src/lib.rs
@@ -0,0 +1,116 @@
+use anchor_lang::prelude::*;
+
+declare_id!("Dec1areProgram11111111111111111111111111111");
+
+declare_program!(external);
+use external::program::External;
+
+// Compilation check for legacy IDL (pre Anchor `0.30`)
+declare_program!(external_legacy);
+
+#[program]
+pub mod declare_program {
+    use super::*;
+
+    pub fn cpi(ctx: Context, value: u32) -> Result<()> {
+        let cpi_my_account = &mut ctx.accounts.cpi_my_account;
+        require_keys_eq!(external::accounts::MyAccount::owner(), external::ID);
+        require_eq!(cpi_my_account.field, 0);
+
+        let cpi_ctx = CpiContext::new(
+            ctx.accounts.external_program.to_account_info(),
+            external::cpi::accounts::Update {
+                authority: ctx.accounts.authority.to_account_info(),
+                my_account: cpi_my_account.to_account_info(),
+            },
+        );
+        external::cpi::update(cpi_ctx, value)?;
+
+        cpi_my_account.reload()?;
+        require_eq!(cpi_my_account.field, value);
+
+        Ok(())
+    }
+
+    pub fn cpi_composite(ctx: Context, value: u32) -> Result<()> {
+        let cpi_my_account = &mut ctx.accounts.cpi_my_account;
+
+        let cpi_ctx = CpiContext::new(
+            ctx.accounts.external_program.to_account_info(),
+            external::cpi::accounts::UpdateComposite {
+                update: external::cpi::accounts::Update {
+                    authority: ctx.accounts.authority.to_account_info(),
+                    my_account: cpi_my_account.to_account_info(),
+                },
+            },
+        );
+        external::cpi::update_composite(cpi_ctx, value)?;
+
+        cpi_my_account.reload()?;
+        require_eq!(cpi_my_account.field, value);
+
+        Ok(())
+    }
+
+    pub fn account_utils(_ctx: Context) -> Result<()> {
+        use external::utils::Account;
+
+        // Empty
+        if Account::try_from_bytes(&[]).is_ok() {
+            return Err(ProgramError::Custom(0).into());
+        }
+
+        const DISC: &[u8] = &external::accounts::MyAccount::DISCRIMINATOR;
+
+        // Correct discriminator but invalid data
+        if Account::try_from_bytes(DISC).is_ok() {
+            return Err(ProgramError::Custom(1).into());
+        };
+
+        // Correct discriminator and valid data
+        match Account::try_from_bytes(&[DISC, &[1, 0, 0, 0]].concat()) {
+            Ok(Account::MyAccount(my_account)) => require_eq!(my_account.field, 1),
+            Err(e) => return Err(e.into()),
+        }
+
+        Ok(())
+    }
+
+    pub fn event_utils(_ctx: Context) -> Result<()> {
+        use external::utils::Event;
+
+        // Empty
+        if Event::try_from_bytes(&[]).is_ok() {
+            return Err(ProgramError::Custom(0).into());
+        }
+
+        const DISC: &[u8] =
+            &::DISCRIMINATOR;
+
+        // Correct discriminator but invalid data
+        if Event::try_from_bytes(DISC).is_ok() {
+            return Err(ProgramError::Custom(1).into());
+        };
+
+        // Correct discriminator and valid data
+        match Event::try_from_bytes(&[DISC, &[1, 0, 0, 0]].concat()) {
+            Ok(Event::MyEvent(my_event)) => require_eq!(my_event.value, 1),
+            Err(e) => return Err(e.into()),
+        }
+
+        Ok(())
+    }
+}
+
+#[derive(Accounts)]
+pub struct Cpi<'info> {
+    pub authority: Signer<'info>,
+    #[account(mut)]
+    pub cpi_my_account: Account<'info, external::accounts::MyAccount>,
+    pub external_program: Program<'info, External>,
+}
+
+#[derive(Accounts)]
+pub struct Utils<'info> {
+    pub authority: Signer<'info>,
+}
diff --git a/tests/idl/programs/client-interactions/Cargo.toml b/tests/declare-program/programs/external/Cargo.toml
similarity index 76%
rename from tests/idl/programs/client-interactions/Cargo.toml
rename to tests/declare-program/programs/external/Cargo.toml
index e96129ddf7..36eb4b0273 100644
--- a/tests/idl/programs/client-interactions/Cargo.toml
+++ b/tests/declare-program/programs/external/Cargo.toml
@@ -1,19 +1,18 @@
 [package]
-name = "client-interactions"
+name = "external"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
 crate-type = ["cdylib", "lib"]
-name = "client_interactions"
 
 [features]
 no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/declare-program/programs/external/Xargo.toml b/tests/declare-program/programs/external/Xargo.toml
new file mode 100644
index 0000000000..1744f098ae
--- /dev/null
+++ b/tests/declare-program/programs/external/Xargo.toml
@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []
\ No newline at end of file
diff --git a/tests/declare-program/programs/external/src/lib.rs b/tests/declare-program/programs/external/src/lib.rs
new file mode 100644
index 0000000000..71dc571db7
--- /dev/null
+++ b/tests/declare-program/programs/external/src/lib.rs
@@ -0,0 +1,77 @@
+use anchor_lang::prelude::*;
+
+declare_id!("Externa111111111111111111111111111111111111");
+
+#[program]
+pub mod external {
+    use super::*;
+
+    pub fn init(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn update(ctx: Context, value: u32) -> Result<()> {
+        ctx.accounts.my_account.field = value;
+        Ok(())
+    }
+
+    pub fn update_composite(ctx: Context, value: u32) -> Result<()> {
+        ctx.accounts.update.my_account.field = value;
+        Ok(())
+    }
+
+    // Compilation test for whether a defined type (an account in this case) can be used in `cpi` client.
+    pub fn test_compilation_defined_type_param(
+        _ctx: Context,
+        _my_account: MyAccount,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    // Compilation test for whether a custom return type can be specified in `cpi` client
+    pub fn test_compilation_return_type(_ctx: Context) -> Result {
+        Ok(true)
+    }
+}
+
+#[derive(Accounts)]
+pub struct TestCompilation<'info> {
+    pub signer: Signer<'info>,
+}
+
+#[derive(Accounts)]
+pub struct Init<'info> {
+    #[account(mut)]
+    pub authority: Signer<'info>,
+    #[account(
+        init,
+        payer = authority,
+        space = 8 + 4,
+        seeds = [authority.key.as_ref()],
+        bump
+    )]
+    pub my_account: Account<'info, MyAccount>,
+    pub system_program: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct Update<'info> {
+    pub authority: Signer<'info>,
+    #[account(mut, seeds = [authority.key.as_ref()], bump)]
+    pub my_account: Account<'info, MyAccount>,
+}
+
+#[derive(Accounts)]
+pub struct UpdateComposite<'info> {
+    pub update: Update<'info>,
+}
+
+#[account]
+pub struct MyAccount {
+    pub field: u32,
+}
+
+#[event]
+pub struct MyEvent {
+    pub value: u32,
+}
diff --git a/tests/declare-program/tests/declare-program.ts b/tests/declare-program/tests/declare-program.ts
new file mode 100644
index 0000000000..0f3f684416
--- /dev/null
+++ b/tests/declare-program/tests/declare-program.ts
@@ -0,0 +1,57 @@
+import * as anchor from "@coral-xyz/anchor";
+import assert from "assert";
+
+import type { DeclareProgram } from "../target/types/declare_program";
+import type { External } from "../target/types/external";
+
+describe("declare-program", () => {
+  anchor.setProvider(anchor.AnchorProvider.env());
+  const program: anchor.Program =
+    anchor.workspace.declareProgram;
+  const externalProgram: anchor.Program = anchor.workspace.external;
+
+  // TODO: Add a utility type that does this?
+  let pubkeys: Awaited<
+    ReturnType<
+      ReturnType["rpcAndKeys"]
+    >
+  >["pubkeys"];
+
+  before(async () => {
+    pubkeys = (await externalProgram.methods.init().rpcAndKeys()).pubkeys;
+  });
+
+  it("Can CPI", async () => {
+    const value = 5;
+    await program.methods
+      .cpi(value)
+      .accounts({ cpiMyAccount: pubkeys.myAccount })
+      .rpc();
+
+    const myAccount = await externalProgram.account.myAccount.fetch(
+      pubkeys.myAccount
+    );
+    assert.strictEqual(myAccount.field, value);
+  });
+
+  it("Can CPI composite", async () => {
+    const value = 3;
+    await program.methods
+      .cpiComposite(value)
+      .accounts({ cpiMyAccount: pubkeys.myAccount })
+      .rpc();
+
+    const myAccount = await externalProgram.account.myAccount.fetch(
+      pubkeys.myAccount
+    );
+    assert.strictEqual(myAccount.field, value);
+  });
+
+  it("Can use account utils", async () => {
+    await program.methods.accountUtils().rpc();
+  });
+
+  it("Can use event utils", async () => {
+    await program.methods.eventUtils().rpc();
+  });
+});
diff --git a/tests/declare-program/tsconfig.json b/tests/declare-program/tsconfig.json
new file mode 100644
index 0000000000..feba6ca17f
--- /dev/null
+++ b/tests/declare-program/tsconfig.json
@@ -0,0 +1,10 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true,
+    "strict": true
+  }
+}
diff --git a/tests/docs/package.json b/tests/docs/package.json
index 0e1f341ab0..7fa3731579 100644
--- a/tests/docs/package.json
+++ b/tests/docs/package.json
@@ -1,6 +1,6 @@
 {
   "name": "errors",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/docs/programs/docs/Cargo.toml b/tests/docs/programs/docs/Cargo.toml
index debe6017ed..b04efa0770 100644
--- a/tests/docs/programs/docs/Cargo.toml
+++ b/tests/docs/programs/docs/Cargo.toml
@@ -11,6 +11,7 @@ name = "errors"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/errors/package.json b/tests/errors/package.json
index 0e1f341ab0..7fa3731579 100644
--- a/tests/errors/package.json
+++ b/tests/errors/package.json
@@ -1,6 +1,6 @@
 {
   "name": "errors",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/errors/programs/errors/Cargo.toml b/tests/errors/programs/errors/Cargo.toml
index de51fd93e3..6e85bf96df 100644
--- a/tests/errors/programs/errors/Cargo.toml
+++ b/tests/errors/programs/errors/Cargo.toml
@@ -2,7 +2,6 @@
 name = "errors"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -12,6 +11,7 @@ name = "errors"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/errors/programs/errors/src/lib.rs b/tests/errors/programs/errors/src/lib.rs
index edc4c755dd..e13d8d4af8 100644
--- a/tests/errors/programs/errors/src/lib.rs
+++ b/tests/errors/programs/errors/src/lib.rs
@@ -131,6 +131,10 @@ mod errors {
         require_gte!(5, 10);
         Ok(())
     }
+
+    pub fn try_into_integer(_ctx: Context) -> Result {
+        Ok(u64::MAX.try_into()?)
+    }
 }
 
 #[derive(Accounts)]
diff --git a/tests/errors/tests/errors.ts b/tests/errors/tests/errors.ts
index b7066d7d17..253fe95bb2 100644
--- a/tests/errors/tests/errors.ts
+++ b/tests/errors/tests/errors.ts
@@ -258,7 +258,7 @@ describe("errors", () => {
             },
           ],
           programId: program.programId,
-          data: program.coder.instruction.encode("signer_error", {}),
+          data: program.coder.instruction.encode("signerError", {}),
         })
       );
       await program.provider.sendAndConfirm(tx);
@@ -604,4 +604,21 @@ describe("errors", () => {
       "Program log: Right: 10",
     ]);
   });
+
+  it("Emits a InvalidNumericConversion error via try_into", async () => {
+    await withLogTest(async () => {
+      try {
+        const tx = await program.methods.tryIntoInteger().rpc();
+        assert.fail(
+          "Unexpected success in creating a transaction that should have failed with `InvalidNumericConversion` error"
+        );
+      } catch (_err) {
+        assert.isTrue(_err instanceof AnchorError);
+        const err: AnchorError = _err;
+        assert.strictEqual(err.error.errorCode.number, 4102);
+      }
+    }, [
+      "Program log: AnchorError occurred. Error Code: InvalidNumericConversion. Error Number: 4102. Error Message: out of range integral type conversion attempted.",
+    ]);
+  });
 });
diff --git a/tests/escrow/Anchor.toml b/tests/escrow/Anchor.toml
index 494e0f3c5f..6639e2a570 100644
--- a/tests/escrow/Anchor.toml
+++ b/tests/escrow/Anchor.toml
@@ -7,11 +7,3 @@ escrow = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run ts-mocha -t 1000000 tests/*.ts"
-
-[features]
-
-[test.validator]
-url = "https://api.mainnet-beta.solana.com"
-
-[[test.validator.clone]]
-address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
diff --git a/tests/escrow/package.json b/tests/escrow/package.json
index 6c3a59f243..fafedc4363 100644
--- a/tests/escrow/package.json
+++ b/tests/escrow/package.json
@@ -1,6 +1,6 @@
 {
   "name": "escrow",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/escrow/programs/escrow/Cargo.toml b/tests/escrow/programs/escrow/Cargo.toml
index 1a75dd327c..e9bf939b3e 100644
--- a/tests/escrow/programs/escrow/Cargo.toml
+++ b/tests/escrow/programs/escrow/Cargo.toml
@@ -2,7 +2,6 @@
 name = "escrow"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/events/package.json b/tests/events/package.json
index 7fc14c4581..f39b99711d 100644
--- a/tests/events/package.json
+++ b/tests/events/package.json
@@ -1,6 +1,6 @@
 {
   "name": "events",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/events/programs/events/Cargo.toml b/tests/events/programs/events/Cargo.toml
index 7b00b1a898..2c118a9b23 100644
--- a/tests/events/programs/events/Cargo.toml
+++ b/tests/events/programs/events/Cargo.toml
@@ -2,7 +2,6 @@
 name = "events"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["event-cpi"] }
diff --git a/tests/events/tests/events.ts b/tests/events/tests/events.ts
index d342948d88..7cd2333a78 100644
--- a/tests/events/tests/events.ts
+++ b/tests/events/tests/events.ts
@@ -27,15 +27,15 @@ describe("Events", () => {
 
   describe("Normal event", () => {
     it("Single event works", async () => {
-      const event = await getEvent("MyEvent", "initialize");
+      const event = await getEvent("myEvent", "initialize");
 
       assert.strictEqual(event.data.toNumber(), 5);
       assert.strictEqual(event.label, "hello");
     });
 
     it("Multiple events work", async () => {
-      const eventOne = await getEvent("MyEvent", "initialize");
-      const eventTwo = await getEvent("MyOtherEvent", "testEvent");
+      const eventOne = await getEvent("myEvent", "initialize");
+      const eventTwo = await getEvent("myOtherEvent", "testEvent");
 
       assert.strictEqual(eventOne.data.toNumber(), 5);
       assert.strictEqual(eventOne.label, "hello");
@@ -61,7 +61,7 @@ describe("Events", () => {
       const eventData = anchor.utils.bytes.base64.encode(ixData.slice(8));
       const event = program.coder.events.decode(eventData);
 
-      assert.strictEqual(event.name, "MyOtherEvent");
+      assert.strictEqual(event.name, "myOtherEvent");
       assert.strictEqual(event.data.label, "cpi");
       assert.strictEqual((event.data.data as anchor.BN).toNumber(), 7);
     });
diff --git a/tests/floats/package.json b/tests/floats/package.json
index 8311b0f875..be38a18bb9 100644
--- a/tests/floats/package.json
+++ b/tests/floats/package.json
@@ -1,6 +1,6 @@
 {
     "name": "floats",
-    "version": "0.29.0",
+    "version": "0.30.1",
     "license": "(MIT OR Apache-2.0)",
     "homepage": "https://github.com/coral-xyz/anchor#readme",
     "bugs": {
diff --git a/tests/floats/programs/floats/Cargo.toml b/tests/floats/programs/floats/Cargo.toml
index c9a4a2b4ab..77d8ca37c1 100644
--- a/tests/floats/programs/floats/Cargo.toml
+++ b/tests/floats/programs/floats/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/idl/Anchor.toml b/tests/idl/Anchor.toml
index eed2cd3684..d5f7fcc491 100644
--- a/tests/idl/Anchor.toml
+++ b/tests/idl/Anchor.toml
@@ -1,16 +1,15 @@
 [features]
-seeds = true
+skip-lint = true
 
 [programs.localnet]
-client_interactions = "C1ient1nteractions1111111111111111111111111"
 docs = "Docs111111111111111111111111111111111111111"
 external = "Externa1111111111111111111111111111111111111"
 generics = "Generics111111111111111111111111111111111111"
 idl = "id11111111111111111111111111111111111111111"
-idl_build_features = "id1Bui1dFeatures111111111111111111111111111"
 relations_derivation = "Re1ationsDerivation111111111111111111111111"
 non_existent = { address = "NonExistent11111111111111111111111111111111", idl = "non-existent.json" }
-numbers_123 = { address = "Numbers111111111111111111111111111111111111", idl = "idls/relations_build.json" }
+numbers_123 = { address = "Numbers111111111111111111111111111111111111", idl = "idls/relations.json" }
+new_idl = "Newid11111111111111111111111111111111111111"
 
 [provider]
 cluster = "localnet"
diff --git a/tests/idl/generate.sh b/tests/idl/generate.sh
index 99c792d2e9..075da596fb 100755
--- a/tests/idl/generate.sh
+++ b/tests/idl/generate.sh
@@ -8,11 +8,10 @@ else
 fi
 
 cd programs/idl
-anchor idl parse --file src/lib.rs -o $dir/parse.json
-anchor idl build -o $dir/build.json
+anchor idl build -o $dir/new.json
 
 cd ../generics
-anchor idl build -o $dir/generics_build.json
+anchor idl build -o $dir/generics.json
 
 cd ../relations-derivation
-anchor idl build -o $dir/relations_build.json
\ No newline at end of file
+anchor idl build -o $dir/relations.json
diff --git a/tests/idl/idls/generics_build.json b/tests/idl/idls/generics.json
similarity index 66%
rename from tests/idl/idls/generics_build.json
rename to tests/idl/idls/generics.json
index a3fda000c3..8fb229925e 100644
--- a/tests/idl/idls/generics_build.json
+++ b/tests/idl/idls/generics.json
@@ -1,40 +1,55 @@
 {
-  "version": "0.1.0",
-  "name": "generics",
+  "address": "Generics111111111111111111111111111111111111",
+  "metadata": {
+    "name": "generics",
+    "version": "0.1.0",
+    "spec": "0.1.0",
+    "description": "Created with Anchor"
+  },
   "instructions": [
     {
       "name": "generic",
+      "discriminator": [
+        63,
+        235,
+        150,
+        148,
+        7,
+        255,
+        185,
+        159
+      ],
       "accounts": [
         {
-          "name": "genericAcc",
-          "isMut": false,
-          "isSigner": false
+          "name": "generic_acc"
         },
         {
           "name": "payer",
-          "isMut": true,
-          "isSigner": true
+          "writable": true,
+          "signer": true
         },
         {
-          "name": "systemProgram",
-          "isMut": false,
-          "isSigner": false
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
         }
       ],
       "args": [
         {
-          "name": "genericField",
+          "name": "generic_field",
           "type": {
-            "definedWithTypeArgs": {
+            "defined": {
               "name": "GenericType",
-              "args": [
+              "generics": [
                 {
+                  "kind": "type",
                   "type": "u32"
                 },
                 {
+                  "kind": "type",
                   "type": "u64"
                 },
                 {
+                  "kind": "const",
                   "value": "10"
                 }
               ]
@@ -45,6 +60,21 @@
     }
   ],
   "accounts": [
+    {
+      "name": "GenericAccount",
+      "discriminator": [
+        10,
+        71,
+        68,
+        49,
+        51,
+        72,
+        147,
+        245
+      ]
+    }
+  ],
+  "types": [
     {
       "name": "GenericAccount",
       "type": {
@@ -53,16 +83,19 @@
           {
             "name": "data",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericType",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": "u32"
                   },
                   {
+                    "kind": "type",
                     "type": "u64"
                   },
                   {
+                    "kind": "const",
                     "value": "10"
                   }
                 ]
@@ -71,27 +104,23 @@
           }
         ]
       }
-    }
-  ],
-  "types": [
-    {
-      "name": "Baz",
-      "type": {
-        "kind": "struct",
-        "fields": [
-          {
-            "name": "someField",
-            "type": "u8"
-          }
-        ]
-      }
     },
     {
       "name": "GenericEnum",
       "generics": [
-        "T",
-        "U",
-        "N"
+        {
+          "kind": "type",
+          "name": "T"
+        },
+        {
+          "kind": "type",
+          "name": "U"
+        },
+        {
+          "kind": "const",
+          "name": "N",
+          "type": "usize"
+        }
       ],
       "type": {
         "kind": "enum",
@@ -128,15 +157,17 @@
             "name": "Struct",
             "fields": [
               {
-                "definedWithTypeArgs": {
+                "defined": {
                   "name": "GenericNested",
-                  "args": [
+                  "generics": [
                     {
+                      "kind": "type",
                       "type": {
                         "generic": "T"
                       }
                     },
                     {
+                      "kind": "type",
                       "type": {
                         "generic": "U"
                       }
@@ -150,11 +181,13 @@
             "name": "Arr",
             "fields": [
               {
-                "genericLenArray": [
+                "array": [
                   {
                     "generic": "T"
                   },
-                  "N"
+                  {
+                    "generic": "N"
+                  }
                 ]
               }
             ]
@@ -165,8 +198,14 @@
     {
       "name": "GenericNested",
       "generics": [
-        "V",
-        "Z"
+        {
+          "kind": "type",
+          "name": "V"
+        },
+        {
+          "kind": "type",
+          "name": "Z"
+        }
       ],
       "type": {
         "kind": "struct",
@@ -189,9 +228,19 @@
     {
       "name": "GenericType",
       "generics": [
-        "T",
-        "U",
-        "N"
+        {
+          "kind": "type",
+          "name": "T"
+        },
+        {
+          "kind": "type",
+          "name": "U"
+        },
+        {
+          "kind": "const",
+          "name": "N",
+          "type": "usize"
+        }
       ],
       "type": {
         "kind": "struct",
@@ -211,13 +260,15 @@
           {
             "name": "gen3",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericNested",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": "u32"
                   },
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "U"
                     }
@@ -229,17 +280,21 @@
           {
             "name": "gen4",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericNested",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "T"
                     }
                   },
                   {
+                    "kind": "type",
                     "type": {
-                      "defined": "Baz"
+                      "defined": {
+                        "name": "MyStruct"
+                      }
                     }
                   }
                 ]
@@ -249,15 +304,17 @@
           {
             "name": "gen5",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericNested",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "T"
                     }
                   },
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "U"
                     }
@@ -269,13 +326,15 @@
           {
             "name": "gen6",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericNested",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": "u32"
                   },
                   {
+                    "kind": "type",
                     "type": "u64"
                   }
                 ]
@@ -285,25 +344,29 @@
           {
             "name": "gen7",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericNested",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "T"
                     }
                   },
                   {
+                    "kind": "type",
                     "type": {
-                      "definedWithTypeArgs": {
+                      "defined": {
                         "name": "GenericNested",
-                        "args": [
+                        "generics": [
                           {
+                            "kind": "type",
                             "type": {
                               "generic": "T"
                             }
                           },
                           {
+                            "kind": "type",
                             "type": {
                               "generic": "U"
                             }
@@ -319,19 +382,22 @@
           {
             "name": "arr",
             "type": {
-              "genericLenArray": [
+              "array": [
                 "u8",
-                "N"
+                {
+                  "generic": "N"
+                }
               ]
             }
           },
           {
             "name": "warr",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "WrappedU8Array",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "N"
                     }
@@ -343,10 +409,11 @@
           {
             "name": "warrval",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "WrappedU8Array",
-                "args": [
+                "generics": [
                   {
+                    "kind": "const",
                     "value": "10"
                   }
                 ]
@@ -356,20 +423,23 @@
           {
             "name": "enm1",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericEnum",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "T"
                     }
                   },
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "U"
                     }
                   },
                   {
+                    "kind": "type",
                     "type": {
                       "generic": "N"
                     }
@@ -381,20 +451,23 @@
           {
             "name": "enm2",
             "type": {
-              "definedWithTypeArgs": {
+              "defined": {
                 "name": "GenericEnum",
-                "args": [
+                "generics": [
                   {
+                    "kind": "type",
                     "type": {
-                      "definedWithTypeArgs": {
+                      "defined": {
                         "name": "GenericNested",
-                        "args": [
+                        "generics": [
                           {
+                            "kind": "type",
                             "type": {
                               "generic": "T"
                             }
                           },
                           {
+                            "kind": "type",
                             "type": "u64"
                           }
                         ]
@@ -402,9 +475,11 @@
                     }
                   },
                   {
+                    "kind": "type",
                     "type": "u32"
                   },
                   {
+                    "kind": "const",
                     "value": "30"
                   }
                 ]
@@ -413,6 +488,34 @@
           }
         ]
       }
+    },
+    {
+      "name": "MyStruct",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "some_field",
+            "type": "u8"
+          }
+        ]
+      }
+    },
+    {
+      "name": "WrappedU8Array",
+      "generics": [
+        {
+          "kind": "const",
+          "name": "N",
+          "type": "usize"
+        }
+      ],
+      "type": {
+        "kind": "struct",
+        "fields": [
+          "u8"
+        ]
+      }
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/idl/idls/build.json b/tests/idl/idls/new.json
similarity index 54%
rename from tests/idl/idls/build.json
rename to tests/idl/idls/new.json
index 0ced23b634..40ff4f1443 100644
--- a/tests/idl/idls/build.json
+++ b/tests/idl/idls/new.json
@@ -1,268 +1,266 @@
 {
-  "version": "0.1.0",
-  "name": "idl",
+  "address": "id11111111111111111111111111111111111111111",
+  "metadata": {
+    "name": "idl",
+    "version": "0.1.0",
+    "spec": "0.1.0",
+    "description": "Created with Anchor"
+  },
   "docs": [
     "IDL test program documentation."
   ],
-  "constants": [
-    {
-      "name": "BYTES_STR",
-      "type": "bytes",
-      "value": "[116, 101, 115, 116]"
-    },
-    {
-      "name": "BYTE_STR",
-      "type": "u8",
-      "value": "116"
-    },
+  "instructions": [
     {
-      "name": "I128",
-      "type": "i128",
-      "value": "1000000"
+      "name": "cause_error",
+      "discriminator": [
+        67,
+        104,
+        37,
+        17,
+        2,
+        155,
+        68,
+        17
+      ],
+      "accounts": [],
+      "args": []
     },
-    {
-      "name": "U8",
-      "type": "u8",
-      "value": "6"
-    }
-  ],
-  "instructions": [
     {
       "name": "initialize",
+      "discriminator": [
+        175,
+        175,
+        109,
+        31,
+        13,
+        152,
+        155,
+        237
+      ],
       "accounts": [
         {
           "name": "state",
-          "isMut": true,
-          "isSigner": true,
           "docs": [
             "State account"
-          ]
+          ],
+          "writable": true,
+          "signer": true
         },
         {
           "name": "nested",
           "accounts": [
             {
               "name": "clock",
-              "isMut": false,
-              "isSigner": false,
               "docs": [
                 "Sysvar clock"
-              ]
+              ],
+              "address": "SysvarC1ock11111111111111111111111111111111"
             },
             {
               "name": "rent",
-              "isMut": false,
-              "isSigner": false
+              "address": "SysvarRent111111111111111111111111111111111"
             }
           ]
         },
         {
-          "name": "zcAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "zc_account"
         },
         {
-          "name": "tokenAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "token_account"
         },
         {
-          "name": "mintAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "mint_account"
         },
         {
-          "name": "tokenInterfaceAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "token_interface_account"
         },
         {
-          "name": "mintInterfaceAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "mint_interface_account"
         },
         {
           "name": "payer",
-          "isMut": true,
-          "isSigner": true
+          "writable": true,
+          "signer": true
         },
         {
-          "name": "systemProgram",
-          "isMut": false,
-          "isSigner": false
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
         }
       ],
       "args": []
     },
     {
-      "name": "initializeWithValues",
+      "name": "initialize_with_values",
       "docs": [
         "Initializes an account with specified values"
       ],
+      "discriminator": [
+        220,
+        73,
+        8,
+        213,
+        178,
+        69,
+        181,
+        141
+      ],
       "accounts": [
         {
           "name": "state",
-          "isMut": true,
-          "isSigner": true,
           "docs": [
             "State account"
-          ]
+          ],
+          "writable": true,
+          "signer": true
         },
         {
           "name": "nested",
           "accounts": [
             {
               "name": "clock",
-              "isMut": false,
-              "isSigner": false,
               "docs": [
                 "Sysvar clock"
-              ]
+              ],
+              "address": "SysvarC1ock11111111111111111111111111111111"
             },
             {
               "name": "rent",
-              "isMut": false,
-              "isSigner": false
+              "address": "SysvarRent111111111111111111111111111111111"
             }
           ]
         },
         {
-          "name": "zcAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "zc_account"
         },
         {
-          "name": "tokenAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "token_account"
         },
         {
-          "name": "mintAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "mint_account"
         },
         {
-          "name": "tokenInterfaceAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "token_interface_account"
         },
         {
-          "name": "mintInterfaceAccount",
-          "isMut": false,
-          "isSigner": false
+          "name": "mint_interface_account"
         },
         {
           "name": "payer",
-          "isMut": true,
-          "isSigner": true
+          "writable": true,
+          "signer": true
         },
         {
-          "name": "systemProgram",
-          "isMut": false,
-          "isSigner": false
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
         }
       ],
       "args": [
         {
-          "name": "boolField",
+          "name": "bool_field",
           "type": "bool"
         },
         {
-          "name": "u8Field",
+          "name": "u8_field",
           "type": "u8"
         },
         {
-          "name": "i8Field",
+          "name": "i8_field",
           "type": "i8"
         },
         {
-          "name": "u16Field",
+          "name": "u16_field",
           "type": "u16"
         },
         {
-          "name": "i16Field",
+          "name": "i16_field",
           "type": "i16"
         },
         {
-          "name": "u32Field",
+          "name": "u32_field",
           "type": "u32"
         },
         {
-          "name": "i32Field",
+          "name": "i32_field",
           "type": "i32"
         },
         {
-          "name": "f32Field",
+          "name": "f32_field",
           "type": "f32"
         },
         {
-          "name": "u64Field",
+          "name": "u64_field",
           "type": "u64"
         },
         {
-          "name": "i64Field",
+          "name": "i64_field",
           "type": "i64"
         },
         {
-          "name": "f64Field",
+          "name": "f64_field",
           "type": "f64"
         },
         {
-          "name": "u128Field",
+          "name": "u128_field",
           "type": "u128"
         },
         {
-          "name": "i128Field",
+          "name": "i128_field",
           "type": "i128"
         },
         {
-          "name": "bytesField",
+          "name": "bytes_field",
           "type": "bytes"
         },
         {
-          "name": "stringField",
+          "name": "string_field",
           "type": "string"
         },
         {
-          "name": "pubkeyField",
-          "type": "publicKey"
+          "name": "pubkey_field",
+          "type": "pubkey"
         },
         {
-          "name": "vecField",
+          "name": "vec_field",
           "type": {
             "vec": "u64"
           }
         },
         {
-          "name": "vecStructField",
+          "name": "vec_struct_field",
           "type": {
             "vec": {
-              "defined": "FooStruct"
+              "defined": {
+                "name": "FooStruct"
+              }
             }
           }
         },
         {
-          "name": "optionField",
+          "name": "option_field",
           "type": {
             "option": "bool"
           }
         },
         {
-          "name": "optionStructField",
+          "name": "option_struct_field",
           "type": {
             "option": {
-              "defined": "FooStruct"
+              "defined": {
+                "name": "FooStruct"
+              }
             }
           }
         },
         {
-          "name": "structField",
+          "name": "struct_field",
           "type": {
-            "defined": "FooStruct"
+            "defined": {
+              "name": "FooStruct"
+            }
           }
         },
         {
-          "name": "arrayField",
+          "name": "array_field",
           "type": {
             "array": [
               "bool",
@@ -271,57 +269,74 @@
           }
         },
         {
-          "name": "enumField1",
+          "name": "enum_field_1",
           "type": {
-            "defined": "FooEnum"
+            "defined": {
+              "name": "FooEnum"
+            }
           }
         },
         {
-          "name": "enumField2",
+          "name": "enum_field_2",
           "type": {
-            "defined": "FooEnum"
+            "defined": {
+              "name": "FooEnum"
+            }
           }
         },
         {
-          "name": "enumField3",
+          "name": "enum_field_3",
           "type": {
-            "defined": "FooEnum"
+            "defined": {
+              "name": "FooEnum"
+            }
           }
         },
         {
-          "name": "enumField4",
+          "name": "enum_field_4",
           "type": {
-            "defined": "FooEnum"
+            "defined": {
+              "name": "FooEnum"
+            }
           }
         }
       ]
     },
     {
-      "name": "initializeWithValues2",
+      "name": "initialize_with_values2",
       "docs": [
         "a separate instruction due to initialize_with_values having too many arguments",
         "https://github.com/solana-labs/solana/issues/23978"
       ],
+      "discriminator": [
+        248,
+        190,
+        21,
+        97,
+        239,
+        148,
+        39,
+        181
+      ],
       "accounts": [
         {
           "name": "state",
-          "isMut": true,
-          "isSigner": true
+          "writable": true,
+          "signer": true
         },
         {
           "name": "payer",
-          "isMut": true,
-          "isSigner": true
+          "writable": true,
+          "signer": true
         },
         {
-          "name": "systemProgram",
-          "isMut": false,
-          "isSigner": false
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
         }
       ],
       "args": [
         {
-          "name": "vecOfOption",
+          "name": "vec_of_option",
           "type": {
             "vec": {
               "option": "u64"
@@ -329,214 +344,90 @@
           }
         },
         {
-          "name": "boxField",
+          "name": "box_field",
           "type": "bool"
         }
       ],
       "returns": {
-        "defined": "SomeRetStruct"
+        "defined": {
+          "name": "SomeRetStruct"
+        }
       }
-    },
-    {
-      "name": "causeError",
-      "accounts": [],
-      "args": []
     }
   ],
   "accounts": [
     {
       "name": "SomeZcAccount",
-      "type": {
-        "kind": "struct",
-        "fields": [
-          {
-            "name": "field",
-            "type": {
-              "defined": "ZcStruct"
-            }
-          }
-        ]
-      }
+      "discriminator": [
+        56,
+        72,
+        82,
+        194,
+        210,
+        35,
+        17,
+        191
+      ]
     },
     {
       "name": "State",
-      "docs": [
-        "An account containing various fields"
-      ],
-      "type": {
-        "kind": "struct",
-        "fields": [
-          {
-            "name": "boolField",
-            "docs": [
-              "A boolean field"
-            ],
-            "type": "bool"
-          },
-          {
-            "name": "u8Field",
-            "type": "u8"
-          },
-          {
-            "name": "i8Field",
-            "type": "i8"
-          },
-          {
-            "name": "u16Field",
-            "type": "u16"
-          },
-          {
-            "name": "i16Field",
-            "type": "i16"
-          },
-          {
-            "name": "u32Field",
-            "type": "u32"
-          },
-          {
-            "name": "i32Field",
-            "type": "i32"
-          },
-          {
-            "name": "f32Field",
-            "type": "f32"
-          },
-          {
-            "name": "u64Field",
-            "type": "u64"
-          },
-          {
-            "name": "i64Field",
-            "type": "i64"
-          },
-          {
-            "name": "f64Field",
-            "type": "f64"
-          },
-          {
-            "name": "u128Field",
-            "type": "u128"
-          },
-          {
-            "name": "i128Field",
-            "type": "i128"
-          },
-          {
-            "name": "bytesField",
-            "type": "bytes"
-          },
-          {
-            "name": "stringField",
-            "type": "string"
-          },
-          {
-            "name": "pubkeyField",
-            "type": "publicKey"
-          },
-          {
-            "name": "vecField",
-            "type": {
-              "vec": "u64"
-            }
-          },
-          {
-            "name": "vecStructField",
-            "type": {
-              "vec": {
-                "defined": "FooStruct"
-              }
-            }
-          },
-          {
-            "name": "optionField",
-            "type": {
-              "option": "bool"
-            }
-          },
-          {
-            "name": "optionStructField",
-            "type": {
-              "option": {
-                "defined": "FooStruct"
-              }
-            }
-          },
-          {
-            "name": "structField",
-            "type": {
-              "defined": "FooStruct"
-            }
-          },
-          {
-            "name": "arrayField",
-            "type": {
-              "array": [
-                "bool",
-                3
-              ]
-            }
-          },
-          {
-            "name": "enumField1",
-            "type": {
-              "defined": "FooEnum"
-            }
-          },
-          {
-            "name": "enumField2",
-            "type": {
-              "defined": "FooEnum"
-            }
-          },
-          {
-            "name": "enumField3",
-            "type": {
-              "defined": "FooEnum"
-            }
-          },
-          {
-            "name": "enumField4",
-            "type": {
-              "defined": "FooEnum"
-            }
-          }
-        ]
-      }
+      "discriminator": [
+        216,
+        146,
+        107,
+        94,
+        104,
+        75,
+        182,
+        177
+      ]
     },
     {
       "name": "State2",
-      "type": {
-        "kind": "struct",
-        "fields": [
-          {
-            "name": "vecOfOption",
-            "type": {
-              "vec": {
-                "option": "u64"
-              }
-            }
-          },
-          {
-            "name": "boxField",
-            "type": "bool"
-          }
-        ]
-      }
+      "discriminator": [
+        106,
+        97,
+        255,
+        161,
+        250,
+        205,
+        185,
+        192
+      ]
     }
   ],
-  "types": [
+  "events": [
     {
-      "name": "external::Baz",
-      "type": {
-        "kind": "struct",
-        "fields": [
-          {
-            "name": "someField",
-            "type": "u8"
-          }
-        ]
-      }
+      "name": "SomeEvent",
+      "discriminator": [
+        39,
+        221,
+        150,
+        148,
+        91,
+        206,
+        29,
+        93
+      ]
+    }
+  ],
+  "errors": [
+    {
+      "code": 6000,
+      "name": "SomeError",
+      "msg": "Example error."
     },
+    {
+      "code": 6001,
+      "name": "OtherError",
+      "msg": "Another error."
+    },
+    {
+      "code": 6002,
+      "name": "ErrorWithoutMsg"
+    }
+  ],
+  "types": [
     {
       "name": "BarStruct",
       "docs": [
@@ -546,14 +437,14 @@
         "kind": "struct",
         "fields": [
           {
-            "name": "someField",
+            "name": "some_field",
             "docs": [
               "Some field"
             ],
             "type": "bool"
           },
           {
-            "name": "otherField",
+            "name": "other_field",
             "type": "u8"
           }
         ]
@@ -573,7 +464,9 @@
               "bool",
               "u8",
               {
-                "defined": "BarStruct"
+                "defined": {
+                  "name": "BarStruct"
+                }
               }
             ]
           },
@@ -581,7 +474,9 @@
             "name": "UnnamedSingle",
             "fields": [
               {
-                "defined": "BarStruct"
+                "defined": {
+                  "name": "BarStruct"
+                }
               }
             ]
           },
@@ -589,20 +484,22 @@
             "name": "Named",
             "fields": [
               {
-                "name": "boolField",
+                "name": "bool_field",
                 "docs": [
                   "A bool field inside a struct tuple kind"
                 ],
                 "type": "bool"
               },
               {
-                "name": "u8Field",
+                "name": "u8_field",
                 "type": "u8"
               },
               {
                 "name": "nested",
                 "type": {
-                  "defined": "BarStruct"
+                  "defined": {
+                    "name": "BarStruct"
+                  }
                 }
               }
             ]
@@ -611,7 +508,9 @@
             "name": "Struct",
             "fields": [
               {
-                "defined": "BarStruct"
+                "defined": {
+                  "name": "BarStruct"
+                }
               }
             ]
           },
@@ -620,7 +519,9 @@
             "fields": [
               {
                 "option": {
-                  "defined": "BarStruct"
+                  "defined": {
+                    "name": "BarStruct"
+                  }
                 }
               }
             ]
@@ -630,7 +531,9 @@
             "fields": [
               {
                 "vec": {
-                  "defined": "BarStruct"
+                  "defined": {
+                    "name": "BarStruct"
+                  }
                 }
               }
             ]
@@ -657,29 +560,65 @@
           {
             "name": "nested",
             "type": {
-              "defined": "BarStruct"
+              "defined": {
+                "name": "BarStruct"
+              }
             }
           },
           {
-            "name": "vecNested",
+            "name": "vec_nested",
             "type": {
               "vec": {
-                "defined": "BarStruct"
+                "defined": {
+                  "name": "BarStruct"
+                }
               }
             }
           },
           {
-            "name": "optionNested",
+            "name": "option_nested",
             "type": {
               "option": {
-                "defined": "BarStruct"
+                "defined": {
+                  "name": "BarStruct"
+                }
+              }
+            }
+          },
+          {
+            "name": "enum_field",
+            "type": {
+              "defined": {
+                "name": "FooEnum"
+              }
+            }
+          }
+        ]
+      }
+    },
+    {
+      "name": "SomeEvent",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "bool_field",
+            "type": "bool"
+          },
+          {
+            "name": "external_my_struct",
+            "type": {
+              "defined": {
+                "name": "external::MyStruct"
               }
             }
           },
           {
-            "name": "enumField",
+            "name": "other_module_my_struct",
             "type": {
-              "defined": "FooEnum"
+              "defined": {
+                "name": "idl::some_other_module::MyStruct"
+              }
             }
           }
         ]
@@ -691,77 +630,272 @@
         "kind": "struct",
         "fields": [
           {
-            "name": "someField",
+            "name": "some_field",
             "type": "u8"
           }
         ]
       }
     },
+    {
+      "name": "SomeZcAccount",
+      "serialization": "bytemuck",
+      "repr": {
+        "kind": "c"
+      },
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "field",
+            "type": {
+              "defined": {
+                "name": "ZcStruct"
+              }
+            }
+          }
+        ]
+      }
+    },
+    {
+      "name": "State",
+      "docs": [
+        "An account containing various fields"
+      ],
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "bool_field",
+            "docs": [
+              "A boolean field"
+            ],
+            "type": "bool"
+          },
+          {
+            "name": "u8_field",
+            "type": "u8"
+          },
+          {
+            "name": "i8_field",
+            "type": "i8"
+          },
+          {
+            "name": "u16_field",
+            "type": "u16"
+          },
+          {
+            "name": "i16_field",
+            "type": "i16"
+          },
+          {
+            "name": "u32_field",
+            "type": "u32"
+          },
+          {
+            "name": "i32_field",
+            "type": "i32"
+          },
+          {
+            "name": "f32_field",
+            "type": "f32"
+          },
+          {
+            "name": "u64_field",
+            "type": "u64"
+          },
+          {
+            "name": "i64_field",
+            "type": "i64"
+          },
+          {
+            "name": "f64_field",
+            "type": "f64"
+          },
+          {
+            "name": "u128_field",
+            "type": "u128"
+          },
+          {
+            "name": "i128_field",
+            "type": "i128"
+          },
+          {
+            "name": "bytes_field",
+            "type": "bytes"
+          },
+          {
+            "name": "string_field",
+            "type": "string"
+          },
+          {
+            "name": "pubkey_field",
+            "type": "pubkey"
+          },
+          {
+            "name": "vec_field",
+            "type": {
+              "vec": "u64"
+            }
+          },
+          {
+            "name": "vec_struct_field",
+            "type": {
+              "vec": {
+                "defined": {
+                  "name": "FooStruct"
+                }
+              }
+            }
+          },
+          {
+            "name": "option_field",
+            "type": {
+              "option": "bool"
+            }
+          },
+          {
+            "name": "option_struct_field",
+            "type": {
+              "option": {
+                "defined": {
+                  "name": "FooStruct"
+                }
+              }
+            }
+          },
+          {
+            "name": "struct_field",
+            "type": {
+              "defined": {
+                "name": "FooStruct"
+              }
+            }
+          },
+          {
+            "name": "array_field",
+            "type": {
+              "array": [
+                "bool",
+                3
+              ]
+            }
+          },
+          {
+            "name": "enum_field_1",
+            "type": {
+              "defined": {
+                "name": "FooEnum"
+              }
+            }
+          },
+          {
+            "name": "enum_field_2",
+            "type": {
+              "defined": {
+                "name": "FooEnum"
+              }
+            }
+          },
+          {
+            "name": "enum_field_3",
+            "type": {
+              "defined": {
+                "name": "FooEnum"
+              }
+            }
+          },
+          {
+            "name": "enum_field_4",
+            "type": {
+              "defined": {
+                "name": "FooEnum"
+              }
+            }
+          }
+        ]
+      }
+    },
+    {
+      "name": "State2",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "vec_of_option",
+            "type": {
+              "vec": {
+                "option": "u64"
+              }
+            }
+          },
+          {
+            "name": "box_field",
+            "type": "bool"
+          }
+        ]
+      }
+    },
     {
       "name": "ZcStruct",
+      "serialization": "bytemuck",
+      "repr": {
+        "kind": "c"
+      },
       "type": {
         "kind": "struct",
         "fields": [
           {
-            "name": "someField",
+            "name": "some_field",
             "type": "u16"
           }
         ]
       }
     },
     {
-      "name": "idl::some_other_module::Baz",
+      "name": "external::MyStruct",
       "type": {
         "kind": "struct",
         "fields": [
           {
-            "name": "someU8",
+            "name": "some_field",
             "type": "u8"
           }
         ]
       }
-    }
-  ],
-  "events": [
+    },
     {
-      "name": "SomeEvent",
-      "fields": [
-        {
-          "name": "boolField",
-          "type": "bool",
-          "index": false
-        },
-        {
-          "name": "externalBaz",
-          "type": {
-            "defined": "external::Baz"
-          },
-          "index": false
-        },
-        {
-          "name": "otherModuleBaz",
-          "type": {
-            "defined": "idl::some_other_module::Baz"
-          },
-          "index": false
-        }
-      ]
+      "name": "idl::some_other_module::MyStruct",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "some_u8",
+            "type": "u8"
+          }
+        ]
+      }
     }
   ],
-  "errors": [
+  "constants": [
     {
-      "code": 6000,
-      "name": "SomeError",
-      "msg": "Example error."
+      "name": "BYTES_STR",
+      "type": "bytes",
+      "value": "[116, 101, 115, 116]"
     },
     {
-      "code": 6001,
-      "name": "OtherError",
-      "msg": "Another error."
+      "name": "BYTE_STR",
+      "type": "u8",
+      "value": "116"
     },
     {
-      "code": 6002,
-      "name": "ErrorWithoutMsg"
+      "name": "I128",
+      "type": "i128",
+      "value": "1000000"
+    },
+    {
+      "name": "U8",
+      "type": "u8",
+      "value": "6"
     }
   ]
 }
\ No newline at end of file
diff --git a/tests/idl/idls/parse.json b/tests/idl/idls/old.json
similarity index 98%
rename from tests/idl/idls/parse.json
rename to tests/idl/idls/old.json
index 3648844023..dac25cd03c 100644
--- a/tests/idl/idls/parse.json
+++ b/tests/idl/idls/old.json
@@ -526,7 +526,7 @@
   ],
   "types": [
     {
-      "name": "Baz",
+      "name": "MyStruct",
       "type": {
         "kind": "struct",
         "fields": [
@@ -720,16 +720,16 @@
           "index": false
         },
         {
-          "name": "externalBaz",
+          "name": "externalMyStruct",
           "type": {
-            "defined": "external::Baz"
+            "defined": "external::MyStruct"
           },
           "index": false
         },
         {
-          "name": "otherModuleBaz",
+          "name": "otherModuleMyStruct",
           "type": {
-            "defined": "some_other_module::Baz"
+            "defined": "some_other_module::MyStruct"
           },
           "index": false
         }
diff --git a/tests/idl/idls/relations.json b/tests/idl/idls/relations.json
new file mode 100644
index 0000000000..6418651649
--- /dev/null
+++ b/tests/idl/idls/relations.json
@@ -0,0 +1,151 @@
+{
+  "address": "Re1ationsDerivation111111111111111111111111",
+  "metadata": {
+    "name": "relations_derivation",
+    "version": "0.1.0",
+    "spec": "0.1.0",
+    "description": "Created with Anchor"
+  },
+  "instructions": [
+    {
+      "name": "init_base",
+      "discriminator": [
+        85,
+        87,
+        185,
+        141,
+        241,
+        191,
+        213,
+        88
+      ],
+      "accounts": [
+        {
+          "name": "my_account",
+          "writable": true,
+          "signer": true
+        },
+        {
+          "name": "account",
+          "writable": true,
+          "pda": {
+            "seeds": [
+              {
+                "kind": "const",
+                "value": [
+                  115,
+                  101,
+                  101,
+                  100
+                ]
+              }
+            ]
+          }
+        },
+        {
+          "name": "system_program",
+          "address": "11111111111111111111111111111111"
+        }
+      ],
+      "args": []
+    },
+    {
+      "name": "test_relation",
+      "discriminator": [
+        247,
+        199,
+        255,
+        202,
+        7,
+        0,
+        197,
+        158
+      ],
+      "accounts": [
+        {
+          "name": "my_account",
+          "relations": [
+            "account"
+          ]
+        },
+        {
+          "name": "account",
+          "pda": {
+            "seeds": [
+              {
+                "kind": "const",
+                "value": [
+                  115,
+                  101,
+                  101,
+                  100
+                ]
+              }
+            ]
+          }
+        },
+        {
+          "name": "nested",
+          "accounts": [
+            {
+              "name": "my_account",
+              "relations": [
+                "account"
+              ]
+            },
+            {
+              "name": "account",
+              "pda": {
+                "seeds": [
+                  {
+                    "kind": "const",
+                    "value": [
+                      115,
+                      101,
+                      101,
+                      100
+                    ]
+                  }
+                ]
+              }
+            }
+          ]
+        }
+      ],
+      "args": []
+    }
+  ],
+  "accounts": [
+    {
+      "name": "MyAccount",
+      "discriminator": [
+        246,
+        28,
+        6,
+        87,
+        251,
+        45,
+        50,
+        42
+      ]
+    }
+  ],
+  "types": [
+    {
+      "name": "MyAccount",
+      "type": {
+        "kind": "struct",
+        "fields": [
+          {
+            "name": "my_account",
+            "type": "pubkey"
+          },
+          {
+            "name": "bump",
+            "type": "u8"
+          }
+        ]
+      }
+    }
+  ]
+}
\ No newline at end of file
diff --git a/tests/idl/idls/relations_build.json b/tests/idl/idls/relations_build.json
deleted file mode 100644
index bf70c7fc1d..0000000000
--- a/tests/idl/idls/relations_build.json
+++ /dev/null
@@ -1,82 +0,0 @@
-{
-  "version": "0.1.0",
-  "name": "relations_derivation",
-  "instructions": [
-    {
-      "name": "initBase",
-      "accounts": [
-        {
-          "name": "myAccount",
-          "isMut": true,
-          "isSigner": true
-        },
-        {
-          "name": "account",
-          "isMut": true,
-          "isSigner": false
-        },
-        {
-          "name": "systemProgram",
-          "isMut": false,
-          "isSigner": false
-        }
-      ],
-      "args": []
-    },
-    {
-      "name": "testRelation",
-      "accounts": [
-        {
-          "name": "myAccount",
-          "isMut": false,
-          "isSigner": false
-        },
-        {
-          "name": "account",
-          "isMut": false,
-          "isSigner": false,
-          "relations": [
-            "my_account"
-          ]
-        },
-        {
-          "name": "nested",
-          "accounts": [
-            {
-              "name": "myAccount",
-              "isMut": false,
-              "isSigner": false
-            },
-            {
-              "name": "account",
-              "isMut": false,
-              "isSigner": false,
-              "relations": [
-                "my_account"
-              ]
-            }
-          ]
-        }
-      ],
-      "args": []
-    }
-  ],
-  "accounts": [
-    {
-      "name": "MyAccount",
-      "type": {
-        "kind": "struct",
-        "fields": [
-          {
-            "name": "myAccount",
-            "type": "publicKey"
-          },
-          {
-            "name": "bump",
-            "type": "u8"
-          }
-        ]
-      }
-    }
-  ]
-}
\ No newline at end of file
diff --git a/tests/idl/package.json b/tests/idl/package.json
index 4e7dbaf826..283b0973fe 100644
--- a/tests/idl/package.json
+++ b/tests/idl/package.json
@@ -1,6 +1,6 @@
 {
   "name": "idl",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/idl/programs/client-interactions/src/lib.rs b/tests/idl/programs/client-interactions/src/lib.rs
deleted file mode 100644
index 08d2bee1f6..0000000000
--- a/tests/idl/programs/client-interactions/src/lib.rs
+++ /dev/null
@@ -1,131 +0,0 @@
-use anchor_lang::prelude::*;
-
-declare_id!("C1ient1nteractions1111111111111111111111111");
-
-#[program]
-pub mod client_interactions {
-    use super::*;
-
-    pub fn int(ctx: Context, i8: i8, i16: i16, i32: i32, i64: i64, i128: i128) -> Result<()> {
-        ctx.accounts.account.i8 = i8;
-        ctx.accounts.account.i16 = i16;
-        ctx.accounts.account.i32 = i32;
-        ctx.accounts.account.i64 = i64;
-        ctx.accounts.account.i128 = i128;
-        Ok(())
-    }
-
-    pub fn uint(
-        ctx: Context,
-        u8: u8,
-        u16: u16,
-        u32: u32,
-        u64: u64,
-        u128: u128,
-    ) -> Result<()> {
-        ctx.accounts.account.u8 = u8;
-        ctx.accounts.account.u16 = u16;
-        ctx.accounts.account.u32 = u32;
-        ctx.accounts.account.u64 = u64;
-        ctx.accounts.account.u128 = u128;
-        Ok(())
-    }
-
-    pub fn enm(ctx: Context, enum_arg: MyEnum) -> Result<()> {
-        ctx.accounts.account.enum_field = enum_arg;
-        Ok(())
-    }
-
-    pub fn type_alias(
-        ctx: Context,
-        type_alias_u8: TypeAliasU8,
-        type_alias_u8_array: TypeAliasU8Array,
-        type_alias_struct: TypeAliasStruct,
-    ) -> Result<()> {
-        ctx.accounts.account.type_alias_u8 = type_alias_u8;
-        ctx.accounts.account.type_alias_u8_array = type_alias_u8_array;
-        ctx.accounts.account.type_alias_struct = type_alias_struct;
-        Ok(())
-    }
-}
-
-#[derive(Accounts)]
-pub struct Int<'info> {
-    #[account(zero)]
-    pub account: Account<'info, IntAccount>,
-}
-
-#[account]
-pub struct IntAccount {
-    pub i8: i8,
-    pub i16: i16,
-    pub i32: i32,
-    pub i64: i64,
-    pub i128: i128,
-}
-
-#[derive(Accounts)]
-pub struct UnsignedInt<'info> {
-    #[account(zero)]
-    pub account: Account<'info, UnsignedIntAccount>,
-}
-
-#[account]
-pub struct UnsignedIntAccount {
-    pub u8: u8,
-    pub u16: u16,
-    pub u32: u32,
-    pub u64: u64,
-    pub u128: u128,
-}
-
-#[derive(Accounts)]
-pub struct Enum<'info> {
-    #[account(zero)]
-    pub account: Account<'info, EnumAccount>,
-}
-
-#[account]
-pub struct EnumAccount {
-    pub enum_field: MyEnum,
-}
-
-#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug, Eq, PartialEq)]
-pub enum MyEnum {
-    Unit,
-    Named { point_x: u64, point_y: u64 },
-    Unnamed(u8, u8, u16, u16),
-    UnnamedStruct(MyStruct),
-}
-
-#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug, Eq, PartialEq)]
-pub struct MyStruct {
-    pub u8: u8,
-    pub u16: u16,
-    pub u32: u32,
-    pub u64: u64,
-}
-
-#[derive(Accounts)]
-pub struct TypeAlias<'info> {
-    #[account(zero)]
-    pub account: Account<'info, TypeAliasAccount>,
-}
-
-#[account]
-pub struct TypeAliasAccount {
-    pub type_alias_u8: TypeAliasU8,
-    pub type_alias_u8_array: TypeAliasU8Array,
-    pub type_alias_struct: TypeAliasStruct,
-}
-
-pub type TypeAliasU8 = u8;
-pub type TypeAliasU8Array = [TypeAliasU8; 8];
-pub type TypeAliasStruct = MyStruct;
-
-/// Generic type aliases should not get included in the IDL
-pub type TypeAliasNotSupported<'a, T> = NotSupported<'a, T>;
-pub struct NotSupported<'a, T> {
-    _t: T,
-    _s: &'a str,
-}
diff --git a/tests/idl/programs/docs/Cargo.toml b/tests/idl/programs/docs/Cargo.toml
index cfff4e5bfc..77d017c54b 100644
--- a/tests/idl/programs/docs/Cargo.toml
+++ b/tests/idl/programs/docs/Cargo.toml
@@ -2,7 +2,6 @@
 name = "docs"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/idl/programs/docs/src/lib.rs b/tests/idl/programs/docs/src/lib.rs
index 7a203abaf6..cc1b624a87 100644
--- a/tests/idl/programs/docs/src/lib.rs
+++ b/tests/idl/programs/docs/src/lib.rs
@@ -4,6 +4,10 @@ use anchor_lang::prelude::*;
 
 declare_id!("Docs111111111111111111111111111111111111111");
 
+/// Documentation comment for constant
+#[constant]
+pub const MY_CONST: u8 = 42;
+
 /// This is a doc comment for the program
 #[program]
 pub mod docs {
diff --git a/tests/idl/programs/external/src/lib.rs b/tests/idl/programs/external/src/lib.rs
index 93cefe9414..7ce4cf49c5 100644
--- a/tests/idl/programs/external/src/lib.rs
+++ b/tests/idl/programs/external/src/lib.rs
@@ -6,15 +6,26 @@ declare_id!("Externa1111111111111111111111111111111111111");
 pub mod external {
     use super::*;
 
-    pub fn initialize(_ctx: Context, _baz: Baz) -> Result<()> {
+    pub fn initialize(_ctx: Context) -> Result<()> {
         Ok(())
     }
 }
 
 #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
-pub struct Baz {
+pub struct MyStruct {
     some_field: u8,
 }
 
+#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
+pub enum MyEnum {
+    Unit,
+    Named { name: String },
+    Tuple(String),
+}
+
+pub struct NonBorshStruct {
+    pub data: i32,
+}
+
 #[derive(Accounts)]
 pub struct Initialize {}
diff --git a/tests/idl/programs/generics/src/lib.rs b/tests/idl/programs/generics/src/lib.rs
index 40ca903bba..4e4b740b26 100644
--- a/tests/idl/programs/generics/src/lib.rs
+++ b/tests/idl/programs/generics/src/lib.rs
@@ -38,7 +38,7 @@ where
     pub gen1: T,
     pub gen2: U,
     pub gen3: GenericNested,
-    pub gen4: GenericNested,
+    pub gen4: GenericNested,
     pub gen5: GenericNested,
     pub gen6: GenericNested,
     pub gen7: GenericNested>,
diff --git a/tests/idl/programs/idl-build-features/src/lib.rs b/tests/idl/programs/idl-build-features/src/lib.rs
deleted file mode 100644
index 939df83eb8..0000000000
--- a/tests/idl/programs/idl-build-features/src/lib.rs
+++ /dev/null
@@ -1,47 +0,0 @@
-use anchor_lang::prelude::*;
-
-declare_id!("id1Bui1dFeatures111111111111111111111111111");
-
-#[program]
-pub mod idl_build_features {
-    use super::*;
-
-    pub fn full_path(
-        ctx: Context,
-        my_struct: MyStruct,
-        some_module_my_struct: some_module::MyStruct,
-    ) -> Result<()> {
-        ctx.accounts.account.my_struct = my_struct;
-        ctx.accounts.account.some_module_my_struct = some_module_my_struct;
-        Ok(())
-    }
-}
-
-#[derive(Accounts)]
-pub struct FullPath<'info> {
-    #[account(zero)]
-    pub account: Account<'info, FullPathAccount>,
-}
-
-#[account]
-pub struct FullPathAccount {
-    pub my_struct: MyStruct,
-    pub some_module_my_struct: some_module::MyStruct,
-}
-
-mod some_module {
-    use super::*;
-
-    #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
-    pub struct MyStruct {
-        pub data: u8,
-    }
-}
-
-#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
-pub struct MyStruct {
-    pub u8: u8,
-    pub u16: u16,
-    pub u32: u32,
-    pub u64: u64,
-}
diff --git a/tests/idl/programs/idl/src/lib.rs b/tests/idl/programs/idl/src/lib.rs
index d436c3ab69..580b17c29c 100644
--- a/tests/idl/programs/idl/src/lib.rs
+++ b/tests/idl/programs/idl/src/lib.rs
@@ -1,6 +1,5 @@
 use anchor_lang::prelude::*;
 use anchor_spl::{token, token_interface};
-use std::str::FromStr;
 
 declare_id!("id11111111111111111111111111111111111111111");
 
@@ -105,7 +104,7 @@ pub mod idl {
     }
 
     pub fn cause_error(_ctx: Context) -> Result<()> {
-        return Err(error!(ErrorCode::SomeError));
+        Err(error!(ErrorCode::SomeError))
     }
 }
 
@@ -137,10 +136,10 @@ pub struct BarStruct {
 
 impl Default for BarStruct {
     fn default() -> Self {
-        return BarStruct {
+        Self {
             some_field: true,
             other_field: 10,
-        };
+        }
     }
 }
 
@@ -156,7 +155,7 @@ pub struct FooStruct {
 
 impl Default for FooStruct {
     fn default() -> Self {
-        return FooStruct {
+        Self {
             field1: 123,
             field2: 999,
             nested: BarStruct::default(),
@@ -167,7 +166,7 @@ impl Default for FooStruct {
                 u8_field: 15,
                 nested: BarStruct::default(),
             },
-        };
+        }
     }
 }
 
@@ -205,8 +204,7 @@ pub struct State {
 
 impl Default for State {
     fn default() -> Self {
-        // some arbitrary default values
-        return State {
+        Self {
             bool_field: true,
             u8_field: 234,
             i8_field: -123,
@@ -222,7 +220,7 @@ impl Default for State {
             i128_field: i128::MIN / 2 - 10,
             bytes_field: vec![1, 2, 255, 254],
             string_field: String::from("hello"),
-            pubkey_field: Pubkey::from_str("EPZP2wrcRtMxrAPJCXVEQaYD9eH7fH7h12YqKDcd4aS7").unwrap(),
+            pubkey_field: pubkey!("EPZP2wrcRtMxrAPJCXVEQaYD9eH7fH7h12YqKDcd4aS7"),
             vec_field: vec![1, 2, 100, 1000, u64::MAX],
             vec_struct_field: vec![FooStruct::default()],
             option_field: None,
@@ -237,7 +235,7 @@ impl Default for State {
             },
             enum_field_3: FooEnum::Struct(BarStruct::default()),
             enum_field_4: FooEnum::NoFields,
-        };
+        }
     }
 }
 
@@ -248,10 +246,10 @@ pub struct State2 {
 }
 impl Default for State2 {
     fn default() -> Self {
-        return State2 {
+        Self {
             vec_of_option: vec![None, Some(10)],
             box_field: Box::new(true),
-        };
+        }
     }
 }
 
@@ -267,7 +265,7 @@ pub struct Initialize<'info> {
     /// State account
     #[account(
         init,
-        space = 8 + 1000, // TODO: use exact space required
+        space = 8 + 1000,
         payer = payer,
     )]
     state: Account<'info, State>,
@@ -289,7 +287,7 @@ pub struct Initialize<'info> {
 pub struct Initialize2<'info> {
     #[account(
         init,
-        space = 8 + 1000, // TODO: use exact space required
+        space = 8 + 1000,
         payer = payer,
     )]
     state: Account<'info, State2>,
@@ -315,7 +313,7 @@ mod some_other_module {
     use super::*;
 
     #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
-    pub struct Baz {
+    pub struct MyStruct {
         some_u8: u8,
     }
 }
@@ -323,8 +321,8 @@ mod some_other_module {
 #[event]
 pub struct SomeEvent {
     bool_field: bool,
-    external_baz: external::Baz,
-    other_module_baz: some_other_module::Baz,
+    external_my_struct: external::MyStruct,
+    other_module_my_struct: some_other_module::MyStruct,
 }
 
 #[zero_copy]
diff --git a/tests/idl/programs/new-idl/Cargo.toml b/tests/idl/programs/new-idl/Cargo.toml
new file mode 100644
index 0000000000..124fa0f6b5
--- /dev/null
+++ b/tests/idl/programs/new-idl/Cargo.toml
@@ -0,0 +1,20 @@
+[package]
+name = "new-idl"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "new_idl"
+
+[features]
+no-entrypoint = []
+no-idl = []
+cpi = ["no-entrypoint"]
+default = []
+idl-build = ["anchor-lang/idl-build"]
+
+[dependencies]
+anchor-lang = { path = "../../../../lang" }
+external = { path = "../external", features = ["no-entrypoint"] }
diff --git a/tests/idl/programs/new-idl/Xargo.toml b/tests/idl/programs/new-idl/Xargo.toml
new file mode 100644
index 0000000000..1744f098ae
--- /dev/null
+++ b/tests/idl/programs/new-idl/Xargo.toml
@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []
\ No newline at end of file
diff --git a/tests/idl/programs/new-idl/src/lib.rs b/tests/idl/programs/new-idl/src/lib.rs
new file mode 100644
index 0000000000..65d05198b1
--- /dev/null
+++ b/tests/idl/programs/new-idl/src/lib.rs
@@ -0,0 +1,448 @@
+use anchor_lang::{prelude::*, solana_program::clock::UnixTimestamp};
+
+declare_id!("Newid11111111111111111111111111111111111111");
+
+#[program]
+pub mod new_idl {
+    use super::*;
+
+    pub fn no_case_conversion(ctx: Context, field_name: u8) -> Result<()> {
+        ctx.accounts.case_conversion_account.field_name = field_name;
+        emit!(SimpleEvent { field_name });
+        Ok(())
+    }
+
+    pub fn empty(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn primitive_types(
+        ctx: Context,
+        bool: bool,
+        i8: i8,
+        i16: i16,
+        i32: i32,
+        i64: i64,
+        i128: i128,
+        u8: u8,
+        u16: u16,
+        u32: u32,
+        u64: u64,
+        u128: u128,
+        f32: f32,
+        f64: f64,
+        pubkey: Pubkey,
+    ) -> Result<()> {
+        ctx.accounts.account.bool = bool;
+
+        ctx.accounts.account.i8 = i8;
+        ctx.accounts.account.i16 = i16;
+        ctx.accounts.account.i32 = i32;
+        ctx.accounts.account.i64 = i64;
+        ctx.accounts.account.i128 = i128;
+
+        ctx.accounts.account.u8 = u8;
+        ctx.accounts.account.u16 = u16;
+        ctx.accounts.account.u32 = u32;
+        ctx.accounts.account.u64 = u64;
+        ctx.accounts.account.u128 = u128;
+
+        ctx.accounts.account.f32 = f32;
+        ctx.accounts.account.f64 = f64;
+
+        ctx.accounts.account.pubkey = pubkey;
+        Ok(())
+    }
+
+    pub fn unsized_types(ctx: Context, string: String, bytes: Vec) -> Result<()> {
+        ctx.accounts.account.string = string;
+        ctx.accounts.account.bytes = bytes;
+        Ok(())
+    }
+
+    pub fn strct(
+        ctx: Context,
+        unit: UnitStruct,
+        named: NamedStruct,
+        tuple: TupleStruct,
+    ) -> Result<()> {
+        ctx.accounts.account.unit = unit;
+        ctx.accounts.account.named = named;
+        ctx.accounts.account.tuple = tuple;
+        Ok(())
+    }
+
+    pub fn enm(ctx: Context, full_enum: FullEnum) -> Result<()> {
+        ctx.accounts.account.full_enum = full_enum;
+        Ok(())
+    }
+
+    pub fn type_alias(
+        ctx: Context,
+        alias_u8: AliasU8,
+        alias_u8_array: AliasU8Array,
+        alias_struct: AliasStruct,
+        alias_vec_string: AliasVec,
+        alias_option_vec_pubkey: AliasOptionVec,
+        alias_generic_const: AliasGenericConst<4>,
+        alias_multiple_generics_mixed: AliasMultipleGenericMixed,
+        alias_external: UnixTimestamp,
+    ) -> Result<()> {
+        ctx.accounts.account.alias_u8 = alias_u8;
+        ctx.accounts.account.alias_u8_array = alias_u8_array;
+        ctx.accounts.account.alias_struct = alias_struct;
+        ctx.accounts.account.alias_vec_string = alias_vec_string;
+        ctx.accounts.account.alias_option_vec_pubkey = alias_option_vec_pubkey;
+        ctx.accounts.account.alias_generic_const = alias_generic_const;
+        ctx.accounts.account.alias_multiple_generics_mixed = alias_multiple_generics_mixed;
+        ctx.accounts.account.alias_external = alias_external;
+        Ok(())
+    }
+
+    pub fn account_and_event_arg_and_field(
+        ctx: Context,
+        account: AccountAndEventFieldAccount,
+    ) -> Result<()> {
+        *ctx.accounts.account = account;
+        Ok(())
+    }
+
+    pub fn generic(ctx: Context, generic_arg: GenericStruct) -> Result<()> {
+        ctx.accounts.my_account.field = generic_arg;
+        Ok(())
+    }
+
+    pub fn generic_custom_struct(
+        ctx: Context,
+        generic_arg: GenericStruct,
+    ) -> Result<()> {
+        ctx.accounts.my_account.field = generic_arg;
+        Ok(())
+    }
+
+    pub fn full_path(
+        ctx: Context,
+        named_struct: NamedStruct,
+        some_module_named_struct: some_module::NamedStruct,
+    ) -> Result<()> {
+        ctx.accounts.account.named_struct = named_struct;
+        ctx.accounts.account.some_module_named_struct = some_module_named_struct;
+        Ok(())
+    }
+
+    pub fn external(ctx: Context, my_struct: external::MyStruct) -> Result<()> {
+        ctx.accounts.account.my_struct = my_struct;
+        Ok(())
+    }
+
+    pub fn external_non_anchor(
+        ctx: Context,
+        feature: wrapped::Feature,
+    ) -> Result<()> {
+        ctx.accounts.account.feature = feature;
+        Ok(())
+    }
+}
+
+#[account]
+#[derive(InitSpace)]
+pub struct SimpleAccount {
+    pub field_name: u8,
+}
+
+#[event]
+#[derive(Clone)]
+pub struct SimpleEvent {
+    pub field_name: u8,
+}
+
+#[derive(Accounts)]
+pub struct NoCaseConversion<'info> {
+    #[account(init, payer = payer, space = 8 + SimpleAccount::INIT_SPACE)]
+    pub case_conversion_account: Account<'info, SimpleAccount>,
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+}
+#[derive(Accounts)]
+pub struct Empty {}
+
+#[derive(Accounts)]
+pub struct PrimitiveTypes<'info> {
+    #[account(zero)]
+    pub account: Account<'info, PrimitiveAccount>,
+}
+
+#[account]
+pub struct PrimitiveAccount {
+    pub bool: bool,
+    pub i8: i8,
+    pub i16: i16,
+    pub i32: i32,
+    pub i64: i64,
+    pub i128: i128,
+    pub u8: u8,
+    pub u16: u16,
+    pub u32: u32,
+    pub u64: u64,
+    pub u128: u128,
+    pub f32: f32,
+    pub f64: f64,
+    pub pubkey: Pubkey,
+}
+
+#[derive(Accounts)]
+pub struct UnsizedTypes<'info> {
+    #[account(zero)]
+    pub account: Account<'info, UnsizedAccount>,
+}
+
+#[account]
+pub struct UnsizedAccount {
+    pub string: String,
+    pub bytes: Vec,
+}
+
+#[derive(Accounts)]
+pub struct Struct<'info> {
+    #[account(zero)]
+    pub account: Account<'info, StructAccount>,
+}
+
+#[account]
+pub struct StructAccount {
+    pub unit: UnitStruct,
+    pub named: NamedStruct,
+    pub tuple: TupleStruct,
+}
+
+#[derive(AnchorDeserialize, AnchorSerialize, Clone)]
+pub struct UnitStruct;
+
+#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug, Eq, PartialEq)]
+pub struct NamedStruct {
+    pub u8: u8,
+    pub u16: u16,
+    pub u32: u32,
+    pub u64: u64,
+}
+
+#[derive(AnchorDeserialize, AnchorSerialize, Clone)]
+pub struct TupleStruct(u64, String);
+
+#[derive(Accounts)]
+pub struct Enum<'info> {
+    #[account(zero)]
+    pub account: Account<'info, EnumAccount>,
+}
+
+#[account]
+pub struct EnumAccount {
+    pub full_enum: FullEnum,
+}
+
+#[derive(AnchorSerialize, AnchorDeserialize, Clone, Copy, Debug, Eq, PartialEq)]
+pub enum FullEnum {
+    Unit,
+    Named { point_x: u64, point_y: u64 },
+    Unnamed(u8, u8, u16, u16),
+    UnnamedStruct(NamedStruct),
+}
+
+#[derive(Accounts)]
+pub struct TypeAlias<'info> {
+    #[account(zero)]
+    pub account: Account<'info, AliasAccount>,
+}
+
+#[account]
+pub struct AliasAccount {
+    pub alias_u8: AliasU8,
+    pub alias_u8_array: AliasU8Array,
+    pub alias_struct: AliasStruct,
+    pub alias_vec_string: AliasVec,
+    pub alias_option_vec_pubkey: AliasOptionVec,
+    pub alias_generic_const: AliasGenericConst<4>,
+    pub alias_multiple_generics_mixed: AliasMultipleGenericMixed,
+    pub alias_external: UnixTimestamp,
+}
+
+pub type AliasU8 = u8;
+pub type AliasU8Array = [AliasU8; 8];
+pub type AliasStruct = NamedStruct;
+pub type AliasVec = Vec;
+pub type AliasOptionVec = Vec>;
+pub type AliasGenericConst = [u32; N];
+pub type AliasMultipleGenericMixed = Vec<[T; N]>;
+
+#[derive(Accounts)]
+pub struct AccountAndEventArgAndField<'info> {
+    #[account(zero)]
+    pub account: Account<'info, AccountAndEventFieldAccount>,
+}
+
+#[account]
+pub struct AccountAndEventFieldAccount {
+    pub simple_account: SimpleAccount,
+    pub simple_event: SimpleEvent,
+}
+
+#[derive(Accounts)]
+pub struct FullPath<'info> {
+    #[account(zero)]
+    pub account: Account<'info, FullPathAccount>,
+}
+
+#[account]
+pub struct FullPathAccount {
+    pub named_struct: NamedStruct,
+    pub some_module_named_struct: some_module::NamedStruct,
+}
+
+mod some_module {
+    use super::*;
+
+    #[derive(AnchorSerialize, AnchorDeserialize, Clone)]
+    pub struct NamedStruct {
+        pub data: u8,
+    }
+}
+
+#[derive(Accounts)]
+pub struct Generic<'info> {
+    #[account(mut)]
+    pub signer: Signer<'info>,
+    #[account(
+        init,
+        payer = signer,
+        space = 1024,
+        seeds = [b"generic", signer.key.as_ref()],
+        bump
+    )]
+    pub my_account: Account<'info, GenericAccount>,
+    pub system_program: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct GenericCustomStruct<'info> {
+    #[account(mut)]
+    pub signer: Signer<'info>,
+    #[account(
+        init,
+        payer = signer,
+        space = 1024,
+        seeds = [b"genericCustomStruct", signer.key.as_ref()],
+        bump
+    )]
+    pub my_account: Account<'info, GenericAccountCustomStruct>,
+    pub system_program: Program<'info, System>,
+}
+
+#[account]
+pub struct GenericAccount {
+    pub field: GenericStruct,
+}
+
+#[account]
+pub struct GenericAccountCustomStruct {
+    pub field: GenericStruct,
+}
+
+#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
+pub struct SomeStruct {
+    pub field: u16,
+}
+
+#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
+pub struct GenericStruct {
+    arr: [T; N],
+    sub_field: SubGenericStruct<8, T, Vec>>,
+}
+
+#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
+pub struct SubGenericStruct {
+    sub_arr: [T; N],
+    another: U,
+}
+
+#[derive(AnchorSerialize, AnchorDeserialize, Clone, Debug)]
+pub enum GenericEnum {
+    Unit,
+    Named { x: T },
+    Tuple(Vec),
+}
+
+#[derive(Accounts)]
+pub struct External<'info> {
+    #[account(zero)]
+    pub account: Account<'info, AccountWithExternalField>,
+}
+
+#[account]
+pub struct AccountWithExternalField {
+    pub my_struct: external::MyStruct,
+}
+
+#[derive(Accounts)]
+pub struct ExternalNonAnchor<'info> {
+    #[account(zero)]
+    pub account: Account<'info, AccountWithNonAnchorExternalField>,
+}
+
+#[account]
+pub struct AccountWithNonAnchorExternalField {
+    pub feature: wrapped::Feature,
+}
+
+/// An example of wrapping a non-Anchor external type in order to include it in the IDL
+mod wrapped {
+    use super::*;
+
+    #[cfg(feature = "idl-build")]
+    use anchor_lang::idl::types::*;
+
+    pub struct Feature(anchor_lang::solana_program::feature::Feature);
+
+    impl AnchorSerialize for Feature {
+        fn serialize(&self, writer: &mut W) -> std::io::Result<()> {
+            self.0.activated_at.serialize(writer)?;
+            Ok(())
+        }
+    }
+
+    impl AnchorDeserialize for Feature {
+        fn deserialize_reader(reader: &mut R) -> std::io::Result {
+            Ok(Self(anchor_lang::solana_program::feature::Feature {
+                activated_at: AnchorDeserialize::deserialize_reader(reader)?,
+            }))
+        }
+    }
+
+    impl Clone for Feature {
+        fn clone(&self) -> Self {
+            Self(anchor_lang::solana_program::feature::Feature {
+                activated_at: self.0.activated_at.clone(),
+            })
+        }
+    }
+
+    #[cfg(feature = "idl-build")]
+    impl IdlBuild for Feature {
+        fn create_type() -> Option {
+            Some(IdlTypeDef {
+                name: "Feature".into(),
+                ty: IdlTypeDefTy::Struct {
+                    fields: Some(IdlDefinedFields::Named(vec![IdlField {
+                        name: "activated_at".into(),
+                        ty: IdlType::Option(Box::new(IdlType::U64)),
+                        docs: Default::default(),
+                    }])),
+                },
+                docs: Default::default(),
+                generics: Default::default(),
+                serialization: Default::default(),
+                repr: Default::default(),
+            })
+        }
+    }
+}
diff --git a/tests/idl/programs/relations-derivation/Cargo.toml b/tests/idl/programs/relations-derivation/Cargo.toml
index b2fe97ecd2..8e6d6ec10d 100644
--- a/tests/idl/programs/relations-derivation/Cargo.toml
+++ b/tests/idl/programs/relations-derivation/Cargo.toml
@@ -2,7 +2,6 @@
 name = "relations-derivation"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
diff --git a/tests/idl/test.sh b/tests/idl/test.sh
index 7b0db254f0..3c23d5cc81 100755
--- a/tests/idl/test.sh
+++ b/tests/idl/test.sh
@@ -1,11 +1,22 @@
 #!/usr/bin/env bash
 set -e
 
+# Generate temp directory
+tmp_dir=$(mktemp -d)
+
+# Fix external type resolution not working in CI due to missing `anchor-lang`
+# crates.io entry in runner machine.
+pushd $tmp_dir
+cargo new external-ci
+pushd external-ci
+cargo add anchor-lang
+cargo b
+popd
+popd
+
 # Run anchor test
 anchor test --skip-lint
 
-tmp_dir=$(mktemp -d)
-
 # Generate IDLs
 ./generate.sh $tmp_dir
 
@@ -27,9 +38,8 @@ compare() {
     echo ""
 }
 
-compare "parse"
-compare "build"
-compare "generics_build"
-compare "relations_build"
+compare "new"
+compare "generics"
+compare "relations"
 
 exit $ret
diff --git a/tests/idl/tests/client-interactions.ts b/tests/idl/tests/client-interactions.ts
deleted file mode 100644
index 25473fbec7..0000000000
--- a/tests/idl/tests/client-interactions.ts
+++ /dev/null
@@ -1,149 +0,0 @@
-import * as anchor from "@coral-xyz/anchor";
-import { assert } from "chai";
-
-import { ClientInteractions } from "../target/types/client_interactions";
-
-describe("Client interactions", () => {
-  anchor.setProvider(anchor.AnchorProvider.env());
-  const program = anchor.workspace
-    .clientInteractions as anchor.Program;
-
-  it("Can use integers", async () => {
-    const kp = anchor.web3.Keypair.generate();
-
-    const i8 = -3;
-    const i16 = 1;
-    const i32 = -5555551;
-    const i64 = new anchor.BN("384535471");
-    const i128 = new anchor.BN(-8342491);
-
-    await program.methods
-      .int(i8, i16, i32, i64, i128)
-      .accounts({ account: kp.publicKey })
-      .signers([kp])
-      .preInstructions([await program.account.intAccount.createInstruction(kp)])
-      .rpc();
-
-    const account = await program.account.intAccount.fetch(kp.publicKey);
-    assert.strictEqual(account.i8, i8);
-    assert.strictEqual(account.i16, i16);
-    assert.strictEqual(account.i32, i32);
-    assert(account.i64.eq(i64));
-    assert(account.i128.eq(i128));
-  });
-
-  it("Can use unsigned integers", async () => {
-    const kp = anchor.web3.Keypair.generate();
-
-    const u8 = 123;
-    const u16 = 7888;
-    const u32 = 5555551;
-    const u64 = new anchor.BN("384535471");
-    const u128 = new anchor.BN(8888888);
-
-    await program.methods
-      .uint(u8, u16, u32, u64, u128)
-      .accounts({ account: kp.publicKey })
-      .signers([kp])
-      .preInstructions([
-        await program.account.unsignedIntAccount.createInstruction(kp),
-      ])
-      .rpc();
-
-    const account = await program.account.unsignedIntAccount.fetch(
-      kp.publicKey
-    );
-    assert.strictEqual(account.u8, u8);
-    assert.strictEqual(account.u16, u16);
-    assert.strictEqual(account.u32, u32);
-    assert(account.u64.eq(u64));
-    assert(account.u128.eq(u128));
-  });
-
-  it("Can use enum", async () => {
-    const testAccountEnum = async (
-      ...args: Parameters
-    ) => {
-      const kp = anchor.web3.Keypair.generate();
-      await program.methods
-        .enm(...(args as any))
-        .accounts({ account: kp.publicKey })
-        .signers([kp])
-        .preInstructions([
-          await program.account.enumAccount.createInstruction(kp),
-        ])
-        .rpc();
-      return await program.account.enumAccount.fetch(kp.publicKey);
-    };
-
-    // Unit
-    const unit = await testAccountEnum({ unit: {} });
-    assert.deepEqual(unit.enumField.unit, {});
-
-    // Named
-    const pointX = new anchor.BN(1);
-    const pointY = new anchor.BN(2);
-    const named = await testAccountEnum({ named: { pointX, pointY } });
-    assert(named.enumField.named.pointX.eq(pointX));
-    assert(named.enumField.named.pointY.eq(pointY));
-
-    // Unnamed
-    const tupleArg = [1, 2, 3, 4] as const;
-    const unnamed = await testAccountEnum({ unnamed: tupleArg });
-    assert.strictEqual(unnamed.enumField.unnamed[0], tupleArg[0]);
-    assert.strictEqual(unnamed.enumField.unnamed[1], tupleArg[1]);
-    assert.strictEqual(unnamed.enumField.unnamed[2], tupleArg[2]);
-    assert.strictEqual(unnamed.enumField.unnamed[3], tupleArg[3]);
-
-    // Unnamed struct
-    const tupleStructArg = [
-      { u8: 1, u16: 11, u32: 111, u64: new anchor.BN(1111) },
-    ] as const;
-    const unnamedStruct = await testAccountEnum({
-      unnamedStruct: tupleStructArg,
-    });
-    assert.strictEqual(
-      unnamedStruct.enumField.unnamedStruct[0].u8,
-      tupleStructArg[0].u8
-    );
-    assert.strictEqual(
-      unnamedStruct.enumField.unnamedStruct[0].u16,
-      tupleStructArg[0].u16
-    );
-    assert.strictEqual(
-      unnamedStruct.enumField.unnamedStruct[0].u32,
-      tupleStructArg[0].u32
-    );
-    assert(
-      unnamedStruct.enumField.unnamedStruct[0].u64.eq(tupleStructArg[0].u64)
-    );
-  });
-
-  it("Can use type aliases", async () => {
-    const kp = anchor.web3.Keypair.generate();
-
-    const typeAliasU8 = 42;
-    const typeAliasU8Array = [1, 2, 3, 4, 5, 6, 7, 8];
-    const typeAliasStruct = {
-      u8: 1,
-      u16: 2,
-      u32: 3,
-      u64: new anchor.BN(4),
-    };
-
-    await program.methods
-      .typeAlias(typeAliasU8, typeAliasU8Array, typeAliasStruct)
-      .accounts({ account: kp.publicKey })
-      .signers([kp])
-      .preInstructions([await program.account.intAccount.createInstruction(kp)])
-      .rpc();
-
-    const account = await program.account.typeAliasAccount.fetch(kp.publicKey);
-    assert.strictEqual(account.typeAliasU8, typeAliasU8);
-    assert.deepEqual(account.typeAliasU8Array, typeAliasU8Array);
-    assert.strictEqual(account.typeAliasStruct.u8, typeAliasStruct.u8);
-    assert.strictEqual(account.typeAliasStruct.u16, typeAliasStruct.u16);
-    assert.strictEqual(account.typeAliasStruct.u32, typeAliasStruct.u32);
-    assert(account.typeAliasStruct.u64.eq(typeAliasStruct.u64));
-  });
-});
diff --git a/tests/idl/tests/docs.ts b/tests/idl/tests/docs.ts
index 401888d7b4..ee7a54a8ac 100644
--- a/tests/idl/tests/docs.ts
+++ b/tests/idl/tests/docs.ts
@@ -10,7 +10,7 @@ describe("Docs", () => {
 
   const instruction = program.idl.instructions.find(
     (i) => i.name === "testIdlDocParse"
-  );
+  )!;
 
   it("includes instruction doc comment", () => {
     assert.deepEqual(instruction.docs, [
@@ -19,28 +19,32 @@ describe("Docs", () => {
   });
 
   it("includes account doc comment", () => {
-    const act = instruction.accounts.find((i) => i.name === "act");
+    const act = instruction.accounts.find((i) => i.name === "act")!;
     assert.deepEqual(act.docs, [
       "This account doc comment should appear in the IDL",
       "This is a multi-line comment",
     ]);
   });
 
-  const dataWithDoc = program.idl.accounts.find(
-    // @ts-expect-error
-    (acc) => acc.name === "DataWithDoc"
-  );
+  const dataWithDoc = program.idl.types.find(
+    (ty) => ty.name === "dataWithDoc"
+  )!;
 
-  it("includes accounts doc comment", () => {
+  it("includes type doc comment", () => {
     assert.deepEqual(dataWithDoc.docs, [
       "Custom account doc comment should appear in the IDL",
     ]);
   });
 
   it("includes account attribute doc comment", () => {
-    const dataField = dataWithDoc.type.fields.find((i) => i.name === "data");
+    const dataField = dataWithDoc.type.fields.find((i) => i.name === "data")!;
     assert.deepEqual(dataField.docs, [
       "Account attribute doc comment should appear in the IDL",
     ]);
   });
+
+  it("includes constant doc comment", () => {
+    const myConst = program.idl.constants.find((c) => c.name === "myConst")!;
+    assert.deepEqual(myConst.docs, ["Documentation comment for constant"]);
+  });
 });
diff --git a/tests/idl/tests/idl-build-features.ts b/tests/idl/tests/idl-build-features.ts
deleted file mode 100644
index 4abdb13d34..0000000000
--- a/tests/idl/tests/idl-build-features.ts
+++ /dev/null
@@ -1,35 +0,0 @@
-import * as anchor from "@coral-xyz/anchor";
-import { assert } from "chai";
-
-import { IdlBuildFeatures } from "../target/types/idl_build_features";
-
-describe("idl-build features", () => {
-  anchor.setProvider(anchor.AnchorProvider.env());
-  const program = anchor.workspace
-    .idlBuildFeatures as anchor.Program;
-
-  it("Can use full module path types", async () => {
-    const kp = anchor.web3.Keypair.generate();
-
-    const outerMyStructArg = { u8: 1, u16: 2, u32: 3, u64: new anchor.BN(4) };
-    const someModuleMyStructArg = { data: 5 };
-
-    await program.methods
-      .fullPath(outerMyStructArg, someModuleMyStructArg)
-      .accounts({ account: kp.publicKey })
-      .preInstructions([
-        await program.account.fullPathAccount.createInstruction(kp),
-      ])
-      .signers([kp])
-      .rpc();
-
-    const fullPathAccount = await program.account.fullPathAccount.fetch(
-      kp.publicKey
-    );
-    assert.strictEqual(fullPathAccount.myStruct.u8, outerMyStructArg.u8);
-    assert.strictEqual(fullPathAccount.myStruct.u16, outerMyStructArg.u16);
-    assert.strictEqual(fullPathAccount.myStruct.u32, outerMyStructArg.u32);
-    assert(fullPathAccount.myStruct.u64.eq(outerMyStructArg.u64));
-    assert.deepEqual(fullPathAccount.someModuleMyStruct, someModuleMyStructArg);
-  });
-});
diff --git a/tests/idl/tests/idl.ts b/tests/idl/tests/idl.ts
index 4aa7e4ddc2..a0bae6127f 100644
--- a/tests/idl/tests/idl.ts
+++ b/tests/idl/tests/idl.ts
@@ -12,19 +12,20 @@ describe("IDL", () => {
     const checkDefined = (
       cb: (constant: typeof program["idl"]["constants"][number]) => boolean
     ) => {
-      program.idl.constants.find((c) => cb(c));
+      const constant = program.idl.constants.find(cb);
+      if (!constant) throw new Error("Constant not found");
     };
 
-    checkDefined((c) => c.name === "U8" && c.type === "u8" && c.value === "6");
+    checkDefined((c) => c.name === "u8" && c.type === "u8" && c.value === "6");
     checkDefined(
-      (c) => c.name === "I128" && c.type === "i128" && c.value === "1000000"
+      (c) => c.name === "i128" && c.type === "i128" && c.value === "1000000"
     );
     checkDefined(
-      (c) => c.name === "BYTE_STR" && c.type === "u8" && c.value === "116"
+      (c) => c.name === "byteStr" && c.type === "u8" && c.value === "116"
     );
     checkDefined(
       (c) =>
-        c.name === "BYTES_STR" &&
+        c.name === "bytesStr" &&
         c.type === "bytes" &&
         c.value === "[116, 101, 115, 116]"
     );
@@ -32,6 +33,6 @@ describe("IDL", () => {
 
   it("Does not include constants that does not use `#[constant]` macro ", () => {
     // @ts-expect-error
-    assert.isUndefined(program.idl.constants.find((c) => c.name === "NO_IDL"));
+    assert.isUndefined(program.idl.constants.find((c) => c.name === "noIdl"));
   });
 });
diff --git a/tests/idl/tests/new-idl.ts b/tests/idl/tests/new-idl.ts
new file mode 100644
index 0000000000..2b05515756
--- /dev/null
+++ b/tests/idl/tests/new-idl.ts
@@ -0,0 +1,489 @@
+import * as anchor from "@coral-xyz/anchor";
+import { assert } from "chai";
+
+import type { NewIdl } from "../target/types/new_idl";
+
+describe("New IDL", () => {
+  anchor.setProvider(anchor.AnchorProvider.env());
+  const program = anchor.workspace.newIdl as anchor.Program;
+
+  describe("Case conversion", () => {
+    const caseConversionAccountKp = anchor.web3.Keypair.generate();
+    const FIELD_NAME = 5;
+
+    it("Works when instructions have no case conversion in IDL", async () => {
+      const ixName = "no_case_conversion";
+      const ix = program.rawIdl.instructions.find((ix) => ix.name === ixName);
+      if (!ix) throw new Error(`Instruction \`${ixName}\` not found`);
+
+      await program.methods
+        .noCaseConversion(FIELD_NAME)
+        .accounts({ caseConversionAccount: caseConversionAccountKp.publicKey })
+        .signers([caseConversionAccountKp])
+        .rpc();
+    });
+
+    it("Works when accounts have no case conversion in IDL", async () => {
+      const accName = "SimpleAccount";
+      const acc = program.rawIdl.accounts!.find((acc) => acc.name === accName);
+      if (!acc) throw new Error(`Account \`${accName}\` not found`);
+
+      const caseConversionAccount = await program.account.simpleAccount.fetch(
+        caseConversionAccountKp.publicKey
+      );
+      assert.strictEqual(caseConversionAccount.fieldName, FIELD_NAME);
+    });
+
+    it("Works when events have no case conversion in IDL", async () => {
+      const eventName = "SimpleEvent";
+      const event = program.rawIdl.events!.find((ev) => ev.name === eventName);
+      if (!event) throw new Error(`Event \`${eventName}\` not found`);
+
+      await new Promise(async (res) => {
+        const id = program.addEventListener("simpleEvent", (ev) => {
+          program.removeEventListener(id);
+          assert.strictEqual(ev.fieldName, FIELD_NAME);
+          res();
+        });
+
+        const caseConversionAccountKp = anchor.web3.Keypair.generate();
+        await program.methods
+          .noCaseConversion(FIELD_NAME)
+          .accounts({
+            caseConversionAccount: caseConversionAccountKp.publicKey,
+          })
+          .signers([caseConversionAccountKp])
+          .rpc();
+      });
+    });
+  });
+
+  describe("Client interaction", () => {
+    it("Can send empty ix(no arg, no account)", async () => {
+      await program.methods.empty().rpc();
+    });
+
+    it("Can use primitive types", async () => {
+      const kp = anchor.web3.Keypair.generate();
+
+      const bool = true;
+
+      const i8 = -3;
+      const i16 = 1;
+      const i32 = -5555551;
+      const i64 = new anchor.BN("384535471");
+      const i128 = new anchor.BN(-8342491);
+
+      const u8 = 123;
+      const u16 = 7888;
+      const u32 = 5555551;
+      const u64 = new anchor.BN("384535471");
+      const u128 = new anchor.BN(8888888);
+
+      const f32 = 1.0;
+      const f64 = 0.618;
+
+      const pubkey = anchor.web3.PublicKey.default;
+
+      await program.methods
+        .primitiveTypes(
+          bool,
+          i8,
+          i16,
+          i32,
+          i64,
+          i128,
+          u8,
+          u16,
+          u32,
+          u64,
+          u128,
+          f32,
+          f64,
+          pubkey
+        )
+        .accounts({ account: kp.publicKey })
+        .signers([kp])
+        .preInstructions([
+          await program.account.primitiveAccount.createInstruction(kp),
+        ])
+        .rpc();
+
+      const account = await program.account.primitiveAccount.fetch(
+        kp.publicKey
+      );
+      assert.strictEqual(account.bool, bool);
+
+      assert.strictEqual(account.i8, i8);
+      assert.strictEqual(account.i16, i16);
+      assert.strictEqual(account.i32, i32);
+      assert(account.i64.eq(i64));
+      assert(account.i128.eq(i128));
+
+      assert.strictEqual(account.u8, u8);
+      assert.strictEqual(account.u16, u16);
+      assert.strictEqual(account.u32, u32);
+      assert(account.u64.eq(u64));
+      assert(account.u128.eq(u128));
+
+      assert.strictEqual(account.f32, f32);
+      assert.strictEqual(account.f64, f64);
+
+      assert(account.pubkey.equals(pubkey));
+    });
+
+    it("Can use unsized types", async () => {
+      const kp = anchor.web3.Keypair.generate();
+
+      const string = "anchor";
+      const bytes = Buffer.from([1, 2, 3, 4]);
+      await program.methods
+        .unsizedTypes(string, bytes)
+        .accounts({ account: kp.publicKey })
+        .signers([kp])
+        .preInstructions([
+          await program.account.primitiveAccount.createInstruction(kp),
+        ])
+        .rpc();
+
+      const account = await program.account.unsizedAccount.fetch(kp.publicKey);
+      assert.strictEqual(account.string, string);
+      assert(account.bytes.equals(bytes));
+    });
+
+    it("Can use struct", async () => {
+      const unitStructArg = {} as const;
+      const namedStructArg = {
+        u8: 1,
+        u16: 11,
+        u32: 111,
+        u64: new anchor.BN(1111),
+      } as const;
+      const tupleStructArg = [new anchor.BN(23), "tuple"] as const;
+
+      const kp = anchor.web3.Keypair.generate();
+      await program.methods
+        .strct(unitStructArg, namedStructArg, tupleStructArg)
+        .accounts({ account: kp.publicKey })
+        .signers([kp])
+        .preInstructions([
+          await program.account.structAccount.createInstruction(kp, 1024),
+        ])
+        .rpc();
+
+      const struct = await program.account.structAccount.fetch(kp.publicKey);
+
+      // Unit
+      assert.deepEqual(struct.unit, unitStructArg);
+
+      // Named
+      assert.strictEqual(struct.named.u8, namedStructArg.u8);
+      assert.strictEqual(struct.named.u16, namedStructArg.u16);
+      assert.strictEqual(struct.named.u32, namedStructArg.u32);
+      assert(struct.named.u64.eq(namedStructArg.u64));
+
+      // Tuple
+      assert(struct.tuple[0].eq(tupleStructArg[0]));
+      assert.strictEqual(struct.tuple[1], tupleStructArg[1]);
+    });
+
+    it("Can use enum", async () => {
+      const testAccountEnum = async (
+        ...args: Parameters
+      ) => {
+        const kp = anchor.web3.Keypair.generate();
+        await program.methods
+          .enm(...(args as any))
+          .accounts({ account: kp.publicKey })
+          .signers([kp])
+          .preInstructions([
+            await program.account.enumAccount.createInstruction(kp),
+          ])
+          .rpc();
+        return await program.account.enumAccount.fetch(kp.publicKey);
+      };
+
+      // Unit
+      const unit = await testAccountEnum({ unit: {} });
+      assert.deepEqual(unit.fullEnum.unit, {});
+
+      // Named
+      const pointX = new anchor.BN(1);
+      const pointY = new anchor.BN(2);
+      const named = await testAccountEnum({ named: { pointX, pointY } });
+      if (!named.fullEnum.named) throw new Error("Named not crated");
+      assert(named.fullEnum.named.pointX.eq(pointX));
+      assert(named.fullEnum.named.pointY.eq(pointY));
+
+      // Unnamed
+      const tupleArg = [1, 2, 3, 4] as const;
+      const unnamed = await testAccountEnum({ unnamed: tupleArg });
+      if (!unnamed.fullEnum.unnamed) throw new Error("Unnamed not crated");
+      assert(
+        Object.entries(unnamed.fullEnum.unnamed).every(
+          ([key, value]) => value === tupleArg[key as keyof typeof tupleArg]
+        )
+      );
+
+      // Unnamed struct
+      const tupleStructArg = [
+        { u8: 1, u16: 11, u32: 111, u64: new anchor.BN(1111) },
+      ] as const;
+      const unnamedStruct = await testAccountEnum({
+        unnamedStruct: tupleStructArg,
+      });
+      if (!unnamedStruct.fullEnum.unnamedStruct) {
+        throw new Error("Unnamed struct not crated");
+      }
+      assert.strictEqual(
+        unnamedStruct.fullEnum.unnamedStruct[0].u8,
+        tupleStructArg[0].u8
+      );
+      assert.strictEqual(
+        unnamedStruct.fullEnum.unnamedStruct[0].u16,
+        tupleStructArg[0].u16
+      );
+      assert.strictEqual(
+        unnamedStruct.fullEnum.unnamedStruct[0].u32,
+        tupleStructArg[0].u32
+      );
+      assert(
+        unnamedStruct.fullEnum.unnamedStruct[0].u64.eq(tupleStructArg[0].u64)
+      );
+    });
+
+    it("Can use type aliases", async () => {
+      const kp = anchor.web3.Keypair.generate();
+
+      const aliasU8 = 42;
+      const aliasU8Array = [1, 2, 3, 4, 5, 6, 7, 8];
+      const aliasStruct = {
+        u8: 1,
+        u16: 2,
+        u32: 3,
+        u64: new anchor.BN(4),
+      };
+      const aliasVecString = ["first", "second"];
+      const aliasOptionVecPubkey = [anchor.web3.Keypair.generate().publicKey];
+      const aliasGenericConst = [1, 23045, 32, 4];
+      const aliasMultipleGenericsMixed = [
+        [true, false],
+        [false, true],
+      ];
+      const aliasExternal = new anchor.BN(1708705033);
+
+      await program.methods
+        .typeAlias(
+          aliasU8,
+          aliasU8Array,
+          aliasStruct,
+          aliasVecString,
+          aliasOptionVecPubkey,
+          aliasGenericConst,
+          aliasMultipleGenericsMixed,
+          aliasExternal
+        )
+        .accounts({ account: kp.publicKey })
+        .signers([kp])
+        .preInstructions([
+          await program.account.aliasAccount.createInstruction(kp, 1024),
+        ])
+        .rpc();
+
+      const account = await program.account.aliasAccount.fetch(kp.publicKey);
+
+      assert.strictEqual(account.aliasU8, aliasU8);
+      assert.deepEqual(account.aliasU8Array, aliasU8Array);
+      assert.strictEqual(account.aliasStruct.u8, aliasStruct.u8);
+      assert.strictEqual(account.aliasStruct.u16, aliasStruct.u16);
+      assert.strictEqual(account.aliasStruct.u32, aliasStruct.u32);
+      assert(account.aliasStruct.u64.eq(aliasStruct.u64));
+      assert.deepEqual(account.aliasVecString, aliasVecString);
+      assert.deepEqual(account.aliasOptionVecPubkey, aliasOptionVecPubkey);
+      assert.deepEqual(account.aliasGenericConst, aliasGenericConst);
+      assert.deepEqual(
+        account.aliasMultipleGenericsMixed,
+        aliasMultipleGenericsMixed
+      );
+      assert(account.aliasExternal.eq(aliasExternal));
+    });
+
+    it("Can use accounts and events as arguments and fields", async () => {
+      const kp = anchor.web3.Keypair.generate();
+
+      const accountArg = {
+        simpleAccount: { fieldName: 2 },
+        simpleEvent: { fieldName: 4 },
+      };
+      await program.methods
+        .accountAndEventArgAndField(accountArg)
+        .accounts({ account: kp.publicKey })
+        .signers([kp])
+        .preInstructions([
+          await program.account.accountAndEventFieldAccount.createInstruction(
+            kp
+          ),
+        ])
+        .rpc();
+
+      const account = await program.account.accountAndEventFieldAccount.fetch(
+        kp.publicKey
+      );
+      assert.deepEqual(account, accountArg);
+    });
+
+    it("Can use generics", async () => {
+      const arg = {
+        arr: [6, 123, 2, 3],
+        subField: {
+          subArr: new Array(8).fill(null).map((_, i) => i + 33),
+          another: [30211, 65050, 21, 441],
+        },
+      };
+      const { pubkeys } = await program.methods.generic(arg).rpcAndKeys();
+      const myAccount = await program.account.genericAccount.fetch(
+        pubkeys.myAccount
+      );
+      assert.deepEqual(myAccount.field, arg);
+    });
+
+    it("Can use generics populated with custom struct", async () => {
+      const arg = {
+        arr: [{ field: 1 }, { field: 2 }, { field: 3 }, { field: 4 }],
+        subField: {
+          subArr: new Array(8).fill(null).map((_, i) => ({ field: i })),
+          another: [
+            { field: 42 },
+            { field: 420 },
+            { field: 4_200 },
+            { field: 42_000 },
+          ],
+        },
+      };
+      const { pubkeys } = await program.methods
+        .genericCustomStruct(arg)
+        .rpcAndKeys();
+      const myAccount = await program.account.genericAccountCustomStruct.fetch(
+        pubkeys.myAccount
+      );
+      assert.deepEqual(myAccount.field, arg);
+    });
+
+    it("Can use full module path types", async () => {
+      const kp = anchor.web3.Keypair.generate();
+
+      const namedStructArg = { u8: 1, u16: 2, u32: 3, u64: new anchor.BN(4) };
+      const someModuleNamedStructArg = { data: 5 };
+
+      await program.methods
+        .fullPath(namedStructArg, someModuleNamedStructArg)
+        .accounts({ account: kp.publicKey })
+        .preInstructions([
+          await program.account.fullPathAccount.createInstruction(kp),
+        ])
+        .signers([kp])
+        .rpc();
+
+      const fullPathAccount = await program.account.fullPathAccount.fetch(
+        kp.publicKey
+      );
+      assert.strictEqual(fullPathAccount.namedStruct.u8, namedStructArg.u8);
+      assert.strictEqual(fullPathAccount.namedStruct.u16, namedStructArg.u16);
+      assert.strictEqual(fullPathAccount.namedStruct.u32, namedStructArg.u32);
+      assert(fullPathAccount.namedStruct.u64.eq(namedStructArg.u64));
+      assert.deepEqual(
+        fullPathAccount.someModuleNamedStruct,
+        someModuleNamedStructArg
+      );
+    });
+
+    it("Can use external types", async () => {
+      const externalArg = { someField: 5 };
+
+      const kp = anchor.web3.Keypair.generate();
+      await program.methods
+        .external(externalArg)
+        .accounts({ account: kp.publicKey })
+        .signers([kp])
+        .preInstructions([
+          await program.account.accountWithExternalField.createInstruction(kp),
+        ])
+        .rpc();
+
+      const account = await program.account.accountWithExternalField.fetch(
+        kp.publicKey
+      );
+
+      assert.deepEqual(account.myStruct, externalArg);
+    });
+
+    it("Can use non-Anchor external types", async () => {
+      const feature = { activatedAt: new anchor.BN(42) };
+
+      const kp = anchor.web3.Keypair.generate();
+      await program.methods
+        .externalNonAnchor(feature)
+        .accounts({ account: kp.publicKey })
+        .signers([kp])
+        .preInstructions([
+          await program.account.accountWithNonAnchorExternalField.createInstruction(
+            kp
+          ),
+        ])
+        .rpc();
+
+      const account =
+        await program.account.accountWithNonAnchorExternalField.fetch(
+          kp.publicKey
+        );
+
+      assert(account.feature.activatedAt?.eq(feature.activatedAt));
+    });
+  });
+
+  describe("Format", () => {
+    const ixCoder = new anchor.BorshInstructionCoder(program.idl);
+
+    const formatEnum = async (argName: string, data: any, expected: string) => {
+      const typeName = Object.keys(data)[0];
+      const arg = data[typeName];
+      const ix = await program.methods
+        .enm(arg)
+        .accounts({ account: anchor.web3.PublicKey.default })
+        .instruction();
+
+      const formattedIx = ixCoder.format({ name: "enm", data }, ix.keys);
+      if (!formattedIx) throw new Error("Failed to format");
+
+      assert.deepEqual(formattedIx.args[0], {
+        name: argName,
+        type: typeName,
+        data: expected,
+      });
+    };
+
+    it("Can format unit enum", async () => {
+      await formatEnum("fullEnum", { fullEnum: { unit: {} } }, "unit");
+    });
+
+    it("Can format named enum", async () => {
+      await formatEnum(
+        "fullEnum",
+        {
+          fullEnum: {
+            named: { pointX: new anchor.BN(1), pointY: new anchor.BN(2) },
+          },
+        },
+        "named { pointX: 1, pointY: 2 }"
+      );
+    });
+
+    it("Can format tuple enum", async () => {
+      await formatEnum(
+        "fullEnum",
+        { fullEnum: { unnamed: [2, 10, 200, 49] } },
+        "unnamed { 0: 2, 1: 10, 2: 200, 3: 49 }"
+      );
+    });
+  });
+});
diff --git a/tests/idl/tests/workspace.ts b/tests/idl/tests/workspace.ts
index c240bdd9b6..458a2c6673 100644
--- a/tests/idl/tests/workspace.ts
+++ b/tests/idl/tests/workspace.ts
@@ -25,7 +25,7 @@ describe("Workspace", () => {
 
     const compareProgramNames = (...programs: anchor.Program[]) => {
       return programs.every(
-        (program) => program.idl.name === "relations_derivation"
+        (program) => program.rawIdl.metadata.name === "relations_derivation"
       );
     };
 
diff --git a/tests/idl/tsconfig.json b/tests/idl/tsconfig.json
index 774260253f..feba6ca17f 100644
--- a/tests/idl/tsconfig.json
+++ b/tests/idl/tsconfig.json
@@ -4,6 +4,7 @@
     "lib": ["es2015"],
     "module": "commonjs",
     "target": "es6",
-    "esModuleInterop": true
+    "esModuleInterop": true,
+    "strict": true
   }
 }
diff --git a/tests/ido-pool/package.json b/tests/ido-pool/package.json
index 2f31a67412..9731ddb1b8 100644
--- a/tests/ido-pool/package.json
+++ b/tests/ido-pool/package.json
@@ -1,6 +1,6 @@
 {
   "name": "ido-pool",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/ido-pool/programs/ido-pool/Cargo.toml b/tests/ido-pool/programs/ido-pool/Cargo.toml
index d7558bf745..db2b4e9078 100644
--- a/tests/ido-pool/programs/ido-pool/Cargo.toml
+++ b/tests/ido-pool/programs/ido-pool/Cargo.toml
@@ -2,7 +2,6 @@
 name = "ido-pool"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/lockup/docs/staking.md b/tests/lockup/docs/staking.md
index 627c372679..c64f54d196 100644
--- a/tests/lockup/docs/staking.md
+++ b/tests/lockup/docs/staking.md
@@ -31,7 +31,7 @@ to understand, contribute to, or modify the code.
 Accounts are the pieces of state owned by a Solana program. For reference while reading, here are all
 accounts used by the **Registry** program.
 
-* `Registrar` - Analagous to an SPL token `Mint`, the `Registrar` defines a staking instance. It has its own pool, and it's own set of rewards distributed amongst its own set of stakers.
+* `Registrar` - Analogous to an SPL token `Mint`, the `Registrar` defines a staking instance. It has its own pool, and it's own set of rewards distributed amongst its own set of stakers.
 * `Member` - Analogous to an SPL token `Account`, `Member` accounts represent a **beneficiary**'s (i.e. a wallet's) stake state. This account has several vaults, all of which represent the funds belonging to an individual user.
 * `PendingWithdrawal` - A transfer out of the staking pool (poorly named since it's not a withdrawal out of the program. But a withdrawal out of the staking pool and into a `Member`'s freely available balances).
 * `RewardVendor` - A reward that has been dropped onto stakers and is distributed pro rata to staked `Member` beneficiaries.
@@ -118,7 +118,7 @@ recreating a BFT system off chain.
 
 Another solution considerered was to use a uniswap-style AMM pool (without the swapping).
 This has a lot of advantages. First it's easy to reason about and implement in a single transaction.
-To drop rewards gloablly onto the pool, one can deposit funds directly into the pool, in which case
+To drop rewards globally onto the pool, one can deposit funds directly into the pool, in which case
 the reward is automatically received by owners of the staking pool token upon redemption, a process
 known as "gulping"--since dropping rewards increases the total value of the pool
 while their proportion of the pool remained constant.
diff --git a/tests/lockup/package.json b/tests/lockup/package.json
index aecaba5ed9..ace9f2986f 100644
--- a/tests/lockup/package.json
+++ b/tests/lockup/package.json
@@ -1,6 +1,6 @@
 {
   "name": "lockup",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/lockup/programs/lockup/Cargo.toml b/tests/lockup/programs/lockup/Cargo.toml
index 976757f2b8..e38b0d84ea 100644
--- a/tests/lockup/programs/lockup/Cargo.toml
+++ b/tests/lockup/programs/lockup/Cargo.toml
@@ -2,7 +2,6 @@
 name = "lockup"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
diff --git a/tests/lockup/programs/registry/Cargo.toml b/tests/lockup/programs/registry/Cargo.toml
index d3bc74fa49..01671bd259 100644
--- a/tests/lockup/programs/registry/Cargo.toml
+++ b/tests/lockup/programs/registry/Cargo.toml
@@ -2,7 +2,6 @@
 name = "registry"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
diff --git a/tests/lockup/tests/lockup.js b/tests/lockup/tests/lockup.js
index ab3c717803..1a3ffd1a0e 100644
--- a/tests/lockup/tests/lockup.js
+++ b/tests/lockup/tests/lockup.js
@@ -6,7 +6,7 @@ const { assert } = require("chai");
 const nativeAssert = require("assert");
 
 describe("Lockup and Registry", () => {
-  // Read the provider from the configured environmnet.
+  // Read the provider from the configured environments.
   const provider = anchor.AnchorProvider.env();
   // hack so we don't have to update serum-common library
   // to the new AnchorProvider class and Provider interface
@@ -934,7 +934,7 @@ describe("Lockup and Registry", () => {
     assert.isTrue(tokenAccount.amount.eq(withdrawAmount));
   });
 
-  it("Should succesfully unlock a locked reward after unstaking", async () => {
+  it("Should successfully unlock a locked reward after unstaking", async () => {
     const token = await serumCmn.createTokenAccount(
       provider,
       mint,
diff --git a/tests/misc/package.json b/tests/misc/package.json
index 0c710e8b5b..65396b55fa 100644
--- a/tests/misc/package.json
+++ b/tests/misc/package.json
@@ -1,6 +1,6 @@
 {
   "name": "misc",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/misc/programs/init-if-needed/Cargo.toml b/tests/misc/programs/init-if-needed/Cargo.toml
index 8843138b0b..0a8f5b70fa 100644
--- a/tests/misc/programs/init-if-needed/Cargo.toml
+++ b/tests/misc/programs/init-if-needed/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
diff --git a/tests/misc/programs/lamports/Cargo.toml b/tests/misc/programs/lamports/Cargo.toml
index ea99d59e5b..341b34880f 100644
--- a/tests/misc/programs/lamports/Cargo.toml
+++ b/tests/misc/programs/lamports/Cargo.toml
@@ -10,6 +10,7 @@ crate-type = ["cdylib", "lib"]
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/misc/programs/lamports/src/lib.rs b/tests/misc/programs/lamports/src/lib.rs
index 84ac072d27..e8ea9732f9 100644
--- a/tests/misc/programs/lamports/src/lib.rs
+++ b/tests/misc/programs/lamports/src/lib.rs
@@ -6,7 +6,7 @@ declare_id!("Lamports11111111111111111111111111111111111");
 pub mod lamports {
     use super::*;
 
-    pub fn test_lamports_trait(ctx: Context, amount: u64) -> Result<()> {
+    pub fn transfer(ctx: Context, amount: u64) -> Result<()> {
         let pda = &ctx.accounts.pda;
         let signer = &ctx.accounts.signer;
 
@@ -52,13 +52,29 @@ pub mod lamports {
 
         Ok(())
     }
+
+    // Return overflow error in the case of overflow (instead of panicking)
+    pub fn overflow(ctx: Context) -> Result<()> {
+        let pda = &ctx.accounts.pda;
+
+        match pda.add_lamports(u64::MAX) {
+            Err(e) => assert_eq!(e, ProgramError::ArithmeticOverflow.into()),
+            _ => unreachable!(),
+        }
+
+        match pda.sub_lamports(u64::MAX) {
+            Err(e) => assert_eq!(e, ProgramError::ArithmeticOverflow.into()),
+            _ => unreachable!(),
+        }
+
+        Ok(())
+    }
 }
 
 #[derive(Accounts)]
-pub struct TestLamportsTrait<'info> {
+pub struct Transfer<'info> {
     #[account(mut)]
     pub signer: Signer<'info>,
-
     #[account(
         init,
         payer = signer,
@@ -67,9 +83,14 @@ pub struct TestLamportsTrait<'info> {
         bump
     )]
     pub pda: Account<'info, LamportsPda>,
-
     pub system_program: Program<'info, System>,
 }
 
+#[derive(Accounts)]
+pub struct Overflow<'info> {
+    #[account(seeds = [b"lamports"], bump)]
+    pub pda: Account<'info, LamportsPda>,
+}
+
 #[account]
 pub struct LamportsPda {}
diff --git a/tests/misc/programs/misc-optional/Cargo.toml b/tests/misc/programs/misc-optional/Cargo.toml
index 366cc8d1c9..d960fc7465 100644
--- a/tests/misc/programs/misc-optional/Cargo.toml
+++ b/tests/misc/programs/misc-optional/Cargo.toml
@@ -2,7 +2,6 @@
 name = "misc-optional"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.56"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
diff --git a/tests/misc/programs/misc-optional/src/context.rs b/tests/misc/programs/misc-optional/src/context.rs
index 90a82e80e5..1b988892c1 100644
--- a/tests/misc/programs/misc-optional/src/context.rs
+++ b/tests/misc/programs/misc-optional/src/context.rs
@@ -693,3 +693,54 @@ pub struct TestAssociatedTokenWithTokenProgramConstraint<'info> {
     /// CHECK: ignore
     pub associated_token_token_program: Option>,
 }
+
+#[derive(Accounts)]
+pub struct InitManyAssociatedTokenAccounts<'info> {
+    #[account(
+        init,
+        payer = user,
+        mint::authority = user,
+        mint::decimals = 9,
+    )]
+    pub mint: Account<'info, Mint>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = user,
+        associated_token::mint = mint,
+    )]
+    pub ata1: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = system_program,
+        associated_token::mint = mint,
+    )]
+    pub ata2: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata3: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = associated_token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata4: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = mint,
+        associated_token::mint = mint,
+    )]
+    pub ata5: Account<'info, TokenAccount>,
+    #[account(mut)]
+    pub user: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+}
diff --git a/tests/misc/programs/misc-optional/src/lib.rs b/tests/misc/programs/misc-optional/src/lib.rs
index 054f44ced5..b209a4d2e2 100644
--- a/tests/misc/programs/misc-optional/src/lib.rs
+++ b/tests/misc/programs/misc-optional/src/lib.rs
@@ -395,4 +395,11 @@ pub mod misc_optional {
     ) -> Result<()> {
         Ok(())
     }
+
+    #[allow(unused_variables)]
+    pub fn test_init_many_associated_token_accounts(
+        _ctx: Context,
+    ) -> Result<()> {
+        Ok(())
+    }
 }
diff --git a/tests/misc/programs/misc/Cargo.toml b/tests/misc/programs/misc/Cargo.toml
index caa7507bac..244e904898 100644
--- a/tests/misc/programs/misc/Cargo.toml
+++ b/tests/misc/programs/misc/Cargo.toml
@@ -2,7 +2,6 @@
 name = "misc"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
diff --git a/tests/misc/programs/misc/src/context.rs b/tests/misc/programs/misc/src/context.rs
index d844aaae80..2944ca4bfb 100644
--- a/tests/misc/programs/misc/src/context.rs
+++ b/tests/misc/programs/misc/src/context.rs
@@ -1,4 +1,5 @@
 use crate::account::*;
+use crate::program::Misc;
 use anchor_lang::prelude::*;
 use anchor_spl::associated_token::AssociatedToken;
 use anchor_spl::token::{Mint, Token, TokenAccount};
@@ -601,6 +602,7 @@ pub struct TestOnlyTokenProgramConstraint<'info> {
         token::token_program = token_token_program
     )]
     pub token: Account<'info, TokenAccount>,
+    /// CHECK: ignore
     pub token_token_program: AccountInfo<'info>,
 }
 
@@ -751,3 +753,62 @@ pub struct TestUsedIdentifiers<'info> {
     /// CHECK: ignore
     pub test4: AccountInfo<'info>,
 }
+
+#[derive(Accounts)]
+pub struct InitManyAssociatedTokenAccounts<'info> {
+    #[account(
+        init,
+        payer = user,
+        mint::authority = user,
+        mint::decimals = 9,
+    )]
+    pub mint: Account<'info, Mint>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = user,
+        associated_token::mint = mint,
+    )]
+    pub ata1: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = system_program,
+        associated_token::mint = mint,
+    )]
+    pub ata2: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata3: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = associated_token_program,
+        associated_token::mint = mint,
+    )]
+    pub ata4: Account<'info, TokenAccount>,
+    #[account(
+        init,
+        payer = user,
+        associated_token::authority = mint,
+        associated_token::mint = mint,
+    )]
+    pub ata5: Account<'info, TokenAccount>,
+    #[account(mut)]
+    pub user: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+}
+
+#[derive(Accounts)]
+pub struct TestBoxedOwnerConstraint<'info> {
+    // Redundant check to test compilation
+    #[account(owner = program.key())]
+    pub my_account: Box>,
+    pub program: Program<'info, Misc>,
+}
diff --git a/tests/misc/programs/misc/src/lib.rs b/tests/misc/programs/misc/src/lib.rs
index d0056018fe..d6b32b9fe4 100644
--- a/tests/misc/programs/misc/src/lib.rs
+++ b/tests/misc/programs/misc/src/lib.rs
@@ -385,4 +385,15 @@ pub mod misc {
     ) -> Result<()> {
         Ok(())
     }
+
+    pub fn test_init_many_associated_token_accounts(
+        _ctx: Context,
+    ) -> Result<()> {
+        Ok(())
+    }
+
+    /// Compilation test for https://github.com/coral-xyz/anchor/issues/3074
+    pub fn test_boxed_owner_constraint(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
 }
diff --git a/tests/misc/programs/overflow-checks/Cargo.toml b/tests/misc/programs/overflow-checks/Cargo.toml
index 52a1c5d5cf..252c84c13e 100644
--- a/tests/misc/programs/overflow-checks/Cargo.toml
+++ b/tests/misc/programs/overflow-checks/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/misc/programs/remaining-accounts/Cargo.toml b/tests/misc/programs/remaining-accounts/Cargo.toml
index 19f2010d5f..935a0454b6 100644
--- a/tests/misc/programs/remaining-accounts/Cargo.toml
+++ b/tests/misc/programs/remaining-accounts/Cargo.toml
@@ -2,7 +2,6 @@
 name = "remaining-accounts"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["init-if-needed"] }
diff --git a/tests/misc/programs/shared/Cargo.toml b/tests/misc/programs/shared/Cargo.toml
index 6f5e186c52..886aebd65d 100644
--- a/tests/misc/programs/shared/Cargo.toml
+++ b/tests/misc/programs/shared/Cargo.toml
@@ -1,7 +1,6 @@
 [package]
 name = "shared"
 version = "0.1.0"
-rust-version = "1.60"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/tests/misc/tests/lamports/lamports.ts b/tests/misc/tests/lamports/lamports.ts
index 678ed5c795..c2e52f59fa 100644
--- a/tests/misc/tests/lamports/lamports.ts
+++ b/tests/misc/tests/lamports/lamports.ts
@@ -1,23 +1,20 @@
 import * as anchor from "@coral-xyz/anchor";
 
-import { Lamports, IDL } from "../../target/types/lamports";
+import { Lamports } from "../../target/types/lamports";
 
-describe(IDL.name, () => {
+describe("lamports", () => {
   // Configure the client to use the local cluster
   anchor.setProvider(anchor.AnchorProvider.env());
 
   const program = anchor.workspace.Lamports as anchor.Program;
 
-  it("Can use the Lamports trait", async () => {
-    const signer = program.provider.publicKey!;
-    const [pda] = anchor.web3.PublicKey.findProgramAddressSync(
-      [Buffer.from("lamports")],
-      program.programId
-    );
-
+  it("Can transfer from/to PDA", async () => {
     await program.methods
-      .testLamportsTrait(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
-      .accounts({ signer, pda })
+      .transfer(new anchor.BN(anchor.web3.LAMPORTS_PER_SOL))
       .rpc();
   });
+
+  it("Returns an error on overflow", async () => {
+    await program.methods.overflow().rpc();
+  });
 });
diff --git a/tests/misc/tests/misc/misc.ts b/tests/misc/tests/misc/misc.ts
index 3567d928bb..60bfb7488f 100644
--- a/tests/misc/tests/misc/misc.ts
+++ b/tests/misc/tests/misc/misc.ts
@@ -438,18 +438,18 @@ const miscTest = (
       ];
 
       assert.deepStrictEqual(expectedRaw, resp.raw.slice(0, -2));
-      assert.strictEqual(resp.events[0].name, "E1");
+      assert.strictEqual(resp.events[0].name, "e1");
       assert.strictEqual(resp.events[0].data.data, 44);
-      assert.strictEqual(resp.events[1].name, "E2");
+      assert.strictEqual(resp.events[1].name, "e2");
       assert.strictEqual(resp.events[1].data.data, 1234);
-      assert.strictEqual(resp.events[2].name, "E3");
+      assert.strictEqual(resp.events[2].name, "e3");
       assert.strictEqual(resp.events[2].data.data, 9);
-      assert.strictEqual(resp.events[3].name, "E5");
+      assert.strictEqual(resp.events[3].name, "e5");
       assert.deepStrictEqual(
         resp.events[3].data.data,
         [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
       );
-      assert.strictEqual(resp.events[4].name, "E6");
+      assert.strictEqual(resp.events[4].name, "e6");
       assert.deepStrictEqual(
         resp.events[4].data.data,
         [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
@@ -1182,9 +1182,9 @@ const miscTest = (
         new anchor.Wallet(anchor.web3.Keypair.generate()),
         { commitment: program.provider.connection.commitment }
       );
+
       const anotherProgram = new anchor.Program(
-        miscIdl,
-        program.programId,
+        { ...miscIdl, address: program.programId },
         anotherProvider
       );
       // Request airdrop for secondary wallet.
@@ -2451,6 +2451,15 @@ const miscTest = (
       assert.deepStrictEqual(dataAccount.data, array2d);
     });
 
+    it("Can initialize 5 associated token accounts in one instruction", async () => {
+      const mint = anchor.web3.Keypair.generate();
+      await program.methods
+        .testInitManyAssociatedTokenAccounts()
+        .accounts({ mint: mint.publicKey, user: provider.wallet.publicKey })
+        .signers([mint])
+        .rpc();
+    });
+
     describe("Can validate PDAs derived from other program ids", () => {
       it("With bumps using create_program_address", async () => {
         const [firstPDA, firstBump] =
diff --git a/tests/misc/tests/overflow-checks/overflow-checks.ts b/tests/misc/tests/overflow-checks/overflow-checks.ts
index 8d08c271d2..615ee32258 100644
--- a/tests/misc/tests/overflow-checks/overflow-checks.ts
+++ b/tests/misc/tests/overflow-checks/overflow-checks.ts
@@ -1,8 +1,8 @@
 import * as anchor from "@coral-xyz/anchor";
 
-import { OverflowChecks, IDL } from "../../target/types/overflow_checks";
+import { OverflowChecks } from "../../target/types/overflow_checks";
 
-describe(IDL.name, () => {
+describe("overflow-checks", () => {
   anchor.setProvider(anchor.AnchorProvider.env());
 
   const program = anchor.workspace
diff --git a/tests/misc/tests/remaining-accounts/remaining-accounts.ts b/tests/misc/tests/remaining-accounts/remaining-accounts.ts
index 7a9fc9009e..b3160fc60c 100644
--- a/tests/misc/tests/remaining-accounts/remaining-accounts.ts
+++ b/tests/misc/tests/remaining-accounts/remaining-accounts.ts
@@ -1,11 +1,11 @@
 import * as anchor from "@coral-xyz/anchor";
+import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
 
 import { TOKEN_PROGRAM_ID, Token } from "@solana/spl-token";
 import { assert } from "chai";
-import { RemainingAccounts, IDL } from "../../target/types/remaining_accounts";
-import NodeWallet from "@coral-xyz/anchor/dist/cjs/nodewallet";
+import { RemainingAccounts } from "../../target/types/remaining_accounts";
 
-describe(IDL.name, () => {
+describe("remaining-accounts", () => {
   // Configure the client to use the local cluster
   anchor.setProvider(anchor.AnchorProvider.env());
   const payer = NodeWallet.local().payer;
diff --git a/tests/multiple-suites-run-single/programs/multiple-suites-run-single/Cargo.toml b/tests/multiple-suites-run-single/programs/multiple-suites-run-single/Cargo.toml
index 5b5e102925..c995e42aa9 100644
--- a/tests/multiple-suites-run-single/programs/multiple-suites-run-single/Cargo.toml
+++ b/tests/multiple-suites-run-single/programs/multiple-suites-run-single/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/multiple-suites/package.json b/tests/multiple-suites/package.json
index 329a2223dd..1d560b537f 100644
--- a/tests/multiple-suites/package.json
+++ b/tests/multiple-suites/package.json
@@ -1,6 +1,6 @@
 {
     "name": "multiple-suites",
-    "version": "0.29.0",
+    "version": "0.30.1",
     "license": "(MIT OR Apache-2.0)",
     "homepage": "https://github.com/coral-xyz/anchor#readme",
     "bugs": {
diff --git a/tests/multiple-suites/programs/multiple-suites/Cargo.toml b/tests/multiple-suites/programs/multiple-suites/Cargo.toml
index fca9cd19fa..cd84759c4e 100644
--- a/tests/multiple-suites/programs/multiple-suites/Cargo.toml
+++ b/tests/multiple-suites/programs/multiple-suites/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/multisig/package.json b/tests/multisig/package.json
index 08c0e4c20a..5fc36c1314 100644
--- a/tests/multisig/package.json
+++ b/tests/multisig/package.json
@@ -1,6 +1,6 @@
 {
   "name": "multisig",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/multisig/programs/multisig/Cargo.toml b/tests/multisig/programs/multisig/Cargo.toml
index 1293910f33..b271bf4d0f 100644
--- a/tests/multisig/programs/multisig/Cargo.toml
+++ b/tests/multisig/programs/multisig/Cargo.toml
@@ -2,7 +2,6 @@
 name = "multisig"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/multisig/tests/multisig.js b/tests/multisig/tests/multisig.js
index f65e7d1822..f3581ed159 100644
--- a/tests/multisig/tests/multisig.js
+++ b/tests/multisig/tests/multisig.js
@@ -59,7 +59,7 @@ describe("multisig", () => {
       },
     ];
     const newOwners = [ownerA.publicKey, ownerB.publicKey, ownerD.publicKey];
-    const data = program.coder.instruction.encode("set_owners", {
+    const data = program.coder.instruction.encode("setOwners", {
       owners: newOwners,
     });
 
diff --git a/tests/optional/package.json b/tests/optional/package.json
index c48fd59848..a5914f01cf 100644
--- a/tests/optional/package.json
+++ b/tests/optional/package.json
@@ -1,6 +1,6 @@
 {
   "name": "optional",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/optional/programs/allow-missing-optionals/Cargo.toml b/tests/optional/programs/allow-missing-optionals/Cargo.toml
index 90ae32316b..dddf7fd0db 100644
--- a/tests/optional/programs/allow-missing-optionals/Cargo.toml
+++ b/tests/optional/programs/allow-missing-optionals/Cargo.toml
@@ -11,6 +11,7 @@ name = "allow_missing_optionals"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang", features = ["allow-missing-optionals"] }
diff --git a/tests/optional/programs/optional/Cargo.toml b/tests/optional/programs/optional/Cargo.toml
index 090174508c..3711f52f87 100644
--- a/tests/optional/programs/optional/Cargo.toml
+++ b/tests/optional/programs/optional/Cargo.toml
@@ -11,6 +11,7 @@ name = "optional"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/optional/programs/optional/src/context.rs b/tests/optional/programs/optional/src/context.rs
index 34303963a7..4509e45250 100644
--- a/tests/optional/programs/optional/src/context.rs
+++ b/tests/optional/programs/optional/src/context.rs
@@ -10,7 +10,7 @@ pub struct Initialize<'info> {
     pub system_program: Option>,
     #[account(zero)]
     pub required: Account<'info, DataAccount>,
-    #[account(init, seeds=[DataPda::PREFIX.as_ref(), optional_account.as_ref().unwrap().key().as_ref()], bump, payer=payer, space=DataPda::LEN)]
+    #[account(init, seeds=[DataPda::PREFIX.as_bytes(), optional_account.as_ref().unwrap().key().as_ref()], bump, payer=payer, space=DataPda::LEN)]
     pub optional_pda: Option>,
 }
 
@@ -19,22 +19,22 @@ pub struct Initialize<'info> {
 pub struct Update<'info> {
     #[account(mut)]
     pub payer: Option>,
-    #[account(mut, seeds=[DataPda::PREFIX.as_ref(), optional_account.as_ref().unwrap().key().as_ref()], bump = pda_bump)]
+    #[account(mut, seeds=[DataPda::PREFIX.as_bytes(), optional_account.as_ref().unwrap().key().as_ref()], bump = pda_bump)]
     pub optional_pda: Option>,
     #[account(mut, signer, constraint = payer.is_some())]
     pub optional_account: Option>>,
 }
 
 #[derive(Accounts)]
-#[instruction(new_size: usize)]
+#[instruction(new_size: u64)]
 pub struct Realloc<'info> {
     #[account(mut)]
     pub payer: Option>,
-    #[account(mut, realloc = new_size, realloc::payer = payer, realloc::zero = false)]
+    #[account(mut, realloc = new_size as usize, realloc::payer = payer, realloc::zero = false)]
     pub optional_pda: Option>,
     pub required: Account<'info, DataAccount>,
     pub system_program: Option>,
-    #[account(mut, signer, realloc = new_size, realloc::payer = payer, realloc::zero = true)]
+    #[account(mut, signer, realloc = new_size as usize, realloc::payer = payer, realloc::zero = true)]
     pub optional_account: Option>,
 }
 
diff --git a/tests/optional/tests/optional.ts b/tests/optional/tests/optional.ts
index 19aeeb7f71..dc4bf4ad30 100644
--- a/tests/optional/tests/optional.ts
+++ b/tests/optional/tests/optional.ts
@@ -75,7 +75,7 @@ describe("Optional", () => {
       const [requiredKeypair, createRequiredIx] = await createRequired();
       const initializeIx = await program.methods
         .initialize(initializeValue1, initializeKey)
-        .accounts({
+        .accountsPartial({
           payer: null,
           optionalAccount: null,
           systemProgram,
@@ -115,7 +115,7 @@ describe("Optional", () => {
         .AllowMissingOptionals as Program;
       const doStuffIx = await allowMissingOptionals.methods
         .doStuff()
-        .accounts({
+        .accountsPartial({
           payer,
           systemProgram,
           optional2: null,
@@ -135,7 +135,7 @@ describe("Optional", () => {
         await program.methods
           .initialize(initializeValue1, initializeKey)
           .preInstructions([createRequiredIx])
-          .accounts({
+          .accountsPartial({
             payer,
             systemProgram,
             // @ts-ignore
@@ -149,7 +149,7 @@ describe("Optional", () => {
           "Unexpected success in creating a transaction that should have failed at the client level"
         );
       } catch (e) {
-        const errMsg = "Invalid arguments: required not provided";
+        const errMsg = "Account `required` not provided";
         // @ts-ignore
         let error: string = e.toString();
         assert(error.includes(errMsg), `Unexpected error: ${e}`);
@@ -161,7 +161,7 @@ describe("Optional", () => {
       await program.methods
         .initialize(initializeValue1, initializeKey)
         .preInstructions([createRequiredIx])
-        .accounts({
+        .accountsPartial({
           payer: null,
           systemProgram,
           required: requiredKeypair.publicKey,
@@ -182,7 +182,7 @@ describe("Optional", () => {
       await program.methods
         .initialize(initializeValue1, initializeKey)
         .preInstructions([createRequiredIx])
-        .accounts({
+        .accountsPartial({
           payer: null,
           systemProgram: null,
           required: requiredKeypair.publicKey,
@@ -205,7 +205,7 @@ describe("Optional", () => {
         await program.methods
           .initialize(initializeValue1, initializeKey)
           .preInstructions([createRequiredIx])
-          .accounts({
+          .accountsStrict({
             payer,
             systemProgram: null,
             required: requiredKeypair.publicKey,
@@ -238,7 +238,7 @@ describe("Optional", () => {
         await program.methods
           .initialize(initializeValue1, initializeKey)
           .preInstructions([createRequiredIx])
-          .accounts({
+          .accountsPartial({
             payer,
             systemProgram,
             required: requiredKeypair.publicKey,
@@ -262,7 +262,7 @@ describe("Optional", () => {
       await program.methods
         .initialize(initializeValue1, initializeKey)
         .preInstructions([createRequiredIx1])
-        .accounts({
+        .accountsPartial({
           payer,
           systemProgram,
           required: requiredKeypair1.publicKey,
@@ -290,7 +290,7 @@ describe("Optional", () => {
         await program.methods
           .initialize(initializeValue2, initializeKey)
           .preInstructions([createRequiredIx2])
-          .accounts({
+          .accountsPartial({
             payer,
             systemProgram,
             required: requiredKeypair2.publicKey,
@@ -319,7 +319,7 @@ describe("Optional", () => {
       await program.methods
         .initialize(initializeValue2, initializeKey)
         .preInstructions([createRequiredIx2])
-        .accounts({
+        .accountsPartial({
           payer,
           systemProgram,
           required: requiredKeypair2.publicKey,
@@ -352,7 +352,7 @@ describe("Optional", () => {
     it("Can update with invalid explicit pda bump with no pda", async () => {
       await program.methods
         .update(initializeValue2, initializeKey, dataPda2[1] - 1)
-        .accounts({
+        .accountsPartial({
           payer,
           optionalPda: null,
           optionalAccount: null,
@@ -364,7 +364,7 @@ describe("Optional", () => {
       try {
         await program.methods
           .update(initializeValue2, initializeKey, dataPda2[1] - 1)
-          .accounts({
+          .accountsPartial({
             payer,
             optionalPda: dataPda2[0],
             optionalAccount: dataAccountKeypair2.publicKey,
@@ -391,7 +391,7 @@ describe("Optional", () => {
       try {
         let txn = await program.methods
           .update(initializeValue2, initializeKey, dataPda2[1])
-          .accounts({
+          .accountsPartial({
             payer,
             optionalPda: dataPda2[0],
             optionalAccount: dataAccountKeypair2.publicKey,
@@ -424,7 +424,7 @@ describe("Optional", () => {
       try {
         await program.methods
           .update(initializeValue2, initializeKey, dataPda2[1])
-          .accounts({
+          .accountsPartial({
             payer: null,
             optionalPda: dataPda2[0],
             optionalAccount: dataAccountKeypair2.publicKey,
@@ -450,7 +450,7 @@ describe("Optional", () => {
     it("Can update an optional account", async () => {
       await program.methods
         .update(initializeValue2.muln(3), initializeKey, dataPda2[1])
-        .accounts({
+        .accountsPartial({
           payer,
           optionalPda: null,
           optionalAccount: dataAccountKeypair2.publicKey,
@@ -470,7 +470,7 @@ describe("Optional", () => {
       const newKey = web3.PublicKey.unique();
       await program.methods
         .update(initializeValue2, newKey, dataPda2[1])
-        .accounts({
+        .accountsPartial({
           payer,
           optionalPda: dataPda2[0],
           optionalAccount: dataAccountKeypair2.publicKey,
@@ -493,7 +493,7 @@ describe("Optional", () => {
       try {
         await program.methods
           .realloc(new BN(100))
-          .accounts({
+          .accountsPartial({
             payer: null,
             required: dataAccountKeypair1.publicKey,
             optionalPda: null,
@@ -522,7 +522,7 @@ describe("Optional", () => {
       try {
         await program.methods
           .realloc(new BN(100))
-          .accounts({
+          .accountsStrict({
             payer,
             required: dataAccountKeypair1.publicKey,
             optionalPda: null,
@@ -551,7 +551,7 @@ describe("Optional", () => {
       try {
         await program.methods
           .realloc(new BN(100))
-          .accounts({
+          .accountsPartial({
             payer,
             required: dataAccountKeypair1.publicKey,
             optionalPda: dataAccountKeypair2.publicKey,
@@ -579,7 +579,7 @@ describe("Optional", () => {
       const newLength = 100;
       await program.methods
         .realloc(new BN(newLength))
-        .accounts({
+        .accountsPartial({
           payer,
           required: dataAccountKeypair1.publicKey,
           optionalPda: null,
@@ -599,7 +599,7 @@ describe("Optional", () => {
       const newLength = program.account.dataAccount.size;
       await program.methods
         .realloc(new BN(newLength))
-        .accounts({
+        .accountsPartial({
           payer,
           required: dataAccountKeypair1.publicKey,
           optionalPda: null,
@@ -619,7 +619,7 @@ describe("Optional", () => {
       const newLength = 100;
       await program.methods
         .realloc(new BN(newLength))
-        .accounts({
+        .accountsPartial({
           payer,
           required: dataAccountKeypair1.publicKey,
           optionalPda: dataPda2[0],
@@ -690,7 +690,7 @@ describe("Optional", () => {
       await program.methods
         .initialize(initializeValue3, initializeKey)
         .preInstructions([createRequiredIx3])
-        .accounts({
+        .accountsPartial({
           payer,
           systemProgram,
           required: requiredKeypair3.publicKey,
@@ -708,7 +708,7 @@ describe("Optional", () => {
       await program.methods
         .initialize(initializeValue4, initializeKey)
         .preInstructions([createRequiredIx4])
-        .accounts({
+        .accountsPartial({
           payer,
           systemProgram,
           required: requiredKeypair4.publicKey,
@@ -726,7 +726,7 @@ describe("Optional", () => {
 
       await program.methods
         .update(initializeValue3, dataAccountKeypair3.publicKey, dataPda3[1])
-        .accounts({
+        .accountsPartial({
           payer,
           optionalPda: dataPda3[0],
           optionalAccount: dataAccountKeypair3.publicKey,
@@ -739,7 +739,7 @@ describe("Optional", () => {
       );
       await program.methods
         .update(initializeValue4, dataAccountKeypair4.publicKey, dataPda4[1])
-        .accounts({
+        .accountsPartial({
           payer,
           optionalPda: dataPda4[0],
           optionalAccount: dataAccountKeypair4.publicKey,
@@ -756,7 +756,7 @@ describe("Optional", () => {
       try {
         await program.methods
           .close()
-          .accounts({
+          .accountsPartial({
             payer: null,
             optionalPda: null,
             dataAccount: dataAccountKeypair3.publicKey,
@@ -784,7 +784,7 @@ describe("Optional", () => {
       try {
         await program.methods
           .close()
-          .accounts({
+          .accountsPartial({
             payer,
             optionalPda: dataPda4[0],
             dataAccount: dataAccountKeypair3.publicKey,
@@ -811,7 +811,7 @@ describe("Optional", () => {
     it("Can close an optional account", async () => {
       await program.methods
         .close()
-        .accounts({
+        .accountsPartial({
           payer,
           optionalPda: null,
           dataAccount: dataAccountKeypair3.publicKey,
@@ -828,7 +828,7 @@ describe("Optional", () => {
     it("Can close multiple optional accounts", async () => {
       await program.methods
         .close()
-        .accounts({
+        .accountsPartial({
           payer,
           optionalPda: dataPda4[0],
           dataAccount: dataAccountKeypair4.publicKey,
diff --git a/tests/package.json b/tests/package.json
index 7f2a29c2c8..7c782d2766 100644
--- a/tests/package.json
+++ b/tests/package.json
@@ -15,6 +15,9 @@
     "chat",
     "composite",
     "custom-coder",
+    "custom-discriminator",
+    "declare-id",
+    "declare-program",
     "errors",
     "escrow",
     "events",
@@ -32,6 +35,7 @@
     "pyth",
     "realloc",
     "spl/metadata",
+    "spl/token-extensions",
     "spl/token-proxy",
     "spl/token-wrapper",
     "spl/transfer-hook",
@@ -42,7 +46,6 @@
     "typescript",
     "validator-clone",
     "zero-copy",
-    "declare-id",
     "cpi-returns",
     "multiple-suites",
     "multiple-suites-run-single",
diff --git a/tests/pda-derivation/package.json b/tests/pda-derivation/package.json
index 291da9264d..36b78953d2 100644
--- a/tests/pda-derivation/package.json
+++ b/tests/pda-derivation/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pda-derivation",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/pda-derivation/programs/pda-derivation/Cargo.toml b/tests/pda-derivation/programs/pda-derivation/Cargo.toml
index afaebd9588..1c992747cd 100644
--- a/tests/pda-derivation/programs/pda-derivation/Cargo.toml
+++ b/tests/pda-derivation/programs/pda-derivation/Cargo.toml
@@ -2,7 +2,6 @@
 name = "pda-derivation"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,8 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
+anchor-spl = { path = "../../../../spl" }
diff --git a/tests/pda-derivation/programs/pda-derivation/src/lib.rs b/tests/pda-derivation/programs/pda-derivation/src/lib.rs
index f695813a89..a641904434 100644
--- a/tests/pda-derivation/programs/pda-derivation/src/lib.rs
+++ b/tests/pda-derivation/programs/pda-derivation/src/lib.rs
@@ -4,10 +4,15 @@
 mod other;
 
 use anchor_lang::prelude::*;
+use anchor_spl::{
+    associated_token::AssociatedToken,
+    token::{Mint, Token, TokenAccount},
+};
 
 declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
 
 pub const MY_SEED: [u8; 2] = *b"hi";
+pub const MY_SEED_BYTES: &[u8] = b"hi";
 pub const MY_SEED_STR: &str = "hi";
 pub const MY_SEED_U8: u8 = 1;
 pub const MY_SEED_U32: u32 = 2;
@@ -34,6 +39,18 @@ pub mod pda_derivation {
         ctx.accounts.account.data = 1337;
         Ok(())
     }
+
+    pub fn test_seed_constant(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn associated_token_resolution(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
+
+    pub fn seed_math_expr(_ctx: Context) -> Result<()> {
+        Ok(())
+    }
 }
 
 #[derive(Accounts)]
@@ -115,6 +132,52 @@ pub struct Nested<'info> {
     account_nested: AccountInfo<'info>,
 }
 
+#[derive(Accounts)]
+pub struct TestSeedConstant<'info> {
+    #[account(mut)]
+    my_account: Signer<'info>,
+    #[account(
+      init,
+      payer = my_account,
+      seeds = [MY_SEED_BYTES],
+      space = 100,
+      bump,
+    )]
+    account: Account<'info, MyAccount>,
+    system_program: Program<'info, System>,
+}
+
+#[derive(Accounts)]
+pub struct AssociatedTokenResolution<'info> {
+    #[account(
+        init,
+        payer = payer,
+        mint::authority = payer,
+        mint::decimals = 9,
+    )]
+    pub mint: Account<'info, Mint>,
+    #[account(
+        init,
+        payer = payer,
+        associated_token::authority = payer,
+        associated_token::mint = mint,
+    )]
+    pub ata: Account<'info, TokenAccount>,
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    pub system_program: Program<'info, System>,
+    pub token_program: Program<'info, Token>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+}
+
+#[derive(Accounts)]
+pub struct SeedMathExpr<'info> {
+    #[account(seeds = [b"const"], bump)]
+    pub my_account: Account<'info, MyAccount>,
+    #[account(seeds = [&(my_account.data + 1).to_le_bytes()], bump)]
+    pub math_expr_account: UncheckedAccount<'info>,
+}
+
 #[account]
 pub struct MyAccount {
     data: u64,
diff --git a/tests/pda-derivation/tests/typescript.spec.ts b/tests/pda-derivation/tests/typescript.spec.ts
index 7e82343c2e..1c904173b6 100644
--- a/tests/pda-derivation/tests/typescript.spec.ts
+++ b/tests/pda-derivation/tests/typescript.spec.ts
@@ -61,7 +61,7 @@ describe("typescript", () => {
       program.programId
     )[0];
 
-    const tx = program.methods.initMyAccount(seedA).accounts({
+    const tx = program.methods.initMyAccount(seedA).accountsPartial({
       base: base.publicKey,
       base2: base.publicKey,
       anotherBase: another.publicKey,
@@ -81,7 +81,6 @@ describe("typescript", () => {
     let called = false;
     const customProgram = new Program(
       program.idl,
-      program.programId,
       program.provider,
       program.coder,
       (instruction) => {
@@ -95,7 +94,7 @@ describe("typescript", () => {
     );
     await customProgram.methods
       .initMyAccount(seedA)
-      .accounts({
+      .accountsPartial({
         base: base.publicKey,
         base2: base.publicKey,
         anotherBase: another.publicKey,
@@ -104,4 +103,22 @@ describe("typescript", () => {
 
     expect(called).is.true;
   });
+
+  it("Can use constant seed ref", async () => {
+    await program.methods.testSeedConstant().rpc();
+  });
+
+  it("Can resolve associated token accounts", async () => {
+    const mintKp = anchor.web3.Keypair.generate();
+    await program.methods
+      .associatedTokenResolution()
+      .accounts({ mint: mintKp.publicKey })
+      .signers([mintKp])
+      .rpc();
+  });
+
+  // TODO: Support more expressions in the IDL e.g. math operations?
+  it("Can use unsupported expressions", () => {
+    // Compilation test to fix issues like https://github.com/coral-xyz/anchor/issues/2933
+  });
 });
diff --git a/tests/pyth/package.json b/tests/pyth/package.json
index e742843d94..8d09d64ff0 100644
--- a/tests/pyth/package.json
+++ b/tests/pyth/package.json
@@ -1,6 +1,6 @@
 {
   "name": "pyth",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/pyth/programs/pyth/Cargo.toml b/tests/pyth/programs/pyth/Cargo.toml
index e3ab5484ae..9a3ecb111d 100644
--- a/tests/pyth/programs/pyth/Cargo.toml
+++ b/tests/pyth/programs/pyth/Cargo.toml
@@ -2,7 +2,6 @@
 name = "pyth"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/realloc/package.json b/tests/realloc/package.json
index 0d06eed7d7..149233a774 100644
--- a/tests/realloc/package.json
+++ b/tests/realloc/package.json
@@ -1,6 +1,6 @@
 {
   "name": "realloc",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/realloc/programs/realloc/Cargo.toml b/tests/realloc/programs/realloc/Cargo.toml
index 4f014303e2..7cf118ddc1 100644
--- a/tests/realloc/programs/realloc/Cargo.toml
+++ b/tests/realloc/programs/realloc/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [profile.release]
 overflow-checks = true
diff --git a/tests/relations-derivation/package.json b/tests/relations-derivation/package.json
index 90230c3e9a..37870c0c2b 100644
--- a/tests/relations-derivation/package.json
+++ b/tests/relations-derivation/package.json
@@ -1,6 +1,6 @@
 {
   "name": "relations-derivation",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/relations-derivation/programs/relations-derivation/Cargo.toml b/tests/relations-derivation/programs/relations-derivation/Cargo.toml
index 3e373f6a26..ac6caeb0b3 100644
--- a/tests/relations-derivation/programs/relations-derivation/Cargo.toml
+++ b/tests/relations-derivation/programs/relations-derivation/Cargo.toml
@@ -2,7 +2,6 @@
 name = "relations-derivation"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/relations-derivation/programs/relations-derivation/src/lib.rs b/tests/relations-derivation/programs/relations-derivation/src/lib.rs
index c2bf74af0f..64ac6f27be 100644
--- a/tests/relations-derivation/programs/relations-derivation/src/lib.rs
+++ b/tests/relations-derivation/programs/relations-derivation/src/lib.rs
@@ -5,8 +5,6 @@ use anchor_lang::prelude::*;
 
 declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
 
-pub const SEED: &[u8] = b"contant-seed";
-
 #[program]
 pub mod relations_derivation {
     use super::*;
@@ -16,10 +14,12 @@ pub mod relations_derivation {
         ctx.accounts.account.bump = ctx.bumps.account;
         Ok(())
     }
+
     pub fn test_relation(_ctx: Context) -> Result<()> {
         Ok(())
     }
-    pub fn test_seed_constant(_ctx: Context) -> Result<()> {
+
+    pub fn test_address_relation(_ctx: Context) -> Result<()> {
         Ok(())
     }
 }
@@ -66,18 +66,11 @@ pub struct TestRelation<'info> {
 }
 
 #[derive(Accounts)]
-pub struct TestSeedConstant<'info> {
-    #[account(mut)]
-    my_account: Signer<'info>,
-    #[account(
-      init,
-      payer = my_account,
-      seeds = [SEED],
-      space = 100,
-      bump,
-    )]
-    account: Account<'info, MyAccount>,
-    system_program: Program<'info, System>,
+pub struct TestAddressRelation<'info> {
+    #[account(address = my_account.my_account)]
+    account: UncheckedAccount<'info>,
+    #[account(seeds = [b"seed"], bump = my_account.bump)]
+    my_account: Account<'info, MyAccount>,
 }
 
 #[account]
diff --git a/tests/relations-derivation/tests/typescript.spec.ts b/tests/relations-derivation/tests/typescript.spec.ts
index f5d326f974..b6ea7ad64a 100644
--- a/tests/relations-derivation/tests/typescript.spec.ts
+++ b/tests/relations-derivation/tests/typescript.spec.ts
@@ -41,7 +41,8 @@ describe("typescript", () => {
     await tx.rpc();
   });
 
-  it("Can use relations derivation with seed constant", async () => {
-    await program.methods.testSeedConstant().accounts({}).rpc();
+  it("Can use relations derivation with `address` constraint", () => {
+    // Only compile test for now since the IDL spec doesn't currently support field access
+    // expressions for the `address` constraint
   });
 });
diff --git a/tests/safety-checks/programs/account-info/Cargo.toml b/tests/safety-checks/programs/account-info/Cargo.toml
index e222f06ed7..495db50692 100644
--- a/tests/safety-checks/programs/account-info/Cargo.toml
+++ b/tests/safety-checks/programs/account-info/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/safety-checks/programs/ignore-non-accounts/Cargo.toml b/tests/safety-checks/programs/ignore-non-accounts/Cargo.toml
index e8de691a5d..284046b1ae 100644
--- a/tests/safety-checks/programs/ignore-non-accounts/Cargo.toml
+++ b/tests/safety-checks/programs/ignore-non-accounts/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/safety-checks/programs/unchecked-account/Cargo.toml b/tests/safety-checks/programs/unchecked-account/Cargo.toml
index 69443051c2..c5f455db83 100644
--- a/tests/safety-checks/programs/unchecked-account/Cargo.toml
+++ b/tests/safety-checks/programs/unchecked-account/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/solang/package.json b/tests/solang/package.json
index ed476c3993..9063210c76 100644
--- a/tests/solang/package.json
+++ b/tests/solang/package.json
@@ -1,6 +1,6 @@
 {
   "name": "solang",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/spl/metadata/package.json b/tests/spl/metadata/package.json
index 056d399924..fd2242b40a 100644
--- a/tests/spl/metadata/package.json
+++ b/tests/spl/metadata/package.json
@@ -1,6 +1,6 @@
 {
   "name": "metadata",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/spl/metadata/programs/metadata/Cargo.toml b/tests/spl/metadata/programs/metadata/Cargo.toml
index c38e0fb52f..cdae1891b6 100644
--- a/tests/spl/metadata/programs/metadata/Cargo.toml
+++ b/tests/spl/metadata/programs/metadata/Cargo.toml
@@ -2,7 +2,6 @@
 name = "metadata"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../../lang" }
diff --git a/tests/spl/token-extensions/Anchor.toml b/tests/spl/token-extensions/Anchor.toml
new file mode 100644
index 0000000000..92a46b8d97
--- /dev/null
+++ b/tests/spl/token-extensions/Anchor.toml
@@ -0,0 +1,14 @@
+[provider]
+cluster = "localnet"
+wallet = "~/.config/solana/id.json"
+
+[programs.localnet]
+token_extensions = "tKEkkQtgMXhdaz5NMTR3XbdUu215sZyHSj6Menvous1"
+
+[scripts]
+test = "yarn run ts-mocha -t 1000000 tests/*.ts"
+
+[features]
+
+[test.validator]
+url = "https://api.mainnet-beta.solana.com"
\ No newline at end of file
diff --git a/tests/spl/token-extensions/Cargo.toml b/tests/spl/token-extensions/Cargo.toml
new file mode 100644
index 0000000000..97d6280542
--- /dev/null
+++ b/tests/spl/token-extensions/Cargo.toml
@@ -0,0 +1,8 @@
+[workspace]
+members = [
+    "programs/*"
+]
+resolver = "2"
+
+[profile.release]
+overflow-checks = true
diff --git a/tests/spl/token-extensions/package.json b/tests/spl/token-extensions/package.json
new file mode 100644
index 0000000000..487bc1297f
--- /dev/null
+++ b/tests/spl/token-extensions/package.json
@@ -0,0 +1,22 @@
+{
+  "name": "token-extensions",
+  "version": "0.30.1",
+  "license": "(MIT OR Apache-2.0)",
+  "homepage": "https://github.com/coral-xyz/anchor#readme",
+  "bugs": {
+    "url": "https://github.com/coral-xyz/anchor/issues"
+  },
+  "repository": {
+    "type": "git",
+    "url": "https://github.com/coral-xyz/anchor.git"
+  },
+  "engines": {
+    "node": ">=11"
+  },
+  "scripts": {
+    "test": "anchor test"
+  },
+  "dependencies": {
+    "@solana/spl-token": "^0.3.9"
+  }
+}
diff --git a/tests/spl/token-extensions/programs/token-extensions/Cargo.toml b/tests/spl/token-extensions/programs/token-extensions/Cargo.toml
new file mode 100644
index 0000000000..0425682514
--- /dev/null
+++ b/tests/spl/token-extensions/programs/token-extensions/Cargo.toml
@@ -0,0 +1,24 @@
+[package]
+name = "token-extensions"
+version = "0.1.0"
+description = "Created with Anchor"
+edition = "2021"
+
+[lib]
+crate-type = ["cdylib", "lib"]
+name = "token_extensions"
+
+[features]
+no-entrypoint = []
+no-idl = []
+cpi = ["no-entrypoint"]
+default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
+
+[dependencies]
+anchor-lang = { path = "../../../../../lang", features = ["init-if-needed"] }
+anchor-spl = { path = "../../../../../spl" }
+spl-tlv-account-resolution = "0.6.3"
+spl-transfer-hook-interface = "0.6.3"
+spl-type-length-value = "0.4.3"
+spl-pod = "0.2.2"
diff --git a/tests/spl/token-extensions/programs/token-extensions/Xargo.toml b/tests/spl/token-extensions/programs/token-extensions/Xargo.toml
new file mode 100644
index 0000000000..1744f098ae
--- /dev/null
+++ b/tests/spl/token-extensions/programs/token-extensions/Xargo.toml
@@ -0,0 +1,2 @@
+[target.bpfel-unknown-unknown.dependencies.std]
+features = []
\ No newline at end of file
diff --git a/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs b/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs
new file mode 100644
index 0000000000..953666fe73
--- /dev/null
+++ b/tests/spl/token-extensions/programs/token-extensions/src/instructions.rs
@@ -0,0 +1,180 @@
+use anchor_lang::{prelude::*, solana_program::entrypoint::ProgramResult};
+
+use anchor_spl::{
+    associated_token::AssociatedToken,
+    token_2022::spl_token_2022::extension::{
+        group_member_pointer::GroupMemberPointer, metadata_pointer::MetadataPointer,
+        mint_close_authority::MintCloseAuthority, permanent_delegate::PermanentDelegate,
+        transfer_hook::TransferHook,
+    },
+    token_interface::{
+        spl_token_metadata_interface::state::TokenMetadata, token_metadata_initialize, Mint,
+        Token2022, TokenAccount, TokenMetadataInitialize,
+    },
+};
+use spl_pod::optional_keys::OptionalNonZeroPubkey;
+
+use crate::{
+    get_meta_list_size, get_mint_extensible_extension_data, get_mint_extension_data,
+    update_account_lamports_to_minimum_balance, META_LIST_ACCOUNT_SEED,
+};
+
+#[derive(AnchorDeserialize, AnchorSerialize)]
+pub struct CreateMintAccountArgs {
+    pub name: String,
+    pub symbol: String,
+    pub uri: String,
+}
+
+#[derive(Accounts)]
+#[instruction(args: CreateMintAccountArgs)]
+pub struct CreateMintAccount<'info> {
+    #[account(mut)]
+    pub payer: Signer<'info>,
+    #[account(mut)]
+    /// CHECK: can be any account
+    pub authority: Signer<'info>,
+    #[account()]
+    /// CHECK: can be any account
+    pub receiver: UncheckedAccount<'info>,
+    #[account(
+        init,
+        signer,
+        payer = payer,
+        mint::token_program = token_program,
+        mint::decimals = 0,
+        mint::authority = authority,
+        mint::freeze_authority = authority,
+        extensions::metadata_pointer::authority = authority,
+        extensions::metadata_pointer::metadata_address = mint,
+        extensions::group_member_pointer::authority = authority,
+        extensions::group_member_pointer::member_address = mint,
+        extensions::transfer_hook::authority = authority,
+        extensions::transfer_hook::program_id = crate::ID,
+        extensions::close_authority::authority = authority,
+        extensions::permanent_delegate::delegate = authority,
+    )]
+    pub mint: Box>,
+    #[account(
+        init,
+        payer = payer,
+        associated_token::token_program = token_program,
+        associated_token::mint = mint,
+        associated_token::authority = receiver,
+    )]
+    pub mint_token_account: Box>,
+    /// CHECK: This account's data is a buffer of TLV data
+    #[account(
+        init,
+        space = get_meta_list_size(None),
+        seeds = [META_LIST_ACCOUNT_SEED, mint.key().as_ref()],
+        bump,
+        payer = payer,
+    )]
+    pub extra_metas_account: UncheckedAccount<'info>,
+    pub system_program: Program<'info, System>,
+    pub associated_token_program: Program<'info, AssociatedToken>,
+    pub token_program: Program<'info, Token2022>,
+}
+
+impl<'info> CreateMintAccount<'info> {
+    fn initialize_token_metadata(
+        &self,
+        name: String,
+        symbol: String,
+        uri: String,
+    ) -> ProgramResult {
+        let cpi_accounts = TokenMetadataInitialize {
+            program_id: self.token_program.to_account_info(),
+            mint: self.mint.to_account_info(),
+            metadata: self.mint.to_account_info(), // metadata account is the mint, since data is stored in mint
+            mint_authority: self.authority.to_account_info(),
+            update_authority: self.authority.to_account_info(),
+        };
+        let cpi_ctx = CpiContext::new(self.token_program.to_account_info(), cpi_accounts);
+        token_metadata_initialize(cpi_ctx, name, symbol, uri)?;
+        Ok(())
+    }
+}
+
+pub fn handler(ctx: Context, args: CreateMintAccountArgs) -> Result<()> {
+    ctx.accounts.initialize_token_metadata(
+        args.name.clone(),
+        args.symbol.clone(),
+        args.uri.clone(),
+    )?;
+    ctx.accounts.mint.reload()?;
+    let mint_data = &mut ctx.accounts.mint.to_account_info();
+    let metadata = get_mint_extensible_extension_data::(mint_data)?;
+    assert_eq!(metadata.mint, ctx.accounts.mint.key());
+    assert_eq!(metadata.name, args.name);
+    assert_eq!(metadata.symbol, args.symbol);
+    assert_eq!(metadata.uri, args.uri);
+    let metadata_pointer = get_mint_extension_data::(mint_data)?;
+    let mint_key: Option = Some(ctx.accounts.mint.key());
+    let authority_key: Option = Some(ctx.accounts.authority.key());
+    assert_eq!(
+        metadata_pointer.metadata_address,
+        OptionalNonZeroPubkey::try_from(mint_key)?
+    );
+    assert_eq!(
+        metadata_pointer.authority,
+        OptionalNonZeroPubkey::try_from(authority_key)?
+    );
+    let permanent_delegate = get_mint_extension_data::(mint_data)?;
+    assert_eq!(
+        permanent_delegate.delegate,
+        OptionalNonZeroPubkey::try_from(authority_key)?
+    );
+    let close_authority = get_mint_extension_data::(mint_data)?;
+    assert_eq!(
+        close_authority.close_authority,
+        OptionalNonZeroPubkey::try_from(authority_key)?
+    );
+    let transfer_hook = get_mint_extension_data::(mint_data)?;
+    let program_id: Option = Some(ctx.program_id.key());
+    assert_eq!(
+        transfer_hook.authority,
+        OptionalNonZeroPubkey::try_from(authority_key)?
+    );
+    assert_eq!(
+        transfer_hook.program_id,
+        OptionalNonZeroPubkey::try_from(program_id)?
+    );
+    let group_member_pointer = get_mint_extension_data::(mint_data)?;
+    assert_eq!(
+        group_member_pointer.authority,
+        OptionalNonZeroPubkey::try_from(authority_key)?
+    );
+    assert_eq!(
+        group_member_pointer.member_address,
+        OptionalNonZeroPubkey::try_from(mint_key)?
+    );
+    // transfer minimum rent to mint account
+    update_account_lamports_to_minimum_balance(
+        ctx.accounts.mint.to_account_info(),
+        ctx.accounts.payer.to_account_info(),
+        ctx.accounts.system_program.to_account_info(),
+    )?;
+
+    Ok(())
+}
+
+#[derive(Accounts)]
+#[instruction()]
+pub struct CheckMintExtensionConstraints<'info> {
+    #[account(mut)]
+    /// CHECK: can be any account
+    pub authority: Signer<'info>,
+    #[account(
+        extensions::metadata_pointer::authority = authority,
+        extensions::metadata_pointer::metadata_address = mint,
+        extensions::group_member_pointer::authority = authority,
+        extensions::group_member_pointer::member_address = mint,
+        extensions::transfer_hook::authority = authority,
+        extensions::transfer_hook::program_id = crate::ID,
+        extensions::close_authority::authority = authority,
+        extensions::permanent_delegate::delegate = authority,
+    )]
+    pub mint: Box>,
+}
diff --git a/tests/spl/token-extensions/programs/token-extensions/src/lib.rs b/tests/spl/token-extensions/programs/token-extensions/src/lib.rs
new file mode 100644
index 0000000000..303be8240b
--- /dev/null
+++ b/tests/spl/token-extensions/programs/token-extensions/src/lib.rs
@@ -0,0 +1,32 @@
+//! An example of a program with token extensions enabled
+//!
+//! This program is intended to implement various token2022 extensions
+//!
+//! 
+
+use anchor_lang::prelude::*;
+
+pub mod instructions;
+pub mod utils;
+pub use instructions::*;
+pub use utils::*;
+
+declare_id!("tKEkkQtgMXhdaz5NMTR3XbdUu215sZyHSj6Menvous1");
+
+#[program]
+pub mod token_extensions {
+    use super::*;
+
+    pub fn create_mint_account(
+        ctx: Context,
+        args: CreateMintAccountArgs,
+    ) -> Result<()> {
+        instructions::handler(ctx, args)
+    }
+
+    pub fn check_mint_extensions_constraints(
+        _ctx: Context,
+    ) -> Result<()> {
+        Ok(())
+    }
+}
diff --git a/tests/spl/token-extensions/programs/token-extensions/src/utils.rs b/tests/spl/token-extensions/programs/token-extensions/src/utils.rs
new file mode 100644
index 0000000000..9a65280554
--- /dev/null
+++ b/tests/spl/token-extensions/programs/token-extensions/src/utils.rs
@@ -0,0 +1,88 @@
+use anchor_lang::{
+    prelude::Result,
+    solana_program::{
+        account_info::AccountInfo,
+        instruction::{get_stack_height, TRANSACTION_LEVEL_STACK_HEIGHT},
+        program::invoke,
+        pubkey::Pubkey,
+        rent::Rent,
+        system_instruction::transfer,
+        sysvar::Sysvar,
+    },
+    Lamports,
+};
+use anchor_spl::token_interface::spl_token_2022::{
+    extension::{BaseStateWithExtensions, Extension, StateWithExtensions},
+    solana_zk_token_sdk::zk_token_proof_instruction::Pod,
+    state::Mint,
+};
+use spl_tlv_account_resolution::{account::ExtraAccountMeta, state::ExtraAccountMetaList};
+use spl_type_length_value::variable_len_pack::VariableLenPack;
+
+pub const APPROVE_ACCOUNT_SEED: &[u8] = b"approve-account";
+pub const META_LIST_ACCOUNT_SEED: &[u8] = b"extra-account-metas";
+
+pub fn update_account_lamports_to_minimum_balance<'info>(
+    account: AccountInfo<'info>,
+    payer: AccountInfo<'info>,
+    system_program: AccountInfo<'info>,
+) -> Result<()> {
+    let extra_lamports = Rent::get()?.minimum_balance(account.data_len()) - account.get_lamports();
+    if extra_lamports > 0 {
+        invoke(
+            &transfer(payer.key, account.key, extra_lamports),
+            &[payer, account, system_program],
+        )?;
+    }
+    Ok(())
+}
+
+pub fn get_mint_extensible_extension_data(
+    account: &mut AccountInfo,
+) -> Result {
+    let mint_data = account.data.borrow();
+    let mint_with_extension = StateWithExtensions::::unpack(&mint_data)?;
+    let extension_data = mint_with_extension.get_variable_len_extension::()?;
+    Ok(extension_data)
+}
+
+pub fn get_mint_extension_data(account: &mut AccountInfo) -> Result {
+    let mint_data = account.data.borrow();
+    let mint_with_extension = StateWithExtensions::::unpack(&mint_data)?;
+    let extension_data = *mint_with_extension.get_extension::()?;
+    Ok(extension_data)
+}
+
+pub fn get_extra_meta_list_account_pda(mint: Pubkey) -> Pubkey {
+    Pubkey::find_program_address(&[META_LIST_ACCOUNT_SEED, mint.as_ref()], &crate::id()).0
+}
+
+pub fn get_approve_account_pda(mint: Pubkey) -> Pubkey {
+    Pubkey::find_program_address(&[APPROVE_ACCOUNT_SEED, mint.as_ref()], &crate::id()).0
+}
+
+/// Determine if we are in CPI
+pub fn hook_in_cpi() -> bool {
+    let stack_height = get_stack_height();
+    let tx_height = TRANSACTION_LEVEL_STACK_HEIGHT;
+    let hook_height: usize = tx_height + 1;
+
+    stack_height > hook_height
+}
+
+pub fn get_meta_list(approve_account: Option) -> Vec {
+    if let Some(approve_account) = approve_account {
+        return vec![ExtraAccountMeta {
+            discriminator: 0,
+            address_config: approve_account.to_bytes(),
+            is_signer: false.into(),
+            is_writable: true.into(),
+        }];
+    }
+    vec![]
+}
+
+pub fn get_meta_list_size(approve_account: Option) -> usize {
+    // safe because it's either 0 or 1
+    ExtraAccountMetaList::size_of(get_meta_list(approve_account).len()).unwrap()
+}
diff --git a/tests/spl/token-extensions/tests/token-extensions.ts b/tests/spl/token-extensions/tests/token-extensions.ts
new file mode 100644
index 0000000000..f2b498d953
--- /dev/null
+++ b/tests/spl/token-extensions/tests/token-extensions.ts
@@ -0,0 +1,84 @@
+import * as anchor from "@coral-xyz/anchor";
+import { Program } from "@coral-xyz/anchor";
+import { PublicKey, Keypair } from "@solana/web3.js";
+import { TokenExtensions } from "../target/types/token_extensions";
+import { ASSOCIATED_PROGRAM_ID } from "@coral-xyz/anchor/dist/cjs/utils/token";
+import { it } from "node:test";
+
+const TOKEN_2022_PROGRAM_ID = new anchor.web3.PublicKey(
+  "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
+);
+
+export function associatedAddress({
+  mint,
+  owner,
+}: {
+  mint: PublicKey;
+  owner: PublicKey;
+}): PublicKey {
+  return PublicKey.findProgramAddressSync(
+    [owner.toBuffer(), TOKEN_2022_PROGRAM_ID.toBuffer(), mint.toBuffer()],
+    ASSOCIATED_PROGRAM_ID
+  )[0];
+}
+
+describe("token extensions", () => {
+  const provider = anchor.AnchorProvider.env();
+  anchor.setProvider(provider);
+
+  const program = anchor.workspace.TokenExtensions as Program;
+
+  const payer = Keypair.generate();
+
+  it("airdrop payer", async () => {
+    await provider.connection.confirmTransaction(
+      await provider.connection.requestAirdrop(payer.publicKey, 10000000000),
+      "confirmed"
+    );
+  });
+
+  let mint = new Keypair();
+
+  it("Create mint account test passes", async () => {
+    const [extraMetasAccount] = PublicKey.findProgramAddressSync(
+      [
+        anchor.utils.bytes.utf8.encode("extra-account-metas"),
+        mint.publicKey.toBuffer(),
+      ],
+      program.programId
+    );
+    await program.methods
+      .createMintAccount({
+        name: "hello",
+        symbol: "hi",
+        uri: "https://hi.com",
+      })
+      .accountsStrict({
+        payer: payer.publicKey,
+        authority: payer.publicKey,
+        receiver: payer.publicKey,
+        mint: mint.publicKey,
+        mintTokenAccount: associatedAddress({
+          mint: mint.publicKey,
+          owner: payer.publicKey,
+        }),
+        extraMetasAccount: extraMetasAccount,
+        systemProgram: anchor.web3.SystemProgram.programId,
+        associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
+        tokenProgram: TOKEN_2022_PROGRAM_ID,
+      })
+      .signers([mint, payer])
+      .rpc();
+  });
+
+  it("mint extension constraints test passes", async () => {
+    await program.methods
+      .checkMintExtensionsConstraints()
+      .accountsStrict({
+        authority: payer.publicKey,
+        mint: mint.publicKey,
+      })
+      .signers([payer])
+      .rpc();
+  });
+});
diff --git a/tests/spl/token-extensions/tsconfig.json b/tests/spl/token-extensions/tsconfig.json
new file mode 100644
index 0000000000..c7f23d9eaf
--- /dev/null
+++ b/tests/spl/token-extensions/tsconfig.json
@@ -0,0 +1,11 @@
+{
+  "compilerOptions": {
+    "types": ["mocha", "chai", "node"],
+    "typeRoots": ["./node_modules/@types"],
+    "lib": ["es2015"],
+    "module": "commonjs",
+    "target": "es6",
+    "esModuleInterop": true,
+    "skipLibCheck": true
+  }
+}
diff --git a/tests/spl/token-proxy/Anchor.toml b/tests/spl/token-proxy/Anchor.toml
index 46bef61d28..5c5f278453 100644
--- a/tests/spl/token-proxy/Anchor.toml
+++ b/tests/spl/token-proxy/Anchor.toml
@@ -7,11 +7,3 @@ token_proxy = "Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS"
 
 [scripts]
 test = "yarn run mocha -t 1000000 tests/"
-
-[features]
-
-[test.validator]
-url = "https://api.mainnet-beta.solana.com"
-
-[[test.validator.clone]]
-address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
diff --git a/tests/spl/token-proxy/package.json b/tests/spl/token-proxy/package.json
index 1935ca7bcd..bda4e6f519 100644
--- a/tests/spl/token-proxy/package.json
+++ b/tests/spl/token-proxy/package.json
@@ -1,6 +1,6 @@
 {
   "name": "token-proxy",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/spl/token-proxy/programs/token-proxy/Cargo.toml b/tests/spl/token-proxy/programs/token-proxy/Cargo.toml
index 122355d369..c86b06b0f6 100644
--- a/tests/spl/token-proxy/programs/token-proxy/Cargo.toml
+++ b/tests/spl/token-proxy/programs/token-proxy/Cargo.toml
@@ -2,7 +2,6 @@
 name = "token-proxy"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -12,6 +11,7 @@ name = "token_proxy"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../../lang" }
diff --git a/tests/spl/token-proxy/programs/token-proxy/src/lib.rs b/tests/spl/token-proxy/programs/token-proxy/src/lib.rs
index 8f8d6710ed..9f3ff8d6b6 100644
--- a/tests/spl/token-proxy/programs/token-proxy/src/lib.rs
+++ b/tests/spl/token-proxy/programs/token-proxy/src/lib.rs
@@ -191,7 +191,8 @@ pub struct ProxyCreateAssociatedTokenAccount<'info> {
 pub struct ProxyCreateMint<'info> {
     #[account(mut)]
     pub authority: Signer<'info>,
-    #[account(init,
+    #[account(
+        init,
         mint::decimals = 9,
         mint::authority = authority,
         seeds = [authority.key().as_ref(), name.as_bytes(), b"token-proxy-mint"],
diff --git a/tests/spl/token-proxy/tests/token-proxy.js b/tests/spl/token-proxy/tests/token-proxy.js
index c7f4e0fed4..c5826a00f9 100644
--- a/tests/spl/token-proxy/tests/token-proxy.js
+++ b/tests/spl/token-proxy/tests/token-proxy.js
@@ -25,8 +25,9 @@ describe("program", () => {
   const program = anchor.workspace.TokenProxy;
 
   TOKEN_PROGRAMS.forEach((tokenProgram) => {
-    const name =
-      tokenProgram.programId === SPL_TOKEN_PROGRAM_ID ? "token" : "token-2022";
+    const name = tokenProgram.programId.equals(SPL_TOKEN_PROGRAM_ID)
+      ? "token"
+      : "token-2022";
     describe(name, () => {
       let mint = null;
       let from = null;
diff --git a/tests/spl/token-wrapper/Anchor.toml b/tests/spl/token-wrapper/Anchor.toml
index 0ad934e07d..bc8910bfa9 100644
--- a/tests/spl/token-wrapper/Anchor.toml
+++ b/tests/spl/token-wrapper/Anchor.toml
@@ -7,11 +7,3 @@ token_wrapper = "4ZPcGU8MX8oL2u1EtErHzixAbgNBNeE9yoYq3kKMqnAy"
 
 [scripts]
 test = "yarn run ts-mocha -t 1000000 tests/*.ts"
-
-[features]
-
-[test.validator]
-url = "https://api.mainnet-beta.solana.com"
-
-[[test.validator.clone]]
-address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
diff --git a/tests/spl/token-wrapper/package.json b/tests/spl/token-wrapper/package.json
index ccc86b4b79..ce70ff4b2f 100644
--- a/tests/spl/token-wrapper/package.json
+++ b/tests/spl/token-wrapper/package.json
@@ -1,6 +1,6 @@
 {
   "name": "token-wrapper",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/spl/token-wrapper/programs/token-wrapper/Cargo.toml b/tests/spl/token-wrapper/programs/token-wrapper/Cargo.toml
index e83d329891..eed1afea4f 100644
--- a/tests/spl/token-wrapper/programs/token-wrapper/Cargo.toml
+++ b/tests/spl/token-wrapper/programs/token-wrapper/Cargo.toml
@@ -2,7 +2,6 @@
 name = "token-wrapper"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../../lang" }
diff --git a/tests/spl/transfer-hook/Anchor.toml b/tests/spl/transfer-hook/Anchor.toml
index fe0caa8f55..b57671cfb2 100644
--- a/tests/spl/transfer-hook/Anchor.toml
+++ b/tests/spl/transfer-hook/Anchor.toml
@@ -7,11 +7,3 @@ transfer_hook = "9vaEfNU4HquQJuNQ6HYrpJW518a3n4wNUt5mAMY2UUHW"
 
 [scripts]
 test = "yarn run ts-mocha -t 1000000 tests/*.ts"
-
-[features]
-
-[test.validator]
-url = "https://api.mainnet-beta.solana.com"
-
-[[test.validator.clone]]
-address = "TokenzQdBNbLqP5VEhdkAS6EPFLC1PHnBqCXEpPxuEb"
diff --git a/tests/spl/transfer-hook/package.json b/tests/spl/transfer-hook/package.json
index a2e70e663d..c97b24f510 100644
--- a/tests/spl/transfer-hook/package.json
+++ b/tests/spl/transfer-hook/package.json
@@ -1,6 +1,6 @@
 {
   "name": "transfer-hook",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/spl/transfer-hook/programs/transfer-hook/Cargo.toml b/tests/spl/transfer-hook/programs/transfer-hook/Cargo.toml
index 1c76665c7d..c662b2b1e9 100644
--- a/tests/spl/transfer-hook/programs/transfer-hook/Cargo.toml
+++ b/tests/spl/transfer-hook/programs/transfer-hook/Cargo.toml
@@ -2,7 +2,6 @@
 name = "transfer-hook"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../../lang", features = ["interface-instructions"] }
diff --git a/tests/spl/transfer-hook/tests/transfer-hook.ts b/tests/spl/transfer-hook/tests/transfer-hook.ts
index 6fca5350a2..249cded332 100644
--- a/tests/spl/transfer-hook/tests/transfer-hook.ts
+++ b/tests/spl/transfer-hook/tests/transfer-hook.ts
@@ -146,7 +146,6 @@ describe("transfer hook", () => {
   it("can create an `InitializeExtraAccountMetaList` instruction with the proper discriminator", async () => {
     const ix = await program.methods
       .initialize(extraMetas as any[])
-      .interface("spl_transfer_hook_interface::initialize_extra_account_metas")
       .accounts({
         extraMetasAccount: extraMetasAddress,
         mint: mint.publicKey,
@@ -162,8 +161,7 @@ describe("transfer hook", () => {
     );
     const { name, data } = new anchor.BorshInstructionCoder(program.idl).decode(
       ix.data,
-      "hex",
-      "initialize"
+      "hex"
     );
     assert.equal(name, "initialize");
     assert.property(data, "metas");
@@ -174,7 +172,6 @@ describe("transfer hook", () => {
   it("can create an `Execute` instruction with the proper discriminator", async () => {
     const ix = await program.methods
       .execute(new anchor.BN(transferAmount))
-      .interface("spl_transfer_hook_interface::execute")
       .accounts({
         sourceAccount: source,
         mint: mint.publicKey,
@@ -193,8 +190,7 @@ describe("transfer hook", () => {
     );
     const { name, data } = new anchor.BorshInstructionCoder(program.idl).decode(
       ix.data,
-      "hex",
-      "execute"
+      "hex"
     );
     assert.equal(name, "execute");
     assert.property(data, "amount");
@@ -206,7 +202,6 @@ describe("transfer hook", () => {
     // Initialize the extra metas
     await program.methods
       .initialize(extraMetas as any[])
-      .interface("spl_transfer_hook_interface::initialize_extra_account_metas")
       .accounts({
         extraMetasAccount: extraMetasAddress,
         mint: mint.publicKey,
diff --git a/tests/swap/package.json b/tests/swap/package.json
index ab37c0ff7d..4327e5e233 100644
--- a/tests/swap/package.json
+++ b/tests/swap/package.json
@@ -1,6 +1,6 @@
 {
   "name": "swap",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/swap/programs/swap/Cargo.toml b/tests/swap/programs/swap/Cargo.toml
index e45242d9e9..9fe3bc2c3b 100644
--- a/tests/swap/programs/swap/Cargo.toml
+++ b/tests/swap/programs/swap/Cargo.toml
@@ -2,7 +2,6 @@
 name = "swap"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/system-accounts/package.json b/tests/system-accounts/package.json
index 22fb238151..a3211bfe26 100644
--- a/tests/system-accounts/package.json
+++ b/tests/system-accounts/package.json
@@ -1,6 +1,6 @@
 {
   "name": "system-accounts",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/system-accounts/programs/system-accounts/Cargo.toml b/tests/system-accounts/programs/system-accounts/Cargo.toml
index f50c6b6686..87212eaada 100644
--- a/tests/system-accounts/programs/system-accounts/Cargo.toml
+++ b/tests/system-accounts/programs/system-accounts/Cargo.toml
@@ -2,7 +2,6 @@
 name = "system-accounts"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -12,6 +11,7 @@ name = "system_accounts"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/sysvars/package.json b/tests/sysvars/package.json
index f1b4cd81c9..54ffc6e258 100644
--- a/tests/sysvars/package.json
+++ b/tests/sysvars/package.json
@@ -1,6 +1,6 @@
 {
   "name": "sysvars",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/sysvars/programs/sysvars/Cargo.toml b/tests/sysvars/programs/sysvars/Cargo.toml
index e0249a20f1..7743752b76 100644
--- a/tests/sysvars/programs/sysvars/Cargo.toml
+++ b/tests/sysvars/programs/sysvars/Cargo.toml
@@ -2,7 +2,6 @@
 name = "sysvars"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -12,6 +11,7 @@ name = "sysvars"
 [features]
 no-entrypoint = []
 cpi = ["no-entrypoint"]
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/tictactoe/package.json b/tests/tictactoe/package.json
index ef541b0c45..a471abb8f3 100644
--- a/tests/tictactoe/package.json
+++ b/tests/tictactoe/package.json
@@ -1,6 +1,6 @@
 {
   "name": "tictactoe",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/tictactoe/programs/tictactoe/Cargo.toml b/tests/tictactoe/programs/tictactoe/Cargo.toml
index b79004546e..0f68e9366a 100644
--- a/tests/tictactoe/programs/tictactoe/Cargo.toml
+++ b/tests/tictactoe/programs/tictactoe/Cargo.toml
@@ -2,7 +2,6 @@
 name = "tictactoe"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build", "anchor-spl/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/typescript/package.json b/tests/typescript/package.json
index 94f8d27814..c338ff7f3e 100644
--- a/tests/typescript/package.json
+++ b/tests/typescript/package.json
@@ -1,6 +1,6 @@
 {
   "name": "typescript-example",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/typescript/programs/shared/Cargo.toml b/tests/typescript/programs/shared/Cargo.toml
index 6f5e186c52..886aebd65d 100644
--- a/tests/typescript/programs/shared/Cargo.toml
+++ b/tests/typescript/programs/shared/Cargo.toml
@@ -1,7 +1,6 @@
 [package]
 name = "shared"
 version = "0.1.0"
-rust-version = "1.60"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/tests/typescript/programs/typescript/Cargo.toml b/tests/typescript/programs/typescript/Cargo.toml
index ddaaf1e5f1..0104e47261 100644
--- a/tests/typescript/programs/typescript/Cargo.toml
+++ b/tests/typescript/programs/typescript/Cargo.toml
@@ -2,7 +2,6 @@
 name = "typescript"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/validator-clone/package.json b/tests/validator-clone/package.json
index e6582ed95c..338257929c 100644
--- a/tests/validator-clone/package.json
+++ b/tests/validator-clone/package.json
@@ -1,6 +1,6 @@
 {
   "name": "validator-clone",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/validator-clone/programs/validator-clone/Cargo.toml b/tests/validator-clone/programs/validator-clone/Cargo.toml
index d246a8c83b..7d21e4f46f 100644
--- a/tests/validator-clone/programs/validator-clone/Cargo.toml
+++ b/tests/validator-clone/programs/validator-clone/Cargo.toml
@@ -14,6 +14,7 @@ no-idl = []
 no-log-ix-name = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/zero-copy/package.json b/tests/zero-copy/package.json
index c8128fbe41..386538a86b 100644
--- a/tests/zero-copy/package.json
+++ b/tests/zero-copy/package.json
@@ -1,6 +1,6 @@
 {
   "name": "zero-copy",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "license": "(MIT OR Apache-2.0)",
   "homepage": "https://github.com/coral-xyz/anchor#readme",
   "bugs": {
diff --git a/tests/zero-copy/programs/shared/Cargo.toml b/tests/zero-copy/programs/shared/Cargo.toml
index 6f5e186c52..886aebd65d 100644
--- a/tests/zero-copy/programs/shared/Cargo.toml
+++ b/tests/zero-copy/programs/shared/Cargo.toml
@@ -1,7 +1,6 @@
 [package]
 name = "shared"
 version = "0.1.0"
-rust-version = "1.60"
 edition = "2021"
 
 # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
diff --git a/tests/zero-copy/programs/zero-copy/Cargo.toml b/tests/zero-copy/programs/zero-copy/Cargo.toml
index 1c03914cc5..df3dcba28e 100644
--- a/tests/zero-copy/programs/zero-copy/Cargo.toml
+++ b/tests/zero-copy/programs/zero-copy/Cargo.toml
@@ -2,7 +2,6 @@
 name = "zero-copy"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -15,6 +14,7 @@ no-idl = []
 cpi = ["no-entrypoint"]
 default = []
 test-sbf = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
@@ -22,4 +22,4 @@ bytemuck = {version = "1.4.0", features = ["derive", "min_const_generics"]}
 
 [dev-dependencies]
 anchor-client = { path = "../../../../client", features = ["debug", "async"] }
-solana-program-test = ">=1.16, <1.18"
+solana-program-test = "1.17.3"
diff --git a/tests/zero-copy/programs/zero-copy/tests/compute_unit_test.rs b/tests/zero-copy/programs/zero-copy/tests/compute_unit_test.rs
index 182c13d6b8..9457cfe970 100644
--- a/tests/zero-copy/programs/zero-copy/tests/compute_unit_test.rs
+++ b/tests/zero-copy/programs/zero-copy/tests/compute_unit_test.rs
@@ -22,7 +22,7 @@ async fn update_foo() {
     let foo_pubkey = Pubkey::new_unique();
     let foo_account = {
         let mut foo_data = Vec::new();
-        foo_data.extend_from_slice(&zero_copy::Foo::discriminator());
+        foo_data.extend_from_slice(zero_copy::Foo::DISCRIMINATOR);
         foo_data.extend_from_slice(bytemuck::bytes_of(&zero_copy::Foo {
             authority: authority.pubkey(),
             ..zero_copy::Foo::default()
diff --git a/tests/zero-copy/programs/zero-cpi/Cargo.toml b/tests/zero-copy/programs/zero-cpi/Cargo.toml
index c3f74ad346..8ade06b2a6 100644
--- a/tests/zero-copy/programs/zero-cpi/Cargo.toml
+++ b/tests/zero-copy/programs/zero-cpi/Cargo.toml
@@ -2,7 +2,6 @@
 name = "zero-cpi"
 version = "0.1.0"
 description = "Created with Anchor"
-rust-version = "1.60"
 edition = "2021"
 
 [lib]
@@ -14,6 +13,7 @@ no-entrypoint = []
 no-idl = []
 cpi = ["no-entrypoint"]
 default = []
+idl-build = ["anchor-lang/idl-build"]
 
 [dependencies]
 anchor-lang = { path = "../../../../lang" }
diff --git a/tests/zero-copy/tests/zero-copy.js b/tests/zero-copy/tests/zero-copy.js
index 805cd8c467..311ad046e6 100644
--- a/tests/zero-copy/tests/zero-copy.js
+++ b/tests/zero-copy/tests/zero-copy.js
@@ -57,7 +57,7 @@ describe("zero-copy", () => {
     );
   });
 
-  it("Updates a a second zero copy account field", async () => {
+  it("Updates a second zero copy account field", async () => {
     await program.rpc.updateFooSecond(new BN(55), {
       accounts: {
         foo: foo.publicKey,
diff --git a/ts/packages/anchor-errors/package.json b/ts/packages/anchor-errors/package.json
new file mode 100644
index 0000000000..65bd2080ef
--- /dev/null
+++ b/ts/packages/anchor-errors/package.json
@@ -0,0 +1,32 @@
+{
+  "name": "@coral-xyz/anchor-errors",
+  "version": "0.30.1",
+  "description": "Anchor error codes",
+  "main": "dist/index.js",
+  "types": "dist/index.d.ts",
+  "exports": {
+    ".": "./dist/index.js"
+  },
+  "license": "Apache-2.0",
+  "publishConfig": {
+    "access": "public"
+  },
+  "engines": {
+    "node": ">=10"
+  },
+  "scripts": {
+    "build": "tsc",
+    "lint:fix": "prettier src/** -w",
+    "lint": "prettier src/** --check",
+    "watch": "tsc --watch",
+    "prepublishOnly": "yarn build",
+    "test": "",
+    "clean": "rm -rf dist"
+  },
+  "files": [
+    "dist"
+  ],
+  "devDependencies": {
+    "prettier": "^2.1.2"
+  }
+}
diff --git a/ts/packages/anchor-errors/src/index.ts b/ts/packages/anchor-errors/src/index.ts
new file mode 100644
index 0000000000..d6ce13742c
--- /dev/null
+++ b/ts/packages/anchor-errors/src/index.ts
@@ -0,0 +1,257 @@
+// Instruction errors.
+
+/** 8 byte instruction identifier not provided. */
+export const ANCHOR_ERROR__INSTRUCTION_MISSING = 100;
+/** Fallback functions are not supported. */
+export const ANCHOR_ERROR__INSTRUCTION_FALLBACK_NOT_FOUND = 101;
+/** The program could not deserialize the given instruction. */
+export const ANCHOR_ERROR__INSTRUCTION_DID_NOT_DESERIALIZE = 102;
+/** The program could not serialize the given instruction. */
+export const ANCHOR_ERROR__INSTRUCTION_DID_NOT_SERIALIZE = 103;
+
+// IDL instruction errors.
+
+/** The program was compiled without idl instructions. */
+export const ANCHOR_ERROR__IDL_INSTRUCTION_STUB = 1000;
+/** The transaction was given an invalid program for the IDL instruction. */
+export const ANCHOR_ERROR__IDL_INSTRUCTION_INVALID_PROGRAM = 1001;
+/** IDL account must be empty in order to resize, try closing first. */
+export const ANCHOR_ERROR__IDL_ACCOUNT_NOT_EMPTY = 1002;
+
+// Event instructions.
+
+/** The program was compiled without `event-cpi` feature. */
+export const ANCHOR_ERROR__EVENT_INSTRUCTION_STUB = 1500;
+
+// Constraint errors.
+
+/** A mut constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MUT = 2000;
+/** A has one constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_HAS_ONE = 2001;
+/** A signer constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_SIGNER = 2002;
+/** A raw constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_RAW = 2003;
+/** An owner constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_OWNER = 2004;
+/** A rent exemption constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_RENT_EXEMPT = 2005;
+/** A seeds constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_SEEDS = 2006;
+/** An executable constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_EXECUTABLE = 2007;
+/** Deprecated Error, feel free to replace with something else. */
+export const ANCHOR_ERROR__CONSTRAINT_STATE = 2008;
+/** An associated constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_ASSOCIATED = 2009;
+/** An associated init constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_ASSOCIATED_INIT = 2010;
+/** A close constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_CLOSE = 2011;
+/** An address constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_ADDRESS = 2012;
+/** Expected zero account discriminant. */
+export const ANCHOR_ERROR__CONSTRAINT_ZERO = 2013;
+/** A token mint constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_TOKEN_MINT = 2014;
+/** A token owner constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_TOKEN_OWNER = 2015;
+/** A mint mint authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_MINT_AUTHORITY = 2016;
+/** A mint freeze authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_FREEZE_AUTHORITY = 2017;
+/** A mint decimals constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_DECIMALS = 2018;
+/** A space constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_SPACE = 2019;
+/** A required account for the constraint is None. */
+export const ANCHOR_ERROR__CONSTRAINT_ACCOUNT_IS_NONE = 2020;
+/** A token account token program constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_TOKEN_TOKEN_PROGRAM = 2021;
+/** A mint token program constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_TOKEN_PROGRAM = 2022;
+/** An associated token account token program constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_ASSOCIATED_TOKEN_TOKEN_PROGRAM = 2023;
+/** A group pointer extension constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION = 2024;
+/** A group pointer extension authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION_AUTHORITY = 2025;
+/** A group pointer extension group address constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION_GROUP_ADDRESS = 2026;
+/** A group member pointer extension constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION = 2027;
+/** A group member pointer extension authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION_AUTHORITY = 2028;
+/** A group member pointer extension group address constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION_MEMBER_ADDRESS = 2029;
+/** A metadata pointer extension constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION = 2030;
+/** A metadata pointer extension authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION_AUTHORITY = 2031;
+/** A metadata pointer extension metadata address constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION_METADATA_ADDRESS = 2032;
+/** A close authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_CLOSE_AUTHORITY_EXTENSION = 2033;
+/** A close authority extension authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_CLOSE_AUTHORITY_EXTENSION_AUTHORITY = 2034;
+/** A permanent delegate extension constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_PERMANENT_DELEGATE_EXTENSION = 2035;
+/** A permanent delegate extension delegate constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_PERMANENT_DELEGATE_EXTENSION_DELEGATE = 2036;
+/** A transfer hook extension constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION = 2037;
+/** A transfer hook extension authority constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION_AUTHORITY = 2038;
+/** A transfer hook extension transfer hook program id constraint was violated. */
+export const ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION_PROGRAM_ID = 2039;
+
+// Require errors.
+
+/** A require expression was violated. */
+export const ANCHOR_ERROR__REQUIRE_VIOLATED = 2500;
+/** A require_eq expression was violated. */
+export const ANCHOR_ERROR__REQUIRE_EQ_VIOLATED = 2501;
+/** A require_keys_eq expression was violated. */
+export const ANCHOR_ERROR__REQUIRE_KEYS_EQ_VIOLATED = 2502;
+/** A require_neq expression was violated. */
+export const ANCHOR_ERROR__REQUIRE_NEQ_VIOLATED = 2503;
+/** A require_keys_neq expression was violated. */
+export const ANCHOR_ERROR__REQUIRE_KEYS_NEQ_VIOLATED = 2504;
+/** A require_gt expression was violated. */
+export const ANCHOR_ERROR__REQUIRE_GT_VIOLATED = 2505;
+/** A require_gte expression was violated. */
+export const ANCHOR_ERROR__REQUIRE_GTE_VIOLATED = 2506;
+
+// Account errors.
+
+/** The account discriminator was already set on this account. */
+export const ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_ALREADY_SET = 3000;
+/** No 8 byte discriminator was found on the account. */
+export const ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_NOT_FOUND = 3001;
+/** 8 byte discriminator did not match what was expected. */
+export const ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_MISMATCH = 3002;
+/** Failed to deserialize the account. */
+export const ANCHOR_ERROR__ACCOUNT_DID_NOT_DESERIALIZE = 3003;
+/** Failed to serialize the account. */
+export const ANCHOR_ERROR__ACCOUNT_DID_NOT_SERIALIZE = 3004;
+/** Not enough account keys given to the instruction. */
+export const ANCHOR_ERROR__ACCOUNT_NOT_ENOUGH_KEYS = 3005;
+/** The given account is not mutable. */
+export const ANCHOR_ERROR__ACCOUNT_NOT_MUTABLE = 3006;
+/** The given account is owned by a different program than expected. */
+export const ANCHOR_ERROR__ACCOUNT_OWNED_BY_WRONG_PROGRAM = 3007;
+/** Program ID was not as expected. */
+export const ANCHOR_ERROR__INVALID_PROGRAM_ID = 3008;
+/** Program account is not executable. */
+export const ANCHOR_ERROR__INVALID_PROGRAM_EXECUTABLE = 3009;
+/** The given account did not sign. */
+export const ANCHOR_ERROR__ACCOUNT_NOT_SIGNER = 3010;
+/** The given account is not owned by the system program. */
+export const ANCHOR_ERROR__ACCOUNT_NOT_SYSTEM_OWNED = 3011;
+/** The program expected this account to be already initialized. */
+export const ANCHOR_ERROR__ACCOUNT_NOT_INITIALIZED = 3012;
+/** The given account is not a program data account. */
+export const ANCHOR_ERROR__ACCOUNT_NOT_PROGRAM_DATA = 3013;
+/** The given account is not the associated token account. */
+export const ANCHOR_ERROR__ACCOUNT_NOT_ASSOCIATED_TOKEN_ACCOUNT = 3014;
+/** The given public key does not match the required sysvar. */
+export const ANCHOR_ERROR__ACCOUNT_SYSVAR_MISMATCH = 3015;
+/** The account reallocation exceeds the MAX_PERMITTED_DATA_INCREASE limit. */
+export const ANCHOR_ERROR__ACCOUNT_REALLOC_EXCEEDS_LIMIT = 3016;
+/** The account was duplicated for more than one reallocation. */
+export const ANCHOR_ERROR__ACCOUNT_DUPLICATE_REALLOCS = 3017;
+
+// Miscellaneous errors.
+
+/** The declared program id does not match the actual program id. */
+export const ANCHOR_ERROR__DECLARED_PROGRAM_ID_MISMATCH = 4100;
+/** You cannot/should not initialize the payer account as a program account. */
+export const ANCHOR_ERROR__TRYING_TO_INIT_PAYER_AS_PROGRAM_ACCOUNT = 4101;
+/** The program could not perform the numeric conversion, out of range integral type conversion attempted. */
+export const ANCHOR_ERROR__INVALID_NUMERIC_CONVERSION = 4102;
+
+// Deprecated errors.
+
+/** The API being used is deprecated and should no longer be used. */
+export const ANCHOR_ERROR__DEPRECATED = 5000;
+
+/** All valid Anchor error codes. */
+export type AnchorErrorCode =
+  | typeof ANCHOR_ERROR__INSTRUCTION_MISSING
+  | typeof ANCHOR_ERROR__INSTRUCTION_FALLBACK_NOT_FOUND
+  | typeof ANCHOR_ERROR__INSTRUCTION_DID_NOT_DESERIALIZE
+  | typeof ANCHOR_ERROR__INSTRUCTION_DID_NOT_SERIALIZE
+  | typeof ANCHOR_ERROR__IDL_INSTRUCTION_STUB
+  | typeof ANCHOR_ERROR__IDL_INSTRUCTION_INVALID_PROGRAM
+  | typeof ANCHOR_ERROR__IDL_ACCOUNT_NOT_EMPTY
+  | typeof ANCHOR_ERROR__EVENT_INSTRUCTION_STUB
+  | typeof ANCHOR_ERROR__CONSTRAINT_MUT
+  | typeof ANCHOR_ERROR__CONSTRAINT_HAS_ONE
+  | typeof ANCHOR_ERROR__CONSTRAINT_SIGNER
+  | typeof ANCHOR_ERROR__CONSTRAINT_RAW
+  | typeof ANCHOR_ERROR__CONSTRAINT_OWNER
+  | typeof ANCHOR_ERROR__CONSTRAINT_RENT_EXEMPT
+  | typeof ANCHOR_ERROR__CONSTRAINT_SEEDS
+  | typeof ANCHOR_ERROR__CONSTRAINT_EXECUTABLE
+  | typeof ANCHOR_ERROR__CONSTRAINT_STATE
+  | typeof ANCHOR_ERROR__CONSTRAINT_ASSOCIATED
+  | typeof ANCHOR_ERROR__CONSTRAINT_ASSOCIATED_INIT
+  | typeof ANCHOR_ERROR__CONSTRAINT_CLOSE
+  | typeof ANCHOR_ERROR__CONSTRAINT_ADDRESS
+  | typeof ANCHOR_ERROR__CONSTRAINT_ZERO
+  | typeof ANCHOR_ERROR__CONSTRAINT_TOKEN_MINT
+  | typeof ANCHOR_ERROR__CONSTRAINT_TOKEN_OWNER
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_MINT_AUTHORITY
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_FREEZE_AUTHORITY
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_DECIMALS
+  | typeof ANCHOR_ERROR__CONSTRAINT_SPACE
+  | typeof ANCHOR_ERROR__CONSTRAINT_ACCOUNT_IS_NONE
+  | typeof ANCHOR_ERROR__CONSTRAINT_TOKEN_TOKEN_PROGRAM
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_TOKEN_PROGRAM
+  | typeof ANCHOR_ERROR__CONSTRAINT_ASSOCIATED_TOKEN_TOKEN_PROGRAM
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION_AUTHORITY
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION_GROUP_ADDRESS
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION_AUTHORITY
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION_MEMBER_ADDRESS
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION_AUTHORITY
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION_METADATA_ADDRESS
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_CLOSE_AUTHORITY_EXTENSION
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_CLOSE_AUTHORITY_EXTENSION_AUTHORITY
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_PERMANENT_DELEGATE_EXTENSION
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_PERMANENT_DELEGATE_EXTENSION_DELEGATE
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION_AUTHORITY
+  | typeof ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION_PROGRAM_ID
+  | typeof ANCHOR_ERROR__REQUIRE_VIOLATED
+  | typeof ANCHOR_ERROR__REQUIRE_EQ_VIOLATED
+  | typeof ANCHOR_ERROR__REQUIRE_KEYS_EQ_VIOLATED
+  | typeof ANCHOR_ERROR__REQUIRE_NEQ_VIOLATED
+  | typeof ANCHOR_ERROR__REQUIRE_KEYS_NEQ_VIOLATED
+  | typeof ANCHOR_ERROR__REQUIRE_GT_VIOLATED
+  | typeof ANCHOR_ERROR__REQUIRE_GTE_VIOLATED
+  | typeof ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_ALREADY_SET
+  | typeof ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_NOT_FOUND
+  | typeof ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_MISMATCH
+  | typeof ANCHOR_ERROR__ACCOUNT_DID_NOT_DESERIALIZE
+  | typeof ANCHOR_ERROR__ACCOUNT_DID_NOT_SERIALIZE
+  | typeof ANCHOR_ERROR__ACCOUNT_NOT_ENOUGH_KEYS
+  | typeof ANCHOR_ERROR__ACCOUNT_NOT_MUTABLE
+  | typeof ANCHOR_ERROR__ACCOUNT_OWNED_BY_WRONG_PROGRAM
+  | typeof ANCHOR_ERROR__INVALID_PROGRAM_ID
+  | typeof ANCHOR_ERROR__INVALID_PROGRAM_EXECUTABLE
+  | typeof ANCHOR_ERROR__ACCOUNT_NOT_SIGNER
+  | typeof ANCHOR_ERROR__ACCOUNT_NOT_SYSTEM_OWNED
+  | typeof ANCHOR_ERROR__ACCOUNT_NOT_INITIALIZED
+  | typeof ANCHOR_ERROR__ACCOUNT_NOT_PROGRAM_DATA
+  | typeof ANCHOR_ERROR__ACCOUNT_NOT_ASSOCIATED_TOKEN_ACCOUNT
+  | typeof ANCHOR_ERROR__ACCOUNT_SYSVAR_MISMATCH
+  | typeof ANCHOR_ERROR__ACCOUNT_REALLOC_EXCEEDS_LIMIT
+  | typeof ANCHOR_ERROR__ACCOUNT_DUPLICATE_REALLOCS
+  | typeof ANCHOR_ERROR__DECLARED_PROGRAM_ID_MISMATCH
+  | typeof ANCHOR_ERROR__TRYING_TO_INIT_PAYER_AS_PROGRAM_ACCOUNT
+  | typeof ANCHOR_ERROR__INVALID_NUMERIC_CONVERSION
+  | typeof ANCHOR_ERROR__DEPRECATED;
diff --git a/ts/packages/anchor-errors/tsconfig.json b/ts/packages/anchor-errors/tsconfig.json
new file mode 100644
index 0000000000..b6cde080f6
--- /dev/null
+++ b/ts/packages/anchor-errors/tsconfig.json
@@ -0,0 +1,18 @@
+{
+  "compilerOptions": {
+    "module": "commonjs",
+    "target": "es2019",
+    "outDir": "./dist",
+    "rootDir": "./src",
+    "composite": true,
+    "declaration": true,
+    "declarationMap": true,
+    "sourceMap": true,
+    "strict": true,
+    "esModuleInterop": true,
+    "skipLibCheck": true,
+    "forceConsistentCasingInFileNames": true,
+    "typeRoots": ["./types"]
+  },
+  "include": ["src/**/*"]
+}
diff --git a/ts/packages/anchor/package.json b/ts/packages/anchor/package.json
index 5d345a2d86..28cdc19ab2 100644
--- a/ts/packages/anchor/package.json
+++ b/ts/packages/anchor/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@coral-xyz/anchor",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "description": "Anchor client",
   "module": "./dist/esm/index.js",
   "main": "./dist/cjs/index.js",
@@ -23,7 +23,7 @@
   },
   "scripts": {
     "build": "rimraf dist/ && yarn build:node && yarn build:browser",
-    "build:node": "cd ../borsh && yarn build && cd ../anchor && tsc && tsc -p tsconfig.cjs.json",
+    "build:node": "cd ../borsh && yarn build && cd ../anchor-errors && yarn build && cd ../anchor && tsc && tsc -p tsconfig.cjs.json",
     "build:browser": "rollup --config",
     "lint:fix": "prettier src/** tests/** -w",
     "lint": "prettier src/** tests/** --check",
@@ -33,7 +33,8 @@
     "test": "jest tests --detectOpenHandles"
   },
   "dependencies": {
-    "@coral-xyz/borsh": "^0.29.0",
+    "@coral-xyz/anchor-errors": "^0.30.1",
+    "@coral-xyz/borsh": "^0.30.1",
     "@noble/hashes": "^1.3.1",
     "@solana/web3.js": "^1.68.0",
     "bn.js": "^5.1.2",
diff --git a/ts/packages/anchor/src/coder/borsh/accounts.ts b/ts/packages/anchor/src/coder/borsh/accounts.ts
index 742c5bc826..6451962c8c 100644
--- a/ts/packages/anchor/src/coder/borsh/accounts.ts
+++ b/ts/packages/anchor/src/coder/borsh/accounts.ts
@@ -1,12 +1,9 @@
 import bs58 from "bs58";
 import { Buffer } from "buffer";
 import { Layout } from "buffer-layout";
-import camelcase from "camelcase";
-import { Idl, IdlTypeDef } from "../../idl.js";
+import { Idl, IdlDiscriminator } from "../../idl.js";
 import { IdlCoder } from "./idl.js";
 import { AccountsCoder } from "../index.js";
-import { accountSize } from "../common.js";
-import { DISCRIMINATOR_SIZE, discriminator } from "./discriminator.js";
 
 /**
  * Encodes and decodes account objects.
@@ -17,24 +14,37 @@ export class BorshAccountsCoder
   /**
    * Maps account type identifier to a layout.
    */
-  private accountLayouts: Map;
+  private accountLayouts: Map<
+    A,
+    { discriminator: IdlDiscriminator; layout: Layout }
+  >;
 
-  /**
-   * IDL whose acconts will be coded.
-   */
-  private idl: Idl;
-
-  public constructor(idl: Idl) {
-    if (idl.accounts === undefined) {
+  public constructor(private idl: Idl) {
+    if (!idl.accounts) {
       this.accountLayouts = new Map();
       return;
     }
-    const layouts: [A, Layout][] = idl.accounts.map((acc) => {
-      return [acc.name as A, IdlCoder.typeDefLayout(acc, idl.types)];
+
+    const types = idl.types;
+    if (!types) {
+      throw new Error("Accounts require `idl.types`");
+    }
+
+    const layouts = idl.accounts.map((acc) => {
+      const typeDef = types.find((ty) => ty.name === acc.name);
+      if (!typeDef) {
+        throw new Error(`Account not found: ${acc.name}`);
+      }
+      return [
+        acc.name as A,
+        {
+          discriminator: acc.discriminator,
+          layout: IdlCoder.typeDefLayout({ typeDef, types }),
+        },
+      ] as const;
     });
 
     this.accountLayouts = new Map(layouts);
-    this.idl = idl;
   }
 
   public async encode(accountName: A, account: T): Promise {
@@ -43,45 +53,44 @@ export class BorshAccountsCoder
     if (!layout) {
       throw new Error(`Unknown account: ${accountName}`);
     }
-    const len = layout.encode(account, buffer);
-    let accountData = buffer.slice(0, len);
-    let discriminator = BorshAccountsCoder.accountDiscriminator(accountName);
+    const len = layout.layout.encode(account, buffer);
+    const accountData = buffer.slice(0, len);
+    const discriminator = this.accountDiscriminator(accountName);
     return Buffer.concat([discriminator, accountData]);
   }
 
   public decode(accountName: A, data: Buffer): T {
     // Assert the account discriminator is correct.
-    const discriminator = BorshAccountsCoder.accountDiscriminator(accountName);
-    if (discriminator.compare(data.slice(0, 8))) {
+    const discriminator = this.accountDiscriminator(accountName);
+    if (discriminator.compare(data.slice(0, discriminator.length))) {
       throw new Error("Invalid account discriminator");
     }
     return this.decodeUnchecked(accountName, data);
   }
 
   public decodeAny(data: Buffer): T {
-    const accountDescriminator = data.slice(0, 8);
-    const accountName = Array.from(this.accountLayouts.keys()).find((key) =>
-      BorshAccountsCoder.accountDiscriminator(key).equals(accountDescriminator)
-    );
-    if (!accountName) {
-      throw new Error("Account descriminator not found");
+    for (const [name, layout] of this.accountLayouts) {
+      const givenDisc = data.subarray(0, layout.discriminator.length);
+      const matches = givenDisc.equals(Buffer.from(layout.discriminator));
+      if (matches) return this.decodeUnchecked(name, data);
     }
 
-    return this.decodeUnchecked(accountName as any, data);
+    throw new Error("Account not found");
   }
 
-  public decodeUnchecked(accountName: A, ix: Buffer): T {
+  public decodeUnchecked(accountName: A, acc: Buffer): T {
     // Chop off the discriminator before decoding.
-    const data = ix.subarray(DISCRIMINATOR_SIZE);
+    const discriminator = this.accountDiscriminator(accountName);
+    const data = acc.subarray(discriminator.length);
     const layout = this.accountLayouts.get(accountName);
     if (!layout) {
       throw new Error(`Unknown account: ${accountName}`);
     }
-    return layout.decode(data);
+    return layout.layout.decode(data);
   }
 
   public memcmp(accountName: A, appendData?: Buffer): any {
-    const discriminator = BorshAccountsCoder.accountDiscriminator(accountName);
+    const discriminator = this.accountDiscriminator(accountName);
     return {
       offset: 0,
       bytes: bs58.encode(
@@ -90,8 +99,11 @@ export class BorshAccountsCoder
     };
   }
 
-  public size(idlAccount: IdlTypeDef): number {
-    return DISCRIMINATOR_SIZE + (accountSize(this.idl, idlAccount) ?? 0);
+  public size(accountName: A): number {
+    return (
+      this.accountDiscriminator(accountName).length +
+      IdlCoder.typeSize({ defined: { name: accountName } }, this.idl)
+    );
   }
 
   /**
@@ -99,11 +111,12 @@ export class BorshAccountsCoder
    *
    * @param name The name of the account to calculate the discriminator.
    */
-  public static accountDiscriminator(name: string): Buffer {
-    const discriminatorPreimage = `account:${camelcase(name, {
-      pascalCase: true,
-      preserveConsecutiveUppercase: true,
-    })}`;
-    return discriminator(discriminatorPreimage);
+  public accountDiscriminator(name: string): Buffer {
+    const account = this.idl.accounts?.find((acc) => acc.name === name);
+    if (!account) {
+      throw new Error(`Account not found: ${name}`);
+    }
+
+    return Buffer.from(account.discriminator);
   }
 }
diff --git a/ts/packages/anchor/src/coder/borsh/discriminator.ts b/ts/packages/anchor/src/coder/borsh/discriminator.ts
deleted file mode 100644
index ec0d24bce6..0000000000
--- a/ts/packages/anchor/src/coder/borsh/discriminator.ts
+++ /dev/null
@@ -1,10 +0,0 @@
-import { sha256 } from "@noble/hashes/sha256";
-
-/**
- * Number of bytes in anchor discriminators
- */
-export const DISCRIMINATOR_SIZE = 8;
-
-export function discriminator(preimage: string): Buffer {
-  return Buffer.from(sha256(preimage).slice(0, DISCRIMINATOR_SIZE));
-}
diff --git a/ts/packages/anchor/src/coder/borsh/event.ts b/ts/packages/anchor/src/coder/borsh/event.ts
index 09e9c72e6f..b3686213fe 100644
--- a/ts/packages/anchor/src/coder/borsh/event.ts
+++ b/ts/packages/anchor/src/coder/borsh/event.ts
@@ -1,55 +1,50 @@
 import { Buffer } from "buffer";
 import { Layout } from "buffer-layout";
 import * as base64 from "../../utils/bytes/base64.js";
-import { Idl, IdlEvent, IdlTypeDef } from "../../idl.js";
-import { Event, EventData } from "../../program/event.js";
+import { Idl, IdlDiscriminator } from "../../idl.js";
 import { IdlCoder } from "./idl.js";
 import { EventCoder } from "../index.js";
-import { discriminator } from "./discriminator.js";
 
 export class BorshEventCoder implements EventCoder {
   /**
    * Maps account type identifier to a layout.
    */
-  private layouts: Map;
-
-  /**
-   * Maps base64 encoded event discriminator to event name.
-   */
-  private discriminators: Map;
+  private layouts: Map<
+    string,
+    { discriminator: IdlDiscriminator; layout: Layout }
+  >;
 
   public constructor(idl: Idl) {
-    if (idl.events === undefined) {
+    if (!idl.events) {
       this.layouts = new Map();
       return;
     }
-    const layouts: [string, Layout][] = idl.events.map((event) => {
-      let eventTypeDef: IdlTypeDef = {
-        name: event.name,
-        type: {
-          kind: "struct",
-          fields: event.fields.map((f) => {
-            return { name: f.name, type: f.type };
-          }),
+
+    const types = idl.types;
+    if (!types) {
+      throw new Error("Events require `idl.types`");
+    }
+
+    const layouts = idl.events.map((ev) => {
+      const typeDef = types.find((ty) => ty.name === ev.name);
+      if (!typeDef) {
+        throw new Error(`Event not found: ${ev.name}`);
+      }
+      return [
+        ev.name,
+        {
+          discriminator: ev.discriminator,
+          layout: IdlCoder.typeDefLayout({ typeDef, types }),
         },
-      };
-      return [event.name, IdlCoder.typeDefLayout(eventTypeDef, idl.types)];
+      ] as const;
     });
     this.layouts = new Map(layouts);
-
-    this.discriminators = new Map(
-      idl.events === undefined
-        ? []
-        : idl.events.map((e) => [
-            base64.encode(eventDiscriminator(e.name)),
-            e.name,
-          ])
-    );
   }
 
-  public decode>(
-    log: string
-  ): Event | null {
+  public decode(log: string): {
+    name: string;
+    data: any;
+  } | null {
     let logArr: Buffer;
     // This will throw if log length is not a multiple of 4.
     try {
@@ -57,26 +52,18 @@ export class BorshEventCoder implements EventCoder {
     } catch (e) {
       return null;
     }
-    const disc = base64.encode(logArr.slice(0, 8));
 
-    // Only deserialize if the discriminator implies a proper event.
-    const eventName = this.discriminators.get(disc);
-    if (eventName === undefined) {
-      return null;
+    for (const [name, layout] of this.layouts) {
+      const givenDisc = logArr.subarray(0, layout.discriminator.length);
+      const matches = givenDisc.equals(Buffer.from(layout.discriminator));
+      if (matches) {
+        return {
+          name,
+          data: layout.layout.decode(logArr.subarray(givenDisc.length)),
+        };
+      }
     }
 
-    const layout = this.layouts.get(eventName);
-    if (!layout) {
-      throw new Error(`Unknown event: ${eventName}`);
-    }
-    const data = layout.decode(logArr.slice(8)) as EventData<
-      E["fields"][number],
-      T
-    >;
-    return { data, name: eventName };
+    return null;
   }
 }
-
-export function eventDiscriminator(name: string): Buffer {
-  return discriminator(`event:${name}`);
-}
diff --git a/ts/packages/anchor/src/coder/borsh/idl.ts b/ts/packages/anchor/src/coder/borsh/idl.ts
index 08d40d9bbe..0ef29cca4b 100644
--- a/ts/packages/anchor/src/coder/borsh/idl.ts
+++ b/ts/packages/anchor/src/coder/borsh/idl.ts
@@ -1,16 +1,25 @@
-import camelCase from "camelcase";
 import { Layout } from "buffer-layout";
 import * as borsh from "@coral-xyz/borsh";
-import { IdlField, IdlTypeDef, IdlEnumVariant, IdlType } from "../../idl.js";
+import {
+  IdlField,
+  IdlTypeDef,
+  IdlType,
+  IdlGenericArg,
+  Idl,
+  handleDefinedFields,
+  IdlArrayLen,
+} from "../../idl.js";
 import { IdlError } from "../../error.js";
 
+type PartialField = { name?: string } & Pick;
+
 export class IdlCoder {
   public static fieldLayout(
-    field: { name?: string } & Pick,
-    types?: IdlTypeDef[]
+    field: PartialField,
+    types: IdlTypeDef[] = [],
+    genericArgs?: IdlGenericArg[] | null
   ): Layout {
-    const fieldName =
-      field.name !== undefined ? camelCase(field.name) : undefined;
+    const fieldName = field.name;
     switch (field.type) {
       case "bool": {
         return borsh.bool(fieldName);
@@ -63,95 +72,157 @@ export class IdlCoder {
       case "string": {
         return borsh.str(fieldName);
       }
-      case "publicKey": {
+      case "pubkey": {
         return borsh.publicKey(fieldName);
       }
       default: {
-        if ("vec" in field.type) {
-          return borsh.vec(
+        if ("option" in field.type) {
+          return borsh.option(
             IdlCoder.fieldLayout(
-              {
-                name: undefined,
-                type: field.type.vec,
-              },
-              types
+              { type: field.type.option },
+              types,
+              genericArgs
             ),
             fieldName
           );
-        } else if ("option" in field.type) {
-          return borsh.option(
-            IdlCoder.fieldLayout(
-              {
-                name: undefined,
-                type: field.type.option,
-              },
-              types
-            ),
+        }
+        if ("vec" in field.type) {
+          return borsh.vec(
+            IdlCoder.fieldLayout({ type: field.type.vec }, types, genericArgs),
             fieldName
           );
-        } else if ("defined" in field.type) {
-          // User defined type.
+        }
+        if ("array" in field.type) {
+          let [type, len] = field.type.array;
+          len = IdlCoder.resolveArrayLen(len, genericArgs);
+
+          return borsh.array(
+            IdlCoder.fieldLayout({ type }, types, genericArgs),
+            len,
+            fieldName
+          );
+        }
+        if ("defined" in field.type) {
           if (!types) {
             throw new IdlError("User defined types not provided");
           }
 
-          const defined = field.type.defined;
-          const filtered = types.filter((t) => t.name === defined);
-          if (filtered.length !== 1) {
-            throw new IdlError(`Type not found: ${JSON.stringify(field)}`);
+          const definedName = field.type.defined.name;
+          const typeDef = types.find((t) => t.name === definedName);
+          if (!typeDef) {
+            throw new IdlError(`Type not found: ${field.name}`);
           }
-          return IdlCoder.typeDefLayout(filtered[0], types, fieldName);
-        } else if ("array" in field.type) {
-          let arrayTy = field.type.array[0];
-          let arrayLen = field.type.array[1];
-          let innerLayout = IdlCoder.fieldLayout(
-            {
-              name: undefined,
-              type: arrayTy,
-            },
+
+          return IdlCoder.typeDefLayout({
+            typeDef,
+            types,
+            genericArgs: genericArgs ?? field.type.defined.generics,
+            name: fieldName,
+          });
+        }
+        if ("generic" in field.type) {
+          const genericArg = genericArgs?.at(0);
+          if (genericArg?.kind !== "type") {
+            throw new IdlError(`Invalid generic field: ${field.name}`);
+          }
+
+          return IdlCoder.fieldLayout(
+            { ...field, type: genericArg.type },
             types
           );
-          return borsh.array(innerLayout, arrayLen, fieldName);
-        } else {
-          throw new Error(`Not yet implemented: ${field}`);
         }
+
+        throw new IdlError(
+          `Not yet implemented: ${JSON.stringify(field.type)}`
+        );
       }
     }
   }
 
-  public static typeDefLayout(
-    typeDef: IdlTypeDef,
-    types: IdlTypeDef[] = [],
-    name?: string
-  ): Layout {
+  /**
+   * Get the type layout of the given defined type(struct or enum).
+   */
+  public static typeDefLayout({
+    typeDef,
+    types,
+    name,
+    genericArgs,
+  }: {
+    typeDef: IdlTypeDef;
+    types: IdlTypeDef[];
+    genericArgs?: IdlGenericArg[] | null;
+    name?: string;
+  }): Layout {
     switch (typeDef.type.kind) {
       case "struct": {
-        const fieldLayouts = typeDef.type.fields.map((field) => {
-          return IdlCoder.fieldLayout(field, types);
-        });
+        const fieldLayouts = handleDefinedFields(
+          typeDef.type.fields,
+          () => [],
+          (fields) =>
+            fields.map((f) => {
+              const genArgs = genericArgs
+                ? IdlCoder.resolveGenericArgs({
+                    type: f.type,
+                    typeDef,
+                    genericArgs,
+                  })
+                : genericArgs;
+              return IdlCoder.fieldLayout(f, types, genArgs);
+            }),
+          (fields) =>
+            fields.map((f, i) => {
+              const genArgs = genericArgs
+                ? IdlCoder.resolveGenericArgs({
+                    type: f,
+                    typeDef,
+                    genericArgs,
+                  })
+                : genericArgs;
+              return IdlCoder.fieldLayout(
+                { name: i.toString(), type: f },
+                types,
+                genArgs
+              );
+            })
+        );
+
         return borsh.struct(fieldLayouts, name);
       }
 
       case "enum": {
-        let variants = typeDef.type.variants.map((variant: IdlEnumVariant) => {
-          const name = camelCase(variant.name);
-          if (!variant.fields) {
-            return borsh.struct([], name);
-          }
-
-          const fieldLayouts = variant.fields.map(
-            (f: IdlField | IdlType, i: number) => {
-              if ((f as IdlField)?.name) {
-                return IdlCoder.fieldLayout(f as IdlField, types);
-              }
-
-              return IdlCoder.fieldLayout(
-                { type: f as IdlType, name: i.toString() },
-                types
-              );
-            }
+        const variants = typeDef.type.variants.map((variant) => {
+          const fieldLayouts = handleDefinedFields(
+            variant.fields,
+            () => [],
+            (fields) =>
+              fields.map((f) => {
+                const genArgs = genericArgs
+                  ? IdlCoder.resolveGenericArgs({
+                      type: f.type,
+                      typeDef,
+                      genericArgs,
+                    })
+                  : genericArgs;
+                return IdlCoder.fieldLayout(f, types, genArgs);
+              }),
+            (fields) =>
+              fields.map((f, i) => {
+                const genArgs = genericArgs
+                  ? IdlCoder.resolveGenericArgs({
+                      type: f,
+                      typeDef,
+                      genericArgs,
+                    })
+                  : genericArgs;
+                return IdlCoder.fieldLayout(
+                  { name: i.toString(), type: f },
+                  types,
+                  genArgs
+                );
+              })
           );
-          return borsh.struct(fieldLayouts, name);
+
+          return borsh.struct(fieldLayouts, variant.name);
         });
 
         if (name !== undefined) {
@@ -163,12 +234,289 @@ export class IdlCoder {
         return borsh.rustEnum(variants, name);
       }
 
-      case "alias": {
-        return IdlCoder.fieldLayout(
-          { type: typeDef.type.value, name: typeDef.name },
-          types
-        );
+      case "type": {
+        return IdlCoder.fieldLayout({ type: typeDef.type.alias, name }, types);
       }
     }
   }
+
+  /**
+   * Get the type of the size in bytes. Returns `1` for variable length types.
+   */
+  public static typeSize(
+    ty: IdlType,
+    idl: Idl,
+    genericArgs?: IdlGenericArg[] | null
+  ): number {
+    switch (ty) {
+      case "bool":
+        return 1;
+      case "u8":
+        return 1;
+      case "i8":
+        return 1;
+      case "i16":
+        return 2;
+      case "u16":
+        return 2;
+      case "u32":
+        return 4;
+      case "i32":
+        return 4;
+      case "f32":
+        return 4;
+      case "u64":
+        return 8;
+      case "i64":
+        return 8;
+      case "f64":
+        return 8;
+      case "u128":
+        return 16;
+      case "i128":
+        return 16;
+      case "u256":
+        return 32;
+      case "i256":
+        return 32;
+      case "bytes":
+        return 1;
+      case "string":
+        return 1;
+      case "pubkey":
+        return 32;
+      default:
+        if ("option" in ty) {
+          return 1 + IdlCoder.typeSize(ty.option, idl, genericArgs);
+        }
+        if ("coption" in ty) {
+          return 4 + IdlCoder.typeSize(ty.coption, idl, genericArgs);
+        }
+        if ("vec" in ty) {
+          return 1;
+        }
+        if ("array" in ty) {
+          let [type, len] = ty.array;
+          len = IdlCoder.resolveArrayLen(len, genericArgs);
+          return IdlCoder.typeSize(type, idl, genericArgs) * len;
+        }
+        if ("defined" in ty) {
+          const typeDef = idl.types?.find((t) => t.name === ty.defined.name);
+          if (!typeDef) {
+            throw new IdlError(`Type not found: ${JSON.stringify(ty)}`);
+          }
+
+          const typeSize = (type: IdlType) => {
+            const genArgs = genericArgs ?? ty.defined.generics;
+            const args = genArgs
+              ? IdlCoder.resolveGenericArgs({
+                  type,
+                  typeDef,
+                  genericArgs: genArgs,
+                })
+              : genArgs;
+
+            return IdlCoder.typeSize(type, idl, args);
+          };
+
+          switch (typeDef.type.kind) {
+            case "struct": {
+              return handleDefinedFields(
+                typeDef.type.fields,
+                () => [0],
+                (fields) => fields.map((f) => typeSize(f.type)),
+                (fields) => fields.map((f) => typeSize(f))
+              ).reduce((acc, size) => acc + size, 0);
+            }
+
+            case "enum": {
+              const variantSizes = typeDef.type.variants.map((variant) => {
+                return handleDefinedFields(
+                  variant.fields,
+                  () => [0],
+                  (fields) => fields.map((f) => typeSize(f.type)),
+                  (fields) => fields.map((f) => typeSize(f))
+                ).reduce((acc, size) => acc + size, 0);
+              });
+
+              return Math.max(...variantSizes) + 1;
+            }
+
+            case "type": {
+              return IdlCoder.typeSize(typeDef.type.alias, idl, genericArgs);
+            }
+          }
+        }
+        if ("generic" in ty) {
+          const genericArg = genericArgs?.at(0);
+          if (genericArg?.kind !== "type") {
+            throw new IdlError(`Invalid generic: ${ty.generic}`);
+          }
+
+          return IdlCoder.typeSize(genericArg.type, idl, genericArgs);
+        }
+
+        throw new Error(`Invalid type ${JSON.stringify(ty)}`);
+    }
+  }
+
+  /**
+   * Resolve the generic array length or return the constant-sized array length.
+   */
+  private static resolveArrayLen(
+    len: IdlArrayLen,
+    genericArgs?: IdlGenericArg[] | null
+  ): number {
+    if (typeof len === "number") return len;
+
+    if (genericArgs) {
+      const genericLen = genericArgs.find((g) => g.kind === "const");
+      if (genericLen?.kind === "const") {
+        len = +genericLen.value;
+      }
+    }
+
+    if (typeof len !== "number") {
+      throw new IdlError("Generic array length did not resolve");
+    }
+
+    return len;
+  }
+
+  /**
+   * Recursively resolve generic arguments i.e. replace all generics with the
+   * actual type that they hold based on the initial `genericArgs` given.
+   */
+  private static resolveGenericArgs({
+    type,
+    typeDef,
+    genericArgs,
+    isDefined,
+  }: {
+    type: IdlType;
+    typeDef: IdlTypeDef;
+    genericArgs: IdlGenericArg[];
+    isDefined?: boolean;
+  }): IdlGenericArg[] | null {
+    if (typeof type !== "object") return null;
+
+    for (const index in typeDef.generics) {
+      const defGeneric = typeDef.generics[index];
+
+      if ("generic" in type && defGeneric.name === type.generic) {
+        return [genericArgs[index]];
+      }
+
+      if ("option" in type) {
+        const args = IdlCoder.resolveGenericArgs({
+          type: type.option,
+          typeDef,
+          genericArgs,
+          isDefined,
+        });
+        if (!args || !isDefined) return args;
+
+        if (args[0].kind === "type") {
+          return [
+            {
+              kind: "type",
+              type: { option: args[0].type },
+            },
+          ];
+        }
+      }
+
+      if ("vec" in type) {
+        const args = IdlCoder.resolveGenericArgs({
+          type: type.vec,
+          typeDef,
+          genericArgs,
+          isDefined,
+        });
+        if (!args || !isDefined) return args;
+
+        if (args[0].kind === "type") {
+          return [
+            {
+              kind: "type",
+              type: { vec: args[0].type },
+            },
+          ];
+        }
+      }
+
+      if ("array" in type) {
+        const [elTy, len] = type.array;
+        const isGenericLen = typeof len === "object";
+
+        const args = IdlCoder.resolveGenericArgs({
+          type: elTy,
+          typeDef,
+          genericArgs,
+          isDefined,
+        });
+        if (args) {
+          // Has generic type, also check for generic length
+          for (const i in typeDef.generics.slice(+index)) {
+            const curIndex = +index + +i;
+            if (
+              isGenericLen &&
+              typeDef.generics[curIndex].name === len.generic
+            ) {
+              args.push(genericArgs[curIndex]);
+            }
+          }
+
+          if (!isDefined) return args;
+
+          if (args[0].kind === "type" && args[1].kind === "const") {
+            return [
+              {
+                kind: "type",
+                type: { array: [args[0].type, +args[1].value] },
+              },
+            ];
+          }
+        }
+
+        // Only generic len
+        if (isGenericLen && defGeneric.name === len.generic) {
+          const arg = genericArgs[index];
+          if (!isDefined) return [arg];
+
+          return [
+            {
+              kind: "type",
+              type: { array: [elTy, +arg.value] },
+            },
+          ];
+        }
+
+        // Non-generic
+        return null;
+      }
+
+      if ("defined" in type) {
+        if (!type.defined.generics) return null;
+
+        return type.defined.generics
+          .flatMap((g) => {
+            switch (g.kind) {
+              case "type":
+                return IdlCoder.resolveGenericArgs({
+                  type: g.type,
+                  typeDef,
+                  genericArgs,
+                  isDefined: true,
+                });
+              case "const":
+                return [g];
+            }
+          })
+          .filter((g) => g !== null) as IdlGenericArg[];
+      }
+    }
+
+    return null;
+  }
 }
diff --git a/ts/packages/anchor/src/coder/borsh/index.ts b/ts/packages/anchor/src/coder/borsh/index.ts
index daf6cb737d..d64a652873 100644
--- a/ts/packages/anchor/src/coder/borsh/index.ts
+++ b/ts/packages/anchor/src/coder/borsh/index.ts
@@ -7,8 +7,7 @@ import { Coder } from "../index.js";
 
 export { BorshInstructionCoder } from "./instruction.js";
 export { BorshAccountsCoder } from "./accounts.js";
-export { DISCRIMINATOR_SIZE } from "./discriminator.js";
-export { BorshEventCoder, eventDiscriminator } from "./event.js";
+export { BorshEventCoder } from "./event.js";
 
 /**
  * BorshCoder is the default Coder for Anchor programs implementing the
diff --git a/ts/packages/anchor/src/coder/borsh/instruction.ts b/ts/packages/anchor/src/coder/borsh/instruction.ts
index 480a1191a5..8961eb802e 100644
--- a/ts/packages/anchor/src/coder/borsh/instruction.ts
+++ b/ts/packages/anchor/src/coder/borsh/instruction.ts
@@ -1,95 +1,59 @@
 import bs58 from "bs58";
 import { Buffer } from "buffer";
 import { Layout } from "buffer-layout";
-import camelCase from "camelcase";
-import { snakeCase } from "snake-case";
 import * as borsh from "@coral-xyz/borsh";
 import { AccountMeta, PublicKey } from "@solana/web3.js";
 import {
+  handleDefinedFields,
   Idl,
   IdlField,
   IdlType,
   IdlTypeDef,
   IdlAccount,
-  IdlAccountItem,
-  IdlTypeDefTyStruct,
+  IdlInstructionAccountItem,
   IdlTypeVec,
-  IdlTypeOption,
-  IdlTypeDefined,
-  IdlAccounts,
-  IdlEnumFieldsNamed,
+  IdlInstructionAccounts,
+  IdlDiscriminator,
 } from "../../idl.js";
 import { IdlCoder } from "./idl.js";
 import { InstructionCoder } from "../index.js";
-import { sha256 } from "@noble/hashes/sha256";
-
-/**
- * Namespace for global instruction function signatures (i.e. functions
- * that aren't namespaced by the state or any of its trait implementations).
- */
-export const SIGHASH_GLOBAL_NAMESPACE = "global";
 
 /**
  * Encodes and decodes program instructions.
  */
 export class BorshInstructionCoder implements InstructionCoder {
   // Instruction args layout. Maps namespaced method
-  private ixLayout: Map;
-
-  // Base58 encoded sighash to instruction layout.
-  private sighashLayouts: Map;
+  private ixLayouts: Map<
+    string,
+    { discriminator: IdlDiscriminator; layout: Layout }
+  >;
 
   public constructor(private idl: Idl) {
-    this.ixLayout = BorshInstructionCoder.parseIxLayout(idl);
-
-    const sighashLayouts = new Map();
-    idl.instructions.forEach((ix) => {
-      const sh = sighash(SIGHASH_GLOBAL_NAMESPACE, ix.name);
-      sighashLayouts.set(bs58.encode(sh), {
-        layout: this.ixLayout.get(ix.name),
-        name: ix.name,
-      });
+    const ixLayouts = idl.instructions.map((ix) => {
+      const name = ix.name;
+      const fieldLayouts = ix.args.map((arg) =>
+        IdlCoder.fieldLayout(arg, idl.types)
+      );
+      const layout = borsh.struct(fieldLayouts, name);
+      return [name, { discriminator: ix.discriminator, layout }] as const;
     });
-
-    this.sighashLayouts = sighashLayouts;
+    this.ixLayouts = new Map(ixLayouts);
   }
 
   /**
    * Encodes a program instruction.
    */
-  public encode(ixName: string, ix: any, discriminator?: Buffer): Buffer {
-    return this._encode(
-      ixName,
-      ix,
-      discriminator ?? sighash(SIGHASH_GLOBAL_NAMESPACE, ixName)
-    );
-  }
-
-  private _encode(ixName: string, ix: any, discriminator: Buffer): Buffer {
+  public encode(ixName: string, ix: any): Buffer {
     const buffer = Buffer.alloc(1000); // TODO: use a tighter buffer.
-    const methodName = camelCase(ixName);
-    const layout = this.ixLayout.get(methodName);
-    if (!layout) {
-      throw new Error(`Unknown method: ${methodName}`);
+    const encoder = this.ixLayouts.get(ixName);
+    if (!encoder) {
+      throw new Error(`Unknown method: ${ixName}`);
     }
-    const len = layout.encode(ix, buffer);
-    const data = buffer.slice(0, len);
-    return Buffer.concat([discriminator, data]);
-  }
 
-  private static parseIxLayout(idl: Idl): Map {
-    const ixLayouts = idl.instructions.map((ix): [string, Layout] => {
-      let fieldLayouts = ix.args.map((arg: IdlField) =>
-        IdlCoder.fieldLayout(
-          arg,
-          Array.from([...(idl.accounts ?? []), ...(idl.types ?? [])])
-        )
-      );
-      const name = camelCase(ix.name);
-      return [name, borsh.struct(fieldLayouts, name)];
-    });
+    const len = encoder.layout.encode(ix, buffer);
+    const data = buffer.slice(0, len);
 
-    return new Map(ixLayouts);
+    return Buffer.concat([Buffer.from(encoder.discriminator), data]);
   }
 
   /**
@@ -97,28 +61,24 @@ export class BorshInstructionCoder implements InstructionCoder {
    */
   public decode(
     ix: Buffer | string,
-    encoding: "hex" | "base58" = "hex",
-    ixName?: string
+    encoding: "hex" | "base58" = "hex"
   ): Instruction | null {
     if (typeof ix === "string") {
       ix = encoding === "hex" ? Buffer.from(ix, "hex") : bs58.decode(ix);
     }
-    // Use the provided method name to get the sighash, ignoring the
-    // discriminator in the instruction data.
-    // This is useful for decoding instructions that have been encoded with a
-    // different namespace, such as an SPL interface.
-    let sighashKey = bs58.encode(
-      ixName ? sighash(SIGHASH_GLOBAL_NAMESPACE, ixName) : ix.slice(0, 8)
-    );
-    let data = ix.slice(8);
-    const decoder = this.sighashLayouts.get(sighashKey);
-    if (!decoder) {
-      return null;
+
+    for (const [name, layout] of this.ixLayouts) {
+      const givenDisc = ix.subarray(0, layout.discriminator.length);
+      const matches = givenDisc.equals(Buffer.from(layout.discriminator));
+      if (matches) {
+        return {
+          name,
+          data: layout.layout.decode(ix.subarray(givenDisc.length)),
+        };
+      }
     }
-    return {
-      data: decoder.layout.decode(data),
-      name: decoder.name,
-    };
+
+    return null;
   }
 
   /**
@@ -153,8 +113,8 @@ class InstructionFormatter {
     accountMetas: AccountMeta[],
     idl: Idl
   ): InstructionDisplay | null {
-    const idlIx = idl.instructions.filter((i) => ix.name === i.name)[0];
-    if (idlIx === undefined) {
+    const idlIx = idl.instructions.find((i) => ix.name === i.name);
+    if (!idlIx) {
       console.error("Invalid instruction given");
       return null;
     }
@@ -199,21 +159,40 @@ class InstructionFormatter {
 
   private static formatIdlType(idlType: IdlType): string {
     if (typeof idlType === "string") {
-      return idlType as string;
+      return idlType;
     }
 
-    if ("vec" in idlType) {
-      return `Vec<${this.formatIdlType(idlType.vec)}>`;
-    }
     if ("option" in idlType) {
       return `Option<${this.formatIdlType(idlType.option)}>`;
     }
-    if ("defined" in idlType) {
-      return idlType.defined;
+    if ("coption" in idlType) {
+      return `COption<${this.formatIdlType(idlType.coption)}>`;
+    }
+    if ("vec" in idlType) {
+      return `Vec<${this.formatIdlType(idlType.vec)}>`;
     }
     if ("array" in idlType) {
       return `Array<${idlType.array[0]}; ${idlType.array[1]}>`;
     }
+    if ("defined" in idlType) {
+      const name = idlType.defined.name;
+      if (idlType.defined.generics) {
+        const generics = idlType.defined.generics
+          .map((g) => {
+            switch (g.kind) {
+              case "type":
+                return InstructionFormatter.formatIdlType(g.type);
+              case "const":
+                return g.value;
+            }
+          })
+          .join(", ");
+
+        return `${name}<${generics}>`;
+      }
+
+      return name;
+    }
 
     throw new Error(`Unknown IDL type: ${idlType}`);
   }
@@ -226,11 +205,11 @@ class InstructionFormatter {
     if (typeof idlField.type === "string") {
       return data.toString();
     }
-    if (idlField.type.hasOwnProperty("vec")) {
+    if ("vec" in idlField.type) {
       return (
         "[" +
         (>data)
-          .map((d: IdlField) =>
+          .map((d) =>
             this.formatIdlData(
               { name: "", type: (idlField.type).vec },
               d,
@@ -241,32 +220,27 @@ class InstructionFormatter {
         "]"
       );
     }
-    if (idlField.type.hasOwnProperty("option")) {
+    if ("option" in idlField.type) {
       return data === null
         ? "null"
         : this.formatIdlData(
-            { name: "", type: (idlField.type).option },
+            { name: "", type: idlField.type.option },
             data,
             types
           );
     }
-    if (idlField.type.hasOwnProperty("defined")) {
-      if (types === undefined) {
+    if ("defined" in idlField.type) {
+      if (!types) {
         throw new Error("User defined types not provided");
       }
-      const filtered = types.filter(
-        (t) => t.name === (idlField.type).defined
-      );
-      if (filtered.length !== 1) {
-        throw new Error(
-          `Type not found: ${(idlField.type).defined}`
-        );
+
+      const definedName = idlField.type.defined.name;
+      const typeDef = types.find((t) => t.name === definedName);
+      if (!typeDef) {
+        throw new Error(`Type not found: ${definedName}`);
       }
-      return InstructionFormatter.formatIdlDataDefined(
-        filtered[0],
-        data,
-        types
-      );
+
+      return InstructionFormatter.formatIdlDataDefined(typeDef, data, types);
     }
 
     return "unknown";
@@ -279,76 +253,106 @@ class InstructionFormatter {
   ): string {
     switch (typeDef.type.kind) {
       case "struct": {
-        const struct: IdlTypeDefTyStruct = typeDef.type;
-        const fields = Object.keys(data)
-          .map((k) => {
-            const field = struct.fields.find((f) => f.name === k);
-            if (!field) {
-              throw new Error("Unable to find type");
+        return (
+          "{ " +
+          handleDefinedFields(
+            typeDef.type.fields,
+            () => "",
+            (fields) => {
+              return Object.entries(data)
+                .map(([key, val]) => {
+                  const field = fields.find((f) => f.name === key);
+                  if (!field) {
+                    throw new Error(`Field not found: ${key}`);
+                  }
+                  return (
+                    key +
+                    ": " +
+                    InstructionFormatter.formatIdlData(field, val, types)
+                  );
+                })
+                .join(", ");
+            },
+            (fields) => {
+              return Object.entries(data)
+                .map(([key, val]) => {
+                  return (
+                    key +
+                    ": " +
+                    InstructionFormatter.formatIdlData(
+                      { name: "", type: fields[key] },
+                      val,
+                      types
+                    )
+                  );
+                })
+                .join(", ");
             }
-            return (
-              k +
-              ": " +
-              InstructionFormatter.formatIdlData(field, data[k], types)
-            );
-          })
-          .join(", ");
-        return "{ " + fields + " }";
+          ) +
+          " }"
+        );
       }
 
       case "enum": {
-        if (typeDef.type.variants.length === 0) {
-          return "{}";
+        const variantName = Object.keys(data)[0];
+        const variant = typeDef.type.variants.find(
+          (v) => v.name === variantName
+        );
+        if (!variant) {
+          throw new Error(`Unable to find variant: ${variantName}`);
         }
-        // Struct enum.
-        if (typeDef.type.variants[0].name) {
-          const variants = typeDef.type.variants;
-          const variant = Object.keys(data)[0];
-          const enumType = data[variant];
-          const enumVariant = variants.find(
-            (v) => camelCase(v.name) === variant
-          );
-          if (!enumVariant) {
-            throw new Error(`Unable to find variant \`${variant}\``);
-          }
-          const fields = enumVariant.fields as IdlEnumFieldsNamed;
-          const namedFields = Object.keys(enumType)
-            .map((f) => {
-              const fieldData = enumType[f];
-              const idlField = fields.find((v) => v.name === f);
-              if (!idlField) {
-                throw new Error(`Unable to find field \`${f}\``);
-              }
-
-              return (
-                f +
-                ": " +
-                InstructionFormatter.formatIdlData(idlField, fieldData, types)
-              );
-            })
-            .join(", ");
-
-          const variantName = camelCase(variant, { pascalCase: true });
-          if (namedFields.length === 0) {
-            return variantName;
+
+        const enumValue = data[variantName];
+        return handleDefinedFields(
+          variant.fields,
+          () => variantName,
+          (fields) => {
+            const namedFields = Object.keys(enumValue)
+              .map((f) => {
+                const fieldData = enumValue[f];
+                const idlField = fields.find((v) => v.name === f);
+                if (!idlField) {
+                  throw new Error(`Field not found: ${f}`);
+                }
+
+                return (
+                  f +
+                  ": " +
+                  InstructionFormatter.formatIdlData(idlField, fieldData, types)
+                );
+              })
+              .join(", ");
+
+            return `${variantName} { ${namedFields} }`;
+          },
+          (fields) => {
+            const tupleFields = Object.entries(enumValue)
+              .map(([key, val]) => {
+                return (
+                  key +
+                  ": " +
+                  InstructionFormatter.formatIdlData(
+                    { name: "", type: fields[key] },
+                    val as any,
+                    types
+                  )
+                );
+              })
+              .join(", ");
+
+            return `${variantName} { ${tupleFields} }`;
           }
-          return `${variantName} { ${namedFields} }`;
-        }
-        // Tuple enum.
-        else {
-          // TODO.
-          return "Tuple formatting not yet implemented";
-        }
+        );
       }
 
-      case "alias": {
-        return InstructionFormatter.formatIdlType(typeDef.type.value);
+      case "type": {
+        return InstructionFormatter.formatIdlType(typeDef.type.alias);
       }
     }
   }
 
   private static flattenIdlAccounts(
-    accounts: IdlAccountItem[],
+    accounts: IdlInstructionAccountItem[],
     prefix?: string
   ): IdlAccount[] {
     return accounts
@@ -357,7 +361,7 @@ class InstructionFormatter {
         if (account.hasOwnProperty("accounts")) {
           const newPrefix = prefix ? `${prefix} > ${accName}` : accName;
           return InstructionFormatter.flattenIdlAccounts(
-            (account).accounts,
+            (account).accounts,
             newPrefix
           );
         } else {
@@ -375,11 +379,3 @@ function sentenceCase(field: string): string {
   const result = field.replace(/([A-Z])/g, " $1");
   return result.charAt(0).toUpperCase() + result.slice(1);
 }
-
-// Not technically sighash, since we don't include the arguments, as Rust
-// doesn't allow function overloading.
-function sighash(nameSpace: string, ixName: string): Buffer {
-  let name = snakeCase(ixName);
-  let preimage = `${nameSpace}:${name}`;
-  return Buffer.from(sha256(preimage).slice(0, 8));
-}
diff --git a/ts/packages/anchor/src/coder/borsh/types.ts b/ts/packages/anchor/src/coder/borsh/types.ts
index 848e4faa3d..4087d5a52d 100644
--- a/ts/packages/anchor/src/coder/borsh/types.ts
+++ b/ts/packages/anchor/src/coder/borsh/types.ts
@@ -13,40 +13,38 @@ export class BorshTypesCoder implements TypesCoder {
    */
   private typeLayouts: Map;
 
-  /**
-   * IDL whose types will be coded.
-   */
-  private idl: Idl;
-
   public constructor(idl: Idl) {
-    if (idl.types === undefined) {
+    const types = idl.types;
+    if (!types) {
       this.typeLayouts = new Map();
       return;
     }
-    const layouts: [N, Layout][] = idl.types.map((acc) => {
-      return [acc.name as N, IdlCoder.typeDefLayout(acc, idl.types)];
-    });
 
+    const layouts: [N, Layout][] = types
+      .filter((ty) => !ty.generics)
+      .map((ty) => [
+        ty.name as N,
+        IdlCoder.typeDefLayout({ typeDef: ty, types }),
+      ]);
     this.typeLayouts = new Map(layouts);
-    this.idl = idl;
   }
 
-  public encode(typeName: N, type: T): Buffer {
+  public encode(name: N, type: T): Buffer {
     const buffer = Buffer.alloc(1000); // TODO: use a tighter buffer.
-    const layout = this.typeLayouts.get(typeName);
+    const layout = this.typeLayouts.get(name);
     if (!layout) {
-      throw new Error(`Unknown type: ${typeName}`);
+      throw new Error(`Unknown type: ${name}`);
     }
     const len = layout.encode(type, buffer);
 
     return buffer.slice(0, len);
   }
 
-  public decode(typeName: N, typeData: Buffer): T {
-    const layout = this.typeLayouts.get(typeName);
+  public decode(name: N, data: Buffer): T {
+    const layout = this.typeLayouts.get(name);
     if (!layout) {
-      throw new Error(`Unknown type: ${typeName}`);
+      throw new Error(`Unknown type: ${name}`);
     }
-    return layout.decode(typeData);
+    return layout.decode(data);
   }
 }
diff --git a/ts/packages/anchor/src/coder/common.ts b/ts/packages/anchor/src/coder/common.ts
deleted file mode 100644
index 6df3b82bdd..0000000000
--- a/ts/packages/anchor/src/coder/common.ts
+++ /dev/null
@@ -1,106 +0,0 @@
-import { Idl, IdlField, IdlTypeDef, IdlType } from "../idl.js";
-import { IdlError } from "../error.js";
-
-export function accountSize(idl: Idl, idlAccount: IdlTypeDef) {
-  switch (idlAccount.type.kind) {
-    case "struct": {
-      return idlAccount.type.fields
-        .map((f) => typeSize(idl, f.type))
-        .reduce((acc, size) => acc + size, 0);
-    }
-
-    case "enum": {
-      const variantSizes = idlAccount.type.variants.map((variant) => {
-        if (!variant.fields) {
-          return 0;
-        }
-
-        return variant.fields
-          .map((f: IdlField | IdlType) => {
-            // Unnamed enum variant
-            if (!(typeof f === "object" && "name" in f)) {
-              return typeSize(idl, f);
-            }
-
-            // Named enum variant
-            return typeSize(idl, f.type);
-          })
-          .reduce((acc, size) => acc + size, 0);
-      });
-
-      return Math.max(...variantSizes) + 1;
-    }
-
-    case "alias": {
-      return typeSize(idl, idlAccount.type.value);
-    }
-  }
-}
-
-// Returns the size of the type in bytes. For variable length types, just return
-// 1. Users should override this value in such cases.
-function typeSize(idl: Idl, ty: IdlType): number {
-  switch (ty) {
-    case "bool":
-      return 1;
-    case "u8":
-      return 1;
-    case "i8":
-      return 1;
-    case "i16":
-      return 2;
-    case "u16":
-      return 2;
-    case "u32":
-      return 4;
-    case "i32":
-      return 4;
-    case "f32":
-      return 4;
-    case "u64":
-      return 8;
-    case "i64":
-      return 8;
-    case "f64":
-      return 8;
-    case "u128":
-      return 16;
-    case "i128":
-      return 16;
-    case "u256":
-      return 32;
-    case "i256":
-      return 32;
-    case "bytes":
-      return 1;
-    case "string":
-      return 1;
-    case "publicKey":
-      return 32;
-    default:
-      if ("vec" in ty) {
-        return 1;
-      }
-      if ("option" in ty) {
-        return 1 + typeSize(idl, ty.option);
-      }
-      if ("coption" in ty) {
-        return 4 + typeSize(idl, ty.coption);
-      }
-      if ("defined" in ty) {
-        const filtered = idl.types?.filter((t) => t.name === ty.defined) ?? [];
-        if (filtered.length !== 1) {
-          throw new IdlError(`Type not found: ${JSON.stringify(ty)}`);
-        }
-        let typeDef = filtered[0];
-
-        return accountSize(idl, typeDef);
-      }
-      if ("array" in ty) {
-        let arrayTy = ty.array[0];
-        let arraySize = ty.array[1];
-        return typeSize(idl, arrayTy) * arraySize;
-      }
-      throw new Error(`Invalid type ${JSON.stringify(ty)}`);
-  }
-}
diff --git a/ts/packages/anchor/src/coder/index.ts b/ts/packages/anchor/src/coder/index.ts
index 10567ebae1..6d0d482d64 100644
--- a/ts/packages/anchor/src/coder/index.ts
+++ b/ts/packages/anchor/src/coder/index.ts
@@ -1,4 +1,4 @@
-import { IdlEvent, IdlTypeDef } from "../idl.js";
+import { IdlEvent } from "../idl.js";
 import { Event } from "../program/event.js";
 
 export * from "./borsh/index.js";
@@ -36,14 +36,14 @@ export interface StateCoder {
 
 export interface AccountsCoder {
   encode(accountName: A, account: T): Promise;
-  decode(accountName: A, ix: Buffer): T;
-  decodeUnchecked(accountName: A, ix: Buffer): T;
+  decode(accountName: A, acc: Buffer): T;
+  decodeUnchecked(accountName: A, acc: Buffer): T;
   memcmp(accountName: A, appendData?: Buffer): any;
-  size(idlAccount: IdlTypeDef): number;
+  size(accountName: A): number;
 }
 
 export interface InstructionCoder {
-  encode(ixName: string, ix: any, discriminator?: Buffer): Buffer;
+  encode(ixName: string, ix: any): Buffer;
 }
 
 export interface EventCoder {
diff --git a/ts/packages/anchor/src/coder/system/accounts.ts b/ts/packages/anchor/src/coder/system/accounts.ts
index c5749dc3c0..9cab25b901 100644
--- a/ts/packages/anchor/src/coder/system/accounts.ts
+++ b/ts/packages/anchor/src/coder/system/accounts.ts
@@ -1,8 +1,8 @@
 import { AccountsCoder } from "../index.js";
-import { Idl, IdlTypeDef } from "../../idl.js";
+import { Idl } from "../../idl.js";
 import * as BufferLayout from "buffer-layout";
 import { NONCE_ACCOUNT_LENGTH, PublicKey } from "@solana/web3.js";
-import { accountSize } from "../common.js";
+import { IdlCoder } from "../borsh/idl.js";
 
 export class SystemAccountsCoder
   implements AccountsCoder
@@ -51,8 +51,8 @@ export class SystemAccountsCoder
     }
   }
 
-  public size(idlAccount: IdlTypeDef): number {
-    return accountSize(this.idl, idlAccount) ?? 0;
+  public size(accountName: A): number {
+    return IdlCoder.typeSize({ defined: { name: accountName } }, this.idl);
   }
 }
 
diff --git a/ts/packages/anchor/src/coder/system/instruction.ts b/ts/packages/anchor/src/coder/system/instruction.ts
index 894cdf12c6..5a6dfa0d78 100644
--- a/ts/packages/anchor/src/coder/system/instruction.ts
+++ b/ts/packages/anchor/src/coder/system/instruction.ts
@@ -1,6 +1,5 @@
 import BN from "bn.js";
 import * as BufferLayout from "buffer-layout";
-import camelCase from "camelcase";
 import { Idl } from "../../idl.js";
 import { InstructionCoder } from "../index.js";
 
@@ -9,7 +8,7 @@ export class SystemInstructionCoder implements InstructionCoder {
   constructor(_: Idl) {}
 
   encode(ixName: string, ix: any): Buffer {
-    switch (camelCase(ixName)) {
+    switch (ixName) {
       case "createAccount": {
         return encodeCreateAccount(ix);
       }
diff --git a/ts/packages/anchor/src/error.ts b/ts/packages/anchor/src/error.ts
index f7ebc86ca5..d5acf55edf 100644
--- a/ts/packages/anchor/src/error.ts
+++ b/ts/packages/anchor/src/error.ts
@@ -1,4 +1,5 @@
 import { PublicKey } from "@solana/web3.js";
+import * as errors from "@coral-xyz/anchor-errors";
 import * as features from "./utils/features.js";
 
 export class IdlError extends Error {
@@ -307,80 +308,134 @@ export function translateError(err: any, idlErrors: Map) {
 
 export const LangErrorCode = {
   // Instructions.
-  InstructionMissing: 100,
-  InstructionFallbackNotFound: 101,
-  InstructionDidNotDeserialize: 102,
-  InstructionDidNotSerialize: 103,
+  InstructionMissing: errors.ANCHOR_ERROR__INSTRUCTION_MISSING,
+  InstructionFallbackNotFound:
+    errors.ANCHOR_ERROR__INSTRUCTION_FALLBACK_NOT_FOUND,
+  InstructionDidNotDeserialize:
+    errors.ANCHOR_ERROR__INSTRUCTION_DID_NOT_DESERIALIZE,
+  InstructionDidNotSerialize:
+    errors.ANCHOR_ERROR__INSTRUCTION_DID_NOT_SERIALIZE,
 
   // IDL instructions.
-  IdlInstructionStub: 1000,
-  IdlInstructionInvalidProgram: 1001,
+  IdlInstructionStub: errors.ANCHOR_ERROR__IDL_INSTRUCTION_STUB,
+  IdlInstructionInvalidProgram:
+    errors.ANCHOR_ERROR__IDL_INSTRUCTION_INVALID_PROGRAM,
+  IdlAccountNotEmpty: errors.ANCHOR_ERROR__IDL_ACCOUNT_NOT_EMPTY,
+
+  // Event instructions.
+  EventInstructionStub: errors.ANCHOR_ERROR__EVENT_INSTRUCTION_STUB,
 
   // Constraints.
-  ConstraintMut: 2000,
-  ConstraintHasOne: 2001,
-  ConstraintSigner: 2002,
-  ConstraintRaw: 2003,
-  ConstraintOwner: 2004,
-  ConstraintRentExempt: 2005,
-  ConstraintSeeds: 2006,
-  ConstraintExecutable: 2007,
-  ConstraintState: 2008,
-  ConstraintAssociated: 2009,
-  ConstraintAssociatedInit: 2010,
-  ConstraintClose: 2011,
-  ConstraintAddress: 2012,
-  ConstraintZero: 2013,
-  ConstraintTokenMint: 2014,
-  ConstraintTokenOwner: 2015,
-  ConstraintMintMintAuthority: 2016,
-  ConstraintMintFreezeAuthority: 2017,
-  ConstraintMintDecimals: 2018,
-  ConstraintSpace: 2019,
-  ConstraintAccountIsNone: 2020,
+  ConstraintMut: errors.ANCHOR_ERROR__CONSTRAINT_MUT,
+  ConstraintHasOne: errors.ANCHOR_ERROR__CONSTRAINT_HAS_ONE,
+  ConstraintSigner: errors.ANCHOR_ERROR__CONSTRAINT_SIGNER,
+  ConstraintRaw: errors.ANCHOR_ERROR__CONSTRAINT_RAW,
+  ConstraintOwner: errors.ANCHOR_ERROR__CONSTRAINT_OWNER,
+  ConstraintRentExempt: errors.ANCHOR_ERROR__CONSTRAINT_RENT_EXEMPT,
+  ConstraintSeeds: errors.ANCHOR_ERROR__CONSTRAINT_SEEDS,
+  ConstraintExecutable: errors.ANCHOR_ERROR__CONSTRAINT_EXECUTABLE,
+  ConstraintState: errors.ANCHOR_ERROR__CONSTRAINT_STATE,
+  ConstraintAssociated: errors.ANCHOR_ERROR__CONSTRAINT_ASSOCIATED,
+  ConstraintAssociatedInit: errors.ANCHOR_ERROR__CONSTRAINT_ASSOCIATED_INIT,
+  ConstraintClose: errors.ANCHOR_ERROR__CONSTRAINT_CLOSE,
+  ConstraintAddress: errors.ANCHOR_ERROR__CONSTRAINT_ADDRESS,
+  ConstraintZero: errors.ANCHOR_ERROR__CONSTRAINT_ZERO,
+  ConstraintTokenMint: errors.ANCHOR_ERROR__CONSTRAINT_TOKEN_MINT,
+  ConstraintTokenOwner: errors.ANCHOR_ERROR__CONSTRAINT_TOKEN_OWNER,
+  ConstraintMintMintAuthority:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_MINT_AUTHORITY,
+  ConstraintMintFreezeAuthority:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_FREEZE_AUTHORITY,
+  ConstraintMintDecimals: errors.ANCHOR_ERROR__CONSTRAINT_MINT_DECIMALS,
+  ConstraintSpace: errors.ANCHOR_ERROR__CONSTRAINT_SPACE,
+  ConstraintAccountIsNone: errors.ANCHOR_ERROR__CONSTRAINT_ACCOUNT_IS_NONE,
+  ConstraintTokenTokenProgram:
+    errors.ANCHOR_ERROR__CONSTRAINT_TOKEN_TOKEN_PROGRAM,
+  ConstraintMintTokenProgram:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_TOKEN_PROGRAM,
+  ConstraintAssociatedTokenTokenProgram:
+    errors.ANCHOR_ERROR__CONSTRAINT_ASSOCIATED_TOKEN_TOKEN_PROGRAM,
+  ConstraintMintGroupPointerExtension:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION,
+  ConstraintMintGroupPointerExtensionAuthority:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION_AUTHORITY,
+  ConstraintMintGroupPointerExtensionGroupAddress:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_POINTER_EXTENSION_GROUP_ADDRESS,
+  ConstraintMintGroupMemberPointerExtension:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION,
+  ConstraintMintGroupMemberPointerExtensionAuthority:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION_AUTHORITY,
+  ConstraintMintGroupMemberPointerExtensionMemberAddress:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_GROUP_MEMBER_POINTER_EXTENSION_MEMBER_ADDRESS,
+  ConstraintMintMetadataPointerExtension:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION,
+  ConstraintMintMetadataPointerExtensionAuthority:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION_AUTHORITY,
+  ConstraintMintMetadataPointerExtensionMetadataAddress:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_METADATA_POINTER_EXTENSION_METADATA_ADDRESS,
+  ConstraintMintCloseAuthorityExtension:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_CLOSE_AUTHORITY_EXTENSION,
+  ConstraintMintCloseAuthorityExtensionAuthority:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_CLOSE_AUTHORITY_EXTENSION_AUTHORITY,
+  ConstraintMintPermanentDelegateExtension:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_PERMANENT_DELEGATE_EXTENSION,
+  ConstraintMintPermanentDelegateExtensionDelegate:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_PERMANENT_DELEGATE_EXTENSION_DELEGATE,
+  ConstraintMintTransferHookExtension:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION,
+  ConstraintMintTransferHookExtensionAuthority:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION_AUTHORITY,
+  ConstraintMintTransferHookExtensionProgramId:
+    errors.ANCHOR_ERROR__CONSTRAINT_MINT_TRANSFER_HOOK_EXTENSION_PROGRAM_ID,
 
   // Require.
-  RequireViolated: 2500,
-  RequireEqViolated: 2501,
-  RequireKeysEqViolated: 2502,
-  RequireNeqViolated: 2503,
-  RequireKeysNeqViolated: 2504,
-  RequireGtViolated: 2505,
-  RequireGteViolated: 2506,
+  RequireViolated: errors.ANCHOR_ERROR__REQUIRE_VIOLATED,
+  RequireEqViolated: errors.ANCHOR_ERROR__REQUIRE_EQ_VIOLATED,
+  RequireKeysEqViolated: errors.ANCHOR_ERROR__REQUIRE_KEYS_EQ_VIOLATED,
+  RequireNeqViolated: errors.ANCHOR_ERROR__REQUIRE_NEQ_VIOLATED,
+  RequireKeysNeqViolated: errors.ANCHOR_ERROR__REQUIRE_KEYS_NEQ_VIOLATED,
+  RequireGtViolated: errors.ANCHOR_ERROR__REQUIRE_GT_VIOLATED,
+  RequireGteViolated: errors.ANCHOR_ERROR__REQUIRE_GTE_VIOLATED,
 
   // Accounts.
-  AccountDiscriminatorAlreadySet: 3000,
-  AccountDiscriminatorNotFound: 3001,
-  AccountDiscriminatorMismatch: 3002,
-  AccountDidNotDeserialize: 3003,
-  AccountDidNotSerialize: 3004,
-  AccountNotEnoughKeys: 3005,
-  AccountNotMutable: 3006,
-  AccountOwnedByWrongProgram: 3007,
-  InvalidProgramId: 3008,
-  InvalidProgramExecutable: 3009,
-  AccountNotSigner: 3010,
-  AccountNotSystemOwned: 3011,
-  AccountNotInitialized: 3012,
-  AccountNotProgramData: 3013,
-  AccountNotAssociatedTokenAccount: 3014,
-  AccountSysvarMismatch: 3015,
-  AccountReallocExceedsLimit: 3016,
-  AccountDuplicateReallocs: 3017,
+  AccountDiscriminatorAlreadySet:
+    errors.ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_ALREADY_SET,
+  AccountDiscriminatorNotFound:
+    errors.ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_NOT_FOUND,
+  AccountDiscriminatorMismatch:
+    errors.ANCHOR_ERROR__ACCOUNT_DISCRIMINATOR_MISMATCH,
+  AccountDidNotDeserialize: errors.ANCHOR_ERROR__ACCOUNT_DID_NOT_DESERIALIZE,
+  AccountDidNotSerialize: errors.ANCHOR_ERROR__ACCOUNT_DID_NOT_SERIALIZE,
+  AccountNotEnoughKeys: errors.ANCHOR_ERROR__ACCOUNT_NOT_ENOUGH_KEYS,
+  AccountNotMutable: errors.ANCHOR_ERROR__ACCOUNT_NOT_MUTABLE,
+  AccountOwnedByWrongProgram:
+    errors.ANCHOR_ERROR__ACCOUNT_OWNED_BY_WRONG_PROGRAM,
+  InvalidProgramId: errors.ANCHOR_ERROR__INVALID_PROGRAM_ID,
+  InvalidProgramExecutable: errors.ANCHOR_ERROR__INVALID_PROGRAM_EXECUTABLE,
+  AccountNotSigner: errors.ANCHOR_ERROR__ACCOUNT_NOT_SIGNER,
+  AccountNotSystemOwned: errors.ANCHOR_ERROR__ACCOUNT_NOT_SYSTEM_OWNED,
+  AccountNotInitialized: errors.ANCHOR_ERROR__ACCOUNT_NOT_INITIALIZED,
+  AccountNotProgramData: errors.ANCHOR_ERROR__ACCOUNT_NOT_PROGRAM_DATA,
+  AccountNotAssociatedTokenAccount:
+    errors.ANCHOR_ERROR__ACCOUNT_NOT_ASSOCIATED_TOKEN_ACCOUNT,
+  AccountSysvarMismatch: errors.ANCHOR_ERROR__ACCOUNT_SYSVAR_MISMATCH,
+  AccountReallocExceedsLimit:
+    errors.ANCHOR_ERROR__ACCOUNT_REALLOC_EXCEEDS_LIMIT,
+  AccountDuplicateReallocs: errors.ANCHOR_ERROR__ACCOUNT_DUPLICATE_REALLOCS,
 
   // Miscellaneous
-  DeclaredProgramIdMismatch: 4100,
+  DeclaredProgramIdMismatch: errors.ANCHOR_ERROR__DECLARED_PROGRAM_ID_MISMATCH,
+  TryingToInitPayerAsProgramAccount:
+    errors.ANCHOR_ERROR__TRYING_TO_INIT_PAYER_AS_PROGRAM_ACCOUNT,
+  InvalidNumericConversion: errors.ANCHOR_ERROR__INVALID_NUMERIC_CONVERSION,
 
   // Used for APIs that shouldn't be used anymore.
-  Deprecated: 5000,
+  Deprecated: errors.ANCHOR_ERROR__DEPRECATED,
 };
 
-export const LangErrorMessage = new Map([
+export const LangErrorMessage = new Map([
   // Instructions.
-  [
-    LangErrorCode.InstructionMissing,
-    "8 byte instruction identifier not provided",
-  ],
+  [LangErrorCode.InstructionMissing, "Instruction discriminator not provided"],
   [
     LangErrorCode.InstructionFallbackNotFound,
     "Fallback functions are not supported",
@@ -403,6 +458,16 @@ export const LangErrorMessage = new Map([
     LangErrorCode.IdlInstructionInvalidProgram,
     "The transaction was given an invalid program for the IDL instruction",
   ],
+  [
+    LangErrorCode.IdlAccountNotEmpty,
+    "IDL account must be empty in order to resize, try closing first",
+  ],
+
+  // Event instructions.
+  [
+    LangErrorCode.EventInstructionStub,
+    "The program was compiled without `event-cpi` feature",
+  ],
 
   // Constraints.
   [LangErrorCode.ConstraintMut, "A mut constraint was violated"],
@@ -447,6 +512,82 @@ export const LangErrorMessage = new Map([
     LangErrorCode.ConstraintAccountIsNone,
     "A required account for the constraint is None",
   ],
+  [
+    LangErrorCode.ConstraintTokenTokenProgram,
+    "A token account token program constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintTokenProgram,
+    "A mint token program constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintAssociatedTokenTokenProgram,
+    "An associated token account token program constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintGroupPointerExtension,
+    "A group pointer extension constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintGroupPointerExtensionAuthority,
+    "A group pointer extension authority constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintGroupPointerExtensionGroupAddress,
+    "A group pointer extension group address constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintGroupMemberPointerExtension,
+    "A group member pointer extension constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintGroupMemberPointerExtensionAuthority,
+    "A group member pointer extension authority constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintGroupMemberPointerExtensionMemberAddress,
+    "A group member pointer extension group address constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintMetadataPointerExtension,
+    "A metadata pointer extension constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintMetadataPointerExtensionAuthority,
+    "A metadata pointer extension authority constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintMetadataPointerExtensionMetadataAddress,
+    "A metadata pointer extension metadata address constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintCloseAuthorityExtension,
+    "A close authority constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintCloseAuthorityExtensionAuthority,
+    "A close authority extension authority constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintPermanentDelegateExtension,
+    "A permanent delegate extension constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintPermanentDelegateExtensionDelegate,
+    "A permanent delegate extension delegate constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintTransferHookExtension,
+    "A transfer hook extension constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintTransferHookExtensionAuthority,
+    "A transfer hook extension authority constraint was violated",
+  ],
+  [
+    LangErrorCode.ConstraintMintTransferHookExtensionProgramId,
+    "A transfer hook extension transfer hook program id constraint was violated",
+  ],
 
   // Require.
   [LangErrorCode.RequireViolated, "A require expression was violated"],
@@ -470,11 +611,11 @@ export const LangErrorMessage = new Map([
   ],
   [
     LangErrorCode.AccountDiscriminatorNotFound,
-    "No 8 byte discriminator was found on the account",
+    "No discriminator was found on the account",
   ],
   [
     LangErrorCode.AccountDiscriminatorMismatch,
-    "8 byte discriminator did not match what was expected",
+    "Account discriminator did not match what was expected",
   ],
   [LangErrorCode.AccountDidNotDeserialize, "Failed to deserialize the account"],
   [LangErrorCode.AccountDidNotSerialize, "Failed to serialize the account"],
@@ -524,6 +665,14 @@ export const LangErrorMessage = new Map([
     LangErrorCode.DeclaredProgramIdMismatch,
     "The declared program id does not match the actual program id",
   ],
+  [
+    LangErrorCode.TryingToInitPayerAsProgramAccount,
+    "You cannot/should not initialize the payer account as a program account",
+  ],
+  [
+    LangErrorCode.InvalidNumericConversion,
+    "The program could not perform the numeric conversion, out of range integral type conversion attempted",
+  ],
 
   // Deprecated
   [
diff --git a/ts/packages/anchor/src/idl.ts b/ts/packages/anchor/src/idl.ts
index 4a6c71fb72..6d7a044b87 100644
--- a/ts/packages/anchor/src/idl.ts
+++ b/ts/packages/anchor/src/idl.ts
@@ -1,98 +1,115 @@
+import camelCase from "camelcase";
 import { Buffer } from "buffer";
 import { PublicKey } from "@solana/web3.js";
 import * as borsh from "@coral-xyz/borsh";
 
 export type Idl = {
-  version: string;
-  name: string;
+  address: string;
+  metadata: IdlMetadata;
   docs?: string[];
   instructions: IdlInstruction[];
-  accounts?: IdlAccountDef[];
-  types?: IdlTypeDef[];
+  accounts?: IdlAccount[];
   events?: IdlEvent[];
   errors?: IdlErrorCode[];
-  constants?: IdlConstant[];
-  metadata?: IdlMetadata;
+  types?: IdlTypeDef[];
+  constants?: IdlConst[];
 };
 
-export type IdlMetadata = any;
-
-export type IdlConstant = {
+export type IdlMetadata = {
   name: string;
-  type: IdlType;
-  value: string;
+  version: string;
+  spec: string;
+  description?: string;
+  repository?: string;
+  dependencies?: IdlDependency[];
+  contact?: string;
+  deployments?: IdlDeployments;
 };
 
-export type IdlEvent = {
+export type IdlDependency = {
   name: string;
-  fields: IdlEventField[];
+  version: string;
 };
 
-export type IdlEventField = {
-  name: string;
-  type: IdlType;
-  index: boolean;
+export type IdlDeployments = {
+  mainnet?: string;
+  testnet?: string;
+  devnet?: string;
+  localnet?: string;
 };
 
 export type IdlInstruction = {
   name: string;
   docs?: string[];
-  accounts: IdlAccountItem[];
+  discriminator: IdlDiscriminator;
+  accounts: IdlInstructionAccountItem[];
   args: IdlField[];
   returns?: IdlType;
 };
 
-export type IdlStateMethod = IdlInstruction;
-
-export type IdlAccountItem = IdlAccount | IdlAccounts;
+export type IdlInstructionAccountItem =
+  | IdlInstructionAccount
+  | IdlInstructionAccounts;
 
-export function isIdlAccounts(
-  accountItem: IdlAccountItem
-): accountItem is IdlAccounts {
-  return "accounts" in accountItem;
-}
-
-export type IdlAccount = {
+export type IdlInstructionAccount = {
   name: string;
-  isMut: boolean;
-  isSigner: boolean;
-  isOptional?: boolean;
   docs?: string[];
-  relations?: string[];
+  writable?: boolean;
+  signer?: boolean;
+  optional?: boolean;
+  address?: string;
   pda?: IdlPda;
+  relations?: string[];
+};
+
+export type IdlInstructionAccounts = {
+  name: string;
+  accounts: IdlInstructionAccount[];
 };
 
 export type IdlPda = {
   seeds: IdlSeed[];
-  programId?: IdlSeed;
+  program?: IdlSeed;
 };
 
 export type IdlSeed = IdlSeedConst | IdlSeedArg | IdlSeedAccount;
 
 export type IdlSeedConst = {
   kind: "const";
-  type: IdlType;
-  value: any;
+  value: number[];
 };
 
 export type IdlSeedArg = {
   kind: "arg";
-  type: IdlType;
   path: string;
 };
 
 export type IdlSeedAccount = {
   kind: "account";
-  type: IdlType;
-  account?: string;
   path: string;
+  account?: string;
 };
 
-// A nested/recursive version of IdlAccount.
-export type IdlAccounts = {
+export type IdlAccount = {
   name: string;
-  docs?: string[];
-  accounts: IdlAccountItem[];
+  discriminator: IdlDiscriminator;
+};
+
+export type IdlEvent = {
+  name: string;
+  discriminator: IdlDiscriminator;
+};
+
+export type IdlConst = {
+  name: string;
+  type: IdlType;
+  value: string;
+};
+
+export type IdlErrorCode = {
+  name: string;
+  code: number;
+  msg?: string;
 };
 
 export type IdlField = {
@@ -104,18 +121,58 @@ export type IdlField = {
 export type IdlTypeDef = {
   name: string;
   docs?: string[];
+  serialization?: IdlSerialization;
+  repr?: IdlRepr;
+  generics?: IdlTypeDefGeneric[];
   type: IdlTypeDefTy;
 };
 
-export type IdlAccountDef = {
+export type IdlSerialization =
+  | "borsh"
+  | "bytemuck"
+  | "bytemuckunsafe"
+  | { custom: string };
+
+export type IdlRepr = IdlReprRust | IdlReprC | IdlReprTransparent;
+
+export type IdlReprRust = {
+  kind: "rust";
+} & IdlReprModifier;
+
+export type IdlReprC = {
+  kind: "c";
+} & IdlReprModifier;
+
+export type IdlReprTransparent = {
+  kind: "transparent";
+};
+
+export type IdlReprModifier = {
+  packed?: boolean;
+  align?: number;
+};
+
+export type IdlTypeDefGeneric = IdlTypeDefGenericType | IdlTypeDefGenericConst;
+
+export type IdlTypeDefGenericType = {
+  kind: "type";
   name: string;
-  docs?: string[];
-  type: IdlTypeDefTyStruct;
 };
 
+export type IdlTypeDefGenericConst = {
+  kind: "const";
+  name: string;
+  type: string;
+};
+
+export type IdlTypeDefTy =
+  | IdlTypeDefTyEnum
+  | IdlTypeDefTyStruct
+  | IdlTypeDefTyType;
+
 export type IdlTypeDefTyStruct = {
   kind: "struct";
-  fields: IdlTypeDefStruct;
+  fields?: IdlDefinedFields;
 };
 
 export type IdlTypeDefTyEnum = {
@@ -123,17 +180,35 @@ export type IdlTypeDefTyEnum = {
   variants: IdlEnumVariant[];
 };
 
-export type IdlTypeDefTyAlias = {
-  kind: "alias";
-  value: IdlType;
+export type IdlTypeDefTyType = {
+  kind: "type";
+  alias: IdlType;
 };
 
-export type IdlTypeDefTy =
-  | IdlTypeDefTyEnum
-  | IdlTypeDefTyStruct
-  | IdlTypeDefTyAlias;
+export type IdlEnumVariant = {
+  name: string;
+  fields?: IdlDefinedFields;
+};
+
+export type IdlDefinedFields = IdlDefinedFieldsNamed | IdlDefinedFieldsTuple;
+
+export type IdlDefinedFieldsNamed = IdlField[];
+
+export type IdlDefinedFieldsTuple = IdlType[];
+
+export type IdlArrayLen = IdlArrayLenGeneric | IdlArrayLenValue;
+
+export type IdlArrayLenGeneric = {
+  generic: string;
+};
 
-export type IdlTypeDefStruct = Array;
+export type IdlArrayLenValue = number;
+
+export type IdlGenericArg = IdlGenericArgType | IdlGenericArgConst;
+
+export type IdlGenericArgType = { kind: "type"; type: IdlType };
+
+export type IdlGenericArgConst = { kind: "const"; value: string };
 
 export type IdlType =
   | "bool"
@@ -153,17 +228,13 @@ export type IdlType =
   | "i256"
   | "bytes"
   | "string"
-  | "publicKey"
-  | IdlTypeDefined
+  | "pubkey"
   | IdlTypeOption
   | IdlTypeCOption
   | IdlTypeVec
-  | IdlTypeArray;
-
-// User defined type.
-export type IdlTypeDefined = {
-  defined: string;
-};
+  | IdlTypeArray
+  | IdlTypeDefined
+  | IdlTypeGeneric;
 
 export type IdlTypeOption = {
   option: IdlType;
@@ -178,25 +249,27 @@ export type IdlTypeVec = {
 };
 
 export type IdlTypeArray = {
-  array: [idlType: IdlType, size: number];
+  array: [idlType: IdlType, size: IdlArrayLen];
 };
 
-export type IdlEnumVariant = {
-  name: string;
-  fields?: IdlEnumFields;
+export type IdlTypeDefined = {
+  defined: {
+    name: string;
+    generics?: IdlGenericArg[];
+  };
 };
 
-export type IdlEnumFields = IdlEnumFieldsNamed | IdlEnumFieldsTuple;
-
-export type IdlEnumFieldsNamed = IdlField[];
+export type IdlTypeGeneric = {
+  generic: string;
+};
 
-export type IdlEnumFieldsTuple = IdlType[];
+export type IdlDiscriminator = number[];
 
-export type IdlErrorCode = {
-  code: number;
-  name: string;
-  msg?: string;
-};
+export function isCompositeAccounts(
+  accountItem: IdlInstructionAccountItem
+): accountItem is IdlInstructionAccounts {
+  return "accounts" in accountItem;
+}
 
 // Deterministic IDL address as a function of the program id.
 export async function idlAddress(programId: PublicKey): Promise {
@@ -229,3 +302,58 @@ export function encodeIdlAccount(acc: IdlProgramAccount): Buffer {
   const len = IDL_ACCOUNT_LAYOUT.encode(acc, buffer);
   return buffer.slice(0, len);
 }
+
+/**
+ * Convert the given IDL to camelCase.
+ *
+ * The IDL is generated from Rust which has different conventions compared to
+ * JS/TS, e.g. instruction names in Rust are snake_case.
+ *
+ * The conversion happens automatically for programs, however, if you are using
+ * internals such as `BorshInstructionCoder` and you only have the original
+ * (not camelCase) IDL, you might need to use this function.
+ *
+ * @param idl IDL to convert to camelCase
+ * @returns camelCase version of the IDL
+ */
+export function convertIdlToCamelCase(idl: I) {
+  const KEYS_TO_CONVERT = ["name", "path", "account", "relations", "generic"];
+
+  // `my_account.field` is getting converted to `myAccountField` but we
+  // need `myAccount.field`.
+  const toCamelCase = (s: any) => s.split(".").map(camelCase).join(".");
+
+  const recursivelyConvertNamesToCamelCase = (obj: Record) => {
+    for (const key in obj) {
+      const val = obj[key];
+      if (KEYS_TO_CONVERT.includes(key)) {
+        obj[key] = Array.isArray(val) ? val.map(toCamelCase) : toCamelCase(val);
+      } else if (typeof val === "object") {
+        recursivelyConvertNamesToCamelCase(val);
+      }
+    }
+  };
+
+  const camelCasedIdl = structuredClone(idl);
+  recursivelyConvertNamesToCamelCase(camelCasedIdl);
+  return camelCasedIdl;
+}
+
+/** Conveniently handle all defined field kinds with proper type support. */
+export function handleDefinedFields(
+  fields: IdlDefinedFields | undefined,
+  unitCb: () => U,
+  namedCb: (fields: IdlDefinedFieldsNamed) => N,
+  tupleCb: (fields: IdlDefinedFieldsTuple) => T
+) {
+  // Unit
+  if (!fields?.length) return unitCb();
+
+  // Named
+  if ((fields as IdlDefinedFieldsNamed)[0].name) {
+    return namedCb(fields as IdlDefinedFieldsNamed);
+  }
+
+  // Tuple
+  return tupleCb(fields as IdlDefinedFieldsTuple);
+}
diff --git a/ts/packages/anchor/src/native/system.ts b/ts/packages/anchor/src/native/system.ts
index e42ead4dc9..c7b4a67744 100644
--- a/ts/packages/anchor/src/native/system.ts
+++ b/ts/packages/anchor/src/native/system.ts
@@ -3,10 +3,12 @@ import { Program } from "../program/index.js";
 import Provider from "../provider.js";
 import { SystemCoder } from "../coder/system/index.js";
 
-const SYSTEM_PROGRAM_ID = new PublicKey("11111111111111111111111111111111");
+export const SYSTEM_PROGRAM_ID = new PublicKey(
+  "11111111111111111111111111111111"
+);
 
 export function program(provider?: Provider): Program {
-  return new Program(IDL, SYSTEM_PROGRAM_ID, provider, coder());
+  return new Program(IDL, provider, coder());
 }
 
 export function coder(): SystemCoder {
@@ -17,321 +19,281 @@ export function coder(): SystemCoder {
  * System IDL.
  */
 export type SystemProgram = {
-  version: "0.1.0";
-  name: "system_program";
+  address: "11111111111111111111111111111111";
+  metadata: {
+    name: "systemProgram";
+    version: "0.1.0";
+    spec: "0.1.0";
+  };
   instructions: [
     {
-      name: "createAccount";
+      name: "advanceNonceAccount";
+      discriminator: [4, 0, 0, 0];
       accounts: [
         {
-          name: "from";
-          isMut: true;
-          isSigner: true;
-        },
-        {
-          name: "to";
-          isMut: true;
-          isSigner: true;
-        }
-      ];
-      args: [
-        {
-          name: "lamports";
-          type: "u64";
+          name: "nonce";
+          writable: true;
         },
         {
-          name: "space";
-          type: "u64";
+          name: "recentBlockhashes";
         },
         {
-          name: "owner";
-          type: "publicKey";
-        }
-      ];
-    },
-    {
-      name: "assign";
-      accounts: [
-        {
-          name: "pubkey";
-          isMut: true;
-          isSigner: true;
+          name: "authorized";
+          signer: true;
         }
       ];
       args: [
         {
-          name: "owner";
-          type: "publicKey";
+          name: "authorized";
+          type: "pubkey";
         }
       ];
     },
     {
-      name: "transfer";
+      name: "allocate";
+      discriminator: [8, 0, 0, 0];
       accounts: [
         {
-          name: "from";
-          isMut: true;
-          isSigner: true;
-        },
-        {
-          name: "to";
-          isMut: true;
-          isSigner: false;
+          name: "pubkey";
+          writable: true;
+          signer: true;
         }
       ];
       args: [
         {
-          name: "lamports";
+          name: "space";
           type: "u64";
         }
       ];
     },
     {
-      name: "createAccountWithSeed";
+      name: "allocateWithSeed";
+      discriminator: [9, 0, 0, 0];
       accounts: [
         {
-          name: "from";
-          isMut: true;
-          isSigner: true;
-        },
-        {
-          name: "to";
-          isMut: true;
-          isSigner: false;
+          name: "account";
+          writable: true;
         },
         {
           name: "base";
-          isMut: false;
-          isSigner: true;
+          signer: true;
         }
       ];
       args: [
         {
           name: "base";
-          type: "publicKey";
+          type: "pubkey";
         },
         {
           name: "seed";
           type: "string";
         },
-        {
-          name: "lamports";
-          type: "u64";
-        },
         {
           name: "space";
           type: "u64";
         },
         {
           name: "owner";
-          type: "publicKey";
+          type: "pubkey";
         }
       ];
     },
     {
-      name: "advanceNonceAccount";
+      name: "assign";
+      discriminator: [1, 0, 0, 0];
       accounts: [
         {
-          name: "nonce";
-          isMut: true;
-          isSigner: false;
-        },
-        {
-          name: "recentBlockhashes";
-          isMut: false;
-          isSigner: false;
-        },
-        {
-          name: "authorized";
-          isMut: false;
-          isSigner: true;
+          name: "pubkey";
+          writable: true;
+          signer: true;
         }
       ];
       args: [
         {
-          name: "authorized";
-          type: "publicKey";
+          name: "owner";
+          type: "pubkey";
         }
       ];
     },
     {
-      name: "withdrawNonceAccount";
+      name: "assignWithSeed";
+      discriminator: [10, 0, 0, 0];
       accounts: [
         {
-          name: "nonce";
-          isMut: true;
-          isSigner: false;
-        },
-        {
-          name: "to";
-          isMut: true;
-          isSigner: false;
-        },
-        {
-          name: "recentBlockhashes";
-          isMut: false;
-          isSigner: false;
-        },
-        {
-          name: "rent";
-          isMut: false;
-          isSigner: false;
+          name: "account";
+          writable: true;
         },
         {
-          name: "authorized";
-          isMut: false;
-          isSigner: true;
+          name: "base";
+          signer: true;
         }
       ];
       args: [
         {
-          name: "lamports";
-          type: "u64";
-        }
-      ];
-    },
-    {
-      name: "initializeNonceAccount";
-      accounts: [
-        {
-          name: "nonce";
-          isMut: true;
-          isSigner: true;
+          name: "base";
+          type: "pubkey";
         },
         {
-          name: "recentBlockhashes";
-          isMut: false;
-          isSigner: false;
+          name: "seed";
+          type: "string";
         },
         {
-          name: "rent";
-          isMut: false;
-          isSigner: false;
-        }
-      ];
-      args: [
-        {
-          name: "authorized";
-          type: "publicKey";
+          name: "owner";
+          type: "pubkey";
         }
       ];
     },
     {
       name: "authorizeNonceAccount";
+      discriminator: [7, 0, 0, 0];
       accounts: [
         {
           name: "nonce";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "authorized";
-          isMut: false;
-          isSigner: true;
+          signer: true;
         }
       ];
       args: [
         {
           name: "authorized";
-          type: "publicKey";
+          type: "pubkey";
         }
       ];
     },
     {
-      name: "allocate";
+      name: "createAccount";
+      discriminator: [0, 0, 0, 0];
       accounts: [
         {
-          name: "pubkey";
-          isMut: true;
-          isSigner: true;
+          name: "from";
+          writable: true;
+          signer: true;
+        },
+        {
+          name: "to";
+          writable: true;
+          signer: true;
         }
       ];
       args: [
+        {
+          name: "lamports";
+          type: "u64";
+        },
         {
           name: "space";
           type: "u64";
+        },
+        {
+          name: "owner";
+          type: "pubkey";
         }
       ];
     },
     {
-      name: "allocateWithSeed";
+      name: "createAccountWithSeed";
+      discriminator: [3, 0, 0, 0];
       accounts: [
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
+          name: "from";
+          writable: true;
+          signer: true;
+        },
+        {
+          name: "to";
+          writable: true;
         },
         {
           name: "base";
-          isMut: false;
-          isSigner: true;
+          signer: true;
         }
       ];
       args: [
         {
           name: "base";
-          type: "publicKey";
+          type: "pubkey";
         },
         {
           name: "seed";
           type: "string";
         },
+        {
+          name: "lamports";
+          type: "u64";
+        },
         {
           name: "space";
           type: "u64";
         },
         {
           name: "owner";
-          type: "publicKey";
+          type: "pubkey";
         }
       ];
     },
     {
-      name: "assignWithSeed";
+      name: "initializeNonceAccount";
+      discriminator: [6, 0, 0, 0];
       accounts: [
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
+          name: "nonce";
+          writable: true;
+          signer: true;
         },
         {
-          name: "base";
-          isMut: false;
-          isSigner: true;
+          name: "recentBlockhashes";
+        },
+        {
+          name: "rent";
+          address: "SysvarRent111111111111111111111111111111111";
         }
       ];
       args: [
         {
-          name: "base";
-          type: "publicKey";
-        },
+          name: "authorized";
+          type: "pubkey";
+        }
+      ];
+    },
+    {
+      name: "transfer";
+      discriminator: [2, 0, 0, 0];
+      accounts: [
         {
-          name: "seed";
-          type: "string";
+          name: "from";
+          writable: true;
+          signer: true;
         },
         {
-          name: "owner";
-          type: "publicKey";
+          name: "to";
+          writable: true;
+        }
+      ];
+      args: [
+        {
+          name: "lamports";
+          type: "u64";
         }
       ];
     },
     {
       name: "transferWithSeed";
+      discriminator: [11, 0, 0, 0];
       accounts: [
         {
           name: "from";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "base";
-          isMut: false;
-          isSigner: true;
+          signer: true;
         },
         {
           name: "to";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         }
       ];
       args: [
@@ -345,12 +307,61 @@ export type SystemProgram = {
         },
         {
           name: "owner";
-          type: "publicKey";
+          type: "pubkey";
+        }
+      ];
+    },
+    {
+      name: "withdrawNonceAccount";
+      discriminator: [5, 0, 0, 0];
+      accounts: [
+        {
+          name: "nonce";
+          writable: true;
+        },
+        {
+          name: "to";
+          writable: true;
+        },
+        {
+          name: "recentBlockhashes";
+        },
+        {
+          name: "rent";
+          address: "SysvarRent111111111111111111111111111111111";
+        },
+        {
+          name: "authorized";
+          signer: true;
+        }
+      ];
+      args: [
+        {
+          name: "lamports";
+          type: "u64";
         }
       ];
     }
   ];
   accounts: [
+    {
+      name: "nonce";
+      discriminator: [];
+    }
+  ];
+  types: [
+    {
+      name: "feeCalculator";
+      type: {
+        kind: "struct";
+        fields: [
+          {
+            name: "lamportsPerSignature";
+            type: "u64";
+          }
+        ];
+      };
+    },
     {
       name: "nonce";
       type: {
@@ -366,354 +377,302 @@ export type SystemProgram = {
           },
           {
             name: "authorizedPubkey";
-            type: "publicKey";
+            type: "pubkey";
           },
           {
             name: "nonce";
-            type: "publicKey";
+            type: "pubkey";
           },
           {
             name: "feeCalculator";
             type: {
-              defined: "FeeCalculator";
+              defined: {
+                name: "feeCalculator";
+              };
             };
           }
         ];
       };
     }
   ];
-  types: [
-    {
-      name: "FeeCalculator";
-      type: {
-        kind: "struct";
-        fields: [
-          {
-            name: "lamportsPerSignature";
-            type: "u64";
-          }
-        ];
-      };
-    }
-  ];
 };
 
 export const IDL: SystemProgram = {
-  version: "0.1.0",
-  name: "system_program",
+  address: "11111111111111111111111111111111",
+  metadata: {
+    name: "systemProgram",
+    version: "0.1.0",
+    spec: "0.1.0",
+  },
   instructions: [
     {
-      name: "createAccount",
+      name: "advanceNonceAccount",
+      discriminator: [4, 0, 0, 0],
       accounts: [
         {
-          name: "from",
-          isMut: true,
-          isSigner: true,
-        },
-        {
-          name: "to",
-          isMut: true,
-          isSigner: true,
-        },
-      ],
-      args: [
-        {
-          name: "lamports",
-          type: "u64",
-        },
-        {
-          name: "space",
-          type: "u64",
+          name: "nonce",
+          writable: true,
         },
         {
-          name: "owner",
-          type: "publicKey",
+          name: "recentBlockhashes",
         },
-      ],
-    },
-    {
-      name: "assign",
-      accounts: [
         {
-          name: "pubkey",
-          isMut: true,
-          isSigner: true,
+          name: "authorized",
+          signer: true,
         },
       ],
       args: [
         {
-          name: "owner",
-          type: "publicKey",
+          name: "authorized",
+          type: "pubkey",
         },
       ],
     },
     {
-      name: "transfer",
+      name: "allocate",
+      discriminator: [8, 0, 0, 0],
       accounts: [
         {
-          name: "from",
-          isMut: true,
-          isSigner: true,
-        },
-        {
-          name: "to",
-          isMut: true,
-          isSigner: false,
+          name: "pubkey",
+          writable: true,
+          signer: true,
         },
       ],
       args: [
         {
-          name: "lamports",
+          name: "space",
           type: "u64",
         },
       ],
     },
     {
-      name: "createAccountWithSeed",
+      name: "allocateWithSeed",
+      discriminator: [9, 0, 0, 0],
       accounts: [
         {
-          name: "from",
-          isMut: true,
-          isSigner: true,
-        },
-        {
-          name: "to",
-          isMut: true,
-          isSigner: false,
+          name: "account",
+          writable: true,
         },
         {
           name: "base",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [
         {
           name: "base",
-          type: "publicKey",
+          type: "pubkey",
         },
         {
           name: "seed",
           type: "string",
         },
-        {
-          name: "lamports",
-          type: "u64",
-        },
         {
           name: "space",
           type: "u64",
         },
         {
           name: "owner",
-          type: "publicKey",
+          type: "pubkey",
         },
       ],
     },
     {
-      name: "advanceNonceAccount",
+      name: "assign",
+      discriminator: [1, 0, 0, 0],
       accounts: [
         {
-          name: "nonce",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "recentBlockhashes",
-          isMut: false,
-          isSigner: false,
-        },
-        {
-          name: "authorized",
-          isMut: false,
-          isSigner: true,
+          name: "pubkey",
+          writable: true,
+          signer: true,
         },
       ],
       args: [
         {
-          name: "authorized",
-          type: "publicKey",
+          name: "owner",
+          type: "pubkey",
         },
       ],
     },
     {
-      name: "withdrawNonceAccount",
+      name: "assignWithSeed",
+      discriminator: [10, 0, 0, 0],
       accounts: [
         {
-          name: "nonce",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "to",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "recentBlockhashes",
-          isMut: false,
-          isSigner: false,
-        },
-        {
-          name: "rent",
-          isMut: false,
-          isSigner: false,
+          name: "account",
+          writable: true,
         },
         {
-          name: "authorized",
-          isMut: false,
-          isSigner: true,
+          name: "base",
+          signer: true,
         },
       ],
       args: [
         {
-          name: "lamports",
-          type: "u64",
-        },
-      ],
-    },
-    {
-      name: "initializeNonceAccount",
-      accounts: [
-        {
-          name: "nonce",
-          isMut: true,
-          isSigner: true,
-        },
-        {
-          name: "recentBlockhashes",
-          isMut: false,
-          isSigner: false,
+          name: "base",
+          type: "pubkey",
         },
         {
-          name: "rent",
-          isMut: false,
-          isSigner: false,
+          name: "seed",
+          type: "string",
         },
-      ],
-      args: [
         {
-          name: "authorized",
-          type: "publicKey",
+          name: "owner",
+          type: "pubkey",
         },
       ],
     },
     {
       name: "authorizeNonceAccount",
+      discriminator: [7, 0, 0, 0],
       accounts: [
         {
           name: "nonce",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "authorized",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [
         {
           name: "authorized",
-          type: "publicKey",
+          type: "pubkey",
         },
       ],
     },
     {
-      name: "allocate",
+      name: "createAccount",
+      discriminator: [0, 0, 0, 0],
       accounts: [
         {
-          name: "pubkey",
-          isMut: true,
-          isSigner: true,
+          name: "from",
+          writable: true,
+          signer: true,
+        },
+        {
+          name: "to",
+          writable: true,
+          signer: true,
         },
       ],
       args: [
+        {
+          name: "lamports",
+          type: "u64",
+        },
         {
           name: "space",
           type: "u64",
         },
+        {
+          name: "owner",
+          type: "pubkey",
+        },
       ],
     },
     {
-      name: "allocateWithSeed",
+      name: "createAccountWithSeed",
+      discriminator: [3, 0, 0, 0],
       accounts: [
         {
-          name: "account",
-          isMut: true,
-          isSigner: false,
+          name: "from",
+          writable: true,
+          signer: true,
+        },
+        {
+          name: "to",
+          writable: true,
         },
         {
           name: "base",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [
         {
           name: "base",
-          type: "publicKey",
+          type: "pubkey",
         },
         {
           name: "seed",
           type: "string",
         },
+        {
+          name: "lamports",
+          type: "u64",
+        },
         {
           name: "space",
           type: "u64",
         },
         {
           name: "owner",
-          type: "publicKey",
+          type: "pubkey",
         },
       ],
     },
     {
-      name: "assignWithSeed",
+      name: "initializeNonceAccount",
+      discriminator: [6, 0, 0, 0],
       accounts: [
         {
-          name: "account",
-          isMut: true,
-          isSigner: false,
+          name: "nonce",
+          writable: true,
+          signer: true,
         },
         {
-          name: "base",
-          isMut: false,
-          isSigner: true,
+          name: "recentBlockhashes",
+        },
+        {
+          name: "rent",
+          address: "SysvarRent111111111111111111111111111111111",
         },
       ],
       args: [
         {
-          name: "base",
-          type: "publicKey",
+          name: "authorized",
+          type: "pubkey",
         },
+      ],
+    },
+    {
+      name: "transfer",
+      discriminator: [2, 0, 0, 0],
+      accounts: [
         {
-          name: "seed",
-          type: "string",
+          name: "from",
+          writable: true,
+          signer: true,
         },
         {
-          name: "owner",
-          type: "publicKey",
+          name: "to",
+          writable: true,
+        },
+      ],
+      args: [
+        {
+          name: "lamports",
+          type: "u64",
         },
       ],
     },
     {
       name: "transferWithSeed",
+      discriminator: [11, 0, 0, 0],
       accounts: [
         {
           name: "from",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "base",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
         {
           name: "to",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
       ],
       args: [
@@ -727,12 +686,61 @@ export const IDL: SystemProgram = {
         },
         {
           name: "owner",
-          type: "publicKey",
+          type: "pubkey",
+        },
+      ],
+    },
+    {
+      name: "withdrawNonceAccount",
+      discriminator: [5, 0, 0, 0],
+      accounts: [
+        {
+          name: "nonce",
+          writable: true,
+        },
+        {
+          name: "to",
+          writable: true,
+        },
+        {
+          name: "recentBlockhashes",
+        },
+        {
+          name: "rent",
+          address: "SysvarRent111111111111111111111111111111111",
+        },
+        {
+          name: "authorized",
+          signer: true,
+        },
+      ],
+      args: [
+        {
+          name: "lamports",
+          type: "u64",
         },
       ],
     },
   ],
   accounts: [
+    {
+      name: "nonce",
+      discriminator: [],
+    },
+  ],
+  types: [
+    {
+      name: "feeCalculator",
+      type: {
+        kind: "struct",
+        fields: [
+          {
+            name: "lamportsPerSignature",
+            type: "u64",
+          },
+        ],
+      },
+    },
     {
       name: "nonce",
       type: {
@@ -748,34 +756,22 @@ export const IDL: SystemProgram = {
           },
           {
             name: "authorizedPubkey",
-            type: "publicKey",
+            type: "pubkey",
           },
           {
             name: "nonce",
-            type: "publicKey",
+            type: "pubkey",
           },
           {
             name: "feeCalculator",
             type: {
-              defined: "FeeCalculator",
+              defined: {
+                name: "feeCalculator",
+              },
             },
           },
         ],
       },
     },
   ],
-  types: [
-    {
-      name: "FeeCalculator",
-      type: {
-        kind: "struct",
-        fields: [
-          {
-            name: "lamportsPerSignature",
-            type: "u64",
-          },
-        ],
-      },
-    },
-  ],
 };
diff --git a/ts/packages/anchor/src/program/accounts-resolver.ts b/ts/packages/anchor/src/program/accounts-resolver.ts
index 0bf4be87b1..0b12784b31 100644
--- a/ts/packages/anchor/src/program/accounts-resolver.ts
+++ b/ts/packages/anchor/src/program/accounts-resolver.ts
@@ -1,36 +1,30 @@
-import camelCase from "camelcase";
-import {
-  PublicKey,
-  SystemProgram,
-  SYSVAR_CLOCK_PUBKEY,
-  SYSVAR_RENT_PUBKEY,
-} from "@solana/web3.js";
+import BN from "bn.js";
+import { PublicKey } from "@solana/web3.js";
 import {
   Idl,
   IdlSeed,
-  IdlAccount,
-  IdlAccountItem,
-  IdlAccounts,
+  IdlInstructionAccountItem,
+  IdlInstructionAccount,
   IdlTypeDef,
   IdlTypeDefTyStruct,
   IdlType,
-  isIdlAccounts,
+  isCompositeAccounts,
   IdlSeedConst,
   IdlSeedArg,
   IdlSeedAccount,
+  IdlTypeDefined,
+  IdlDefinedFieldsNamed,
 } from "../idl.js";
-import * as utf8 from "../utils/bytes/utf8.js";
-import { TOKEN_PROGRAM_ID, ASSOCIATED_PROGRAM_ID } from "../utils/token.js";
 import { AllInstructions } from "./namespace/types.js";
 import Provider from "../provider.js";
 import { AccountNamespace } from "./namespace/account.js";
 import { BorshAccountsCoder } from "src/coder/index.js";
 import { decodeTokenAccount } from "./token-account-layout";
-import { Program, translateAddress } from "./index.js";
+import { Address, Program, translateAddress } from "./index.js";
 import {
+  PartialAccounts,
   flattenPartialAccounts,
   isPartialAccounts,
-  PartialAccounts,
 } from "./namespace/methods";
 
 export type AccountsGeneric = {
@@ -53,88 +47,101 @@ export type CustomAccountResolver = (params: {
 
 // Populates a given accounts context with PDAs and common missing accounts.
 export class AccountsResolver {
-  _args: Array;
-  static readonly CONST_ACCOUNTS = {
-    associatedTokenProgram: ASSOCIATED_PROGRAM_ID,
-    rent: SYSVAR_RENT_PUBKEY,
-    systemProgram: SystemProgram.programId,
-    tokenProgram: TOKEN_PROGRAM_ID,
-    clock: SYSVAR_CLOCK_PUBKEY,
-  };
-
   private _accountStore: AccountStore;
 
   constructor(
-    _args: Array,
+    private _args: any[],
     private _accounts: AccountsGeneric,
     private _provider: Provider,
     private _programId: PublicKey,
     private _idlIx: AllInstructions,
-    _accountNamespace: AccountNamespace,
+    accountNamespace: AccountNamespace,
     private _idlTypes: IdlTypeDef[],
     private _customResolver?: CustomAccountResolver
   ) {
-    this._args = _args;
     this._accountStore = new AccountStore(
       _provider,
-      _accountNamespace,
-      this._programId
+      accountNamespace,
+      _programId
     );
   }
 
-  public args(_args: Array): void {
-    this._args = _args;
+  public args(args: Array): void {
+    this._args = args;
   }
 
   // Note: We serially resolve PDAs one by one rather than doing them
   //       in parallel because there can be dependencies between
   //       addresses. That is, one PDA can be used as a seed in another.
   public async resolve() {
-    await this.resolveConst(this._idlIx.accounts);
-    this._resolveEventCpi(this._idlIx.accounts);
+    this.resolveEventCpi(this._idlIx.accounts);
+    this.resolveConst(this._idlIx.accounts);
 
     // Auto populate pdas and relations until we stop finding new accounts
+    let depth = 0;
     while (
-      (await this.resolvePdas(this._idlIx.accounts)) +
-        (await this.resolveRelations(this._idlIx.accounts)) +
+      (await this.resolvePdasAndRelations(this._idlIx.accounts)) +
         (await this.resolveCustom()) >
       0
-    ) {}
+    ) {
+      depth++;
+      if (depth === 16) {
+        throw new Error("Reached maximum depth for account resolution");
+      }
+    }
   }
 
-  private async resolveCustom(): Promise {
-    if (this._customResolver) {
-      const { accounts, resolved } = await this._customResolver({
-        args: this._args,
-        accounts: this._accounts,
-        provider: this._provider,
-        programId: this._programId,
-        idlIx: this._idlIx,
-      });
-      this._accounts = accounts;
-      return resolved;
+  public resolveOptionals(accounts: PartialAccounts) {
+    Object.assign(
+      this._accounts,
+      this.resolveOptionalsHelper(accounts, this._idlIx.accounts)
+    );
+  }
+
+  private get(path: string[]): PublicKey | undefined {
+    // Only return if pubkey
+    const ret = path.reduce(
+      (acc, subPath) => acc && acc[subPath],
+      this._accounts
+    );
+
+    if (ret && ret.toBase58) {
+      return ret as PublicKey;
     }
-    return 0;
+  }
+
+  private set(path: string[], value: PublicKey): void {
+    let cur = this._accounts;
+    path.forEach((p, i) => {
+      const isLast = i === path.length - 1;
+      if (isLast) {
+        cur[p] = value;
+      }
+
+      cur[p] = cur[p] ?? {};
+      cur = cur[p] as AccountsGeneric;
+    });
   }
 
   private resolveOptionalsHelper(
     partialAccounts: PartialAccounts,
-    accountItems: IdlAccountItem[]
+    accounts: IdlInstructionAccountItem[]
   ): AccountsGeneric {
     const nestedAccountsGeneric: AccountsGeneric = {};
     // Looping through accountItem array instead of on partialAccounts, so
     // we only traverse array once
-    for (const accountItem of accountItems) {
+    for (const accountItem of accounts) {
       const accountName = accountItem.name;
       const partialAccount = partialAccounts[accountName];
       // Skip if the account isn't included (thus would be undefined)
       if (partialAccount === undefined) continue;
+
       if (isPartialAccounts(partialAccount)) {
         // is compound accounts, recurse one level deeper
-        if (isIdlAccounts(accountItem)) {
+        if (isCompositeAccounts(accountItem)) {
           nestedAccountsGeneric[accountName] = this.resolveOptionalsHelper(
             partialAccount,
-            accountItem["accounts"] as IdlAccountItem[]
+            accountItem["accounts"]
           );
         } else {
           // Here we try our best to recover gracefully. If there are optionals we can't check, we will fail then.
@@ -146,8 +153,10 @@ export class AccountsResolver {
       } else {
         // if not compound accounts, do null/optional check and proceed
         if (partialAccount !== null) {
-          nestedAccountsGeneric[accountName] = translateAddress(partialAccount);
-        } else if (accountItem["isOptional"]) {
+          nestedAccountsGeneric[accountName] = translateAddress(
+            partialAccount as Address
+          );
+        } else if (accountItem["optional"]) {
           nestedAccountsGeneric[accountName] = this._programId;
         }
       }
@@ -155,78 +164,20 @@ export class AccountsResolver {
     return nestedAccountsGeneric;
   }
 
-  public resolveOptionals(accounts: PartialAccounts) {
-    Object.assign(
-      this._accounts,
-      this.resolveOptionalsHelper(accounts, this._idlIx.accounts)
-    );
-  }
-
-  private get(path: string[]): PublicKey | undefined {
-    // Only return if pubkey
-    const ret = path.reduce(
-      (acc, subPath) => acc && acc[subPath],
-      this._accounts
-    );
-
-    if (ret && ret.toBase58) {
-      return ret as PublicKey;
+  private async resolveCustom() {
+    if (this._customResolver) {
+      const { accounts, resolved } = await this._customResolver({
+        args: this._args,
+        accounts: this._accounts,
+        provider: this._provider,
+        programId: this._programId,
+        idlIx: this._idlIx,
+      });
+      this._accounts = accounts;
+      return resolved;
     }
-  }
-
-  private set(path: string[], value: PublicKey): void {
-    let curr = this._accounts;
-    path.forEach((p, idx) => {
-      const isLast = idx == path.length - 1;
-      if (isLast) {
-        curr[p] = value;
-      }
-
-      curr[p] = curr[p] || {};
-      curr = curr[p] as AccountsGeneric;
-    });
-  }
 
-  private async resolveConst(
-    accounts: IdlAccountItem[],
-    path: string[] = []
-  ): Promise {
-    for (let k = 0; k < accounts.length; k += 1) {
-      const accountDescOrAccounts = accounts[k];
-      const subAccounts = (accountDescOrAccounts as IdlAccounts).accounts;
-      if (subAccounts) {
-        await this.resolveConst(subAccounts, [
-          ...path,
-          camelCase(accountDescOrAccounts.name),
-        ]);
-      }
-
-      const accountDesc = accountDescOrAccounts as IdlAccount;
-      const accountDescName = camelCase(accountDescOrAccounts.name);
-
-      // Signers default to the provider.
-      if (accountDesc.isSigner && !this.get([...path, accountDescName])) {
-        // @ts-expect-error
-        if (this._provider.wallet === undefined) {
-          throw new Error(
-            "This function requires the Provider interface implementor to have a 'wallet' field."
-          );
-        }
-        // @ts-expect-error
-        this.set([...path, accountDescName], this._provider.wallet.publicKey);
-      }
-
-      // Common accounts are auto populated with magic names by convention.
-      if (
-        Reflect.has(AccountsResolver.CONST_ACCOUNTS, accountDescName) &&
-        !this.get([...path, accountDescName])
-      ) {
-        this.set(
-          [...path, accountDescName],
-          AccountsResolver.CONST_ACCOUNTS[accountDescName]
-        );
-      }
-    }
+    return 0;
   }
 
   /**
@@ -235,17 +186,16 @@ export class AccountsResolver {
    * Accounts will only be resolved if they are declared next to each other to
    * reduce the chance of name collision.
    */
-  private _resolveEventCpi(
-    accounts: IdlAccountItem[],
+  private resolveEventCpi(
+    accounts: IdlInstructionAccountItem[],
     path: string[] = []
   ): void {
     for (const i in accounts) {
-      const accountDescOrAccounts = accounts[i];
-      const subAccounts = (accountDescOrAccounts as IdlAccounts).accounts;
-      if (subAccounts) {
-        this._resolveEventCpi(subAccounts, [
+      const accountOrAccounts = accounts[i];
+      if (isCompositeAccounts(accountOrAccounts)) {
+        this.resolveEventCpi(accountOrAccounts.accounts, [
           ...path,
-          camelCase(accountDescOrAccounts.name),
+          accountOrAccounts.name,
         ]);
       }
 
@@ -253,8 +203,8 @@ export class AccountsResolver {
       const nextIndex = +i + 1;
       if (nextIndex === accounts.length) return;
 
-      const currentName = camelCase(accounts[i].name);
-      const nextName = camelCase(accounts[nextIndex].name);
+      const currentName = accounts[i].name;
+      const nextName = accounts[nextIndex].name;
 
       // Populate event CPI accounts if they exist
       if (currentName === "eventAuthority" && nextName === "program") {
@@ -279,364 +229,338 @@ export class AccountsResolver {
     }
   }
 
-  private async resolvePdas(
-    accounts: IdlAccountItem[],
+  private resolveConst(
+    accounts: IdlInstructionAccountItem[],
     path: string[] = []
-  ): Promise {
-    let found = 0;
-    for (let k = 0; k < accounts.length; k += 1) {
-      const accountDesc = accounts[k];
-      const subAccounts = (accountDesc as IdlAccounts).accounts;
-      if (subAccounts) {
-        found += await this.resolvePdas(subAccounts, [
-          ...path,
-          camelCase(accountDesc.name),
-        ]);
-      }
+  ) {
+    for (const accountOrAccounts of accounts) {
+      const name = accountOrAccounts.name;
+      if (isCompositeAccounts(accountOrAccounts)) {
+        this.resolveConst(accountOrAccounts.accounts, [...path, name]);
+      } else {
+        const account = accountOrAccounts;
+
+        if ((account.signer || account.address) && !this.get([...path, name])) {
+          // Default signers to the provider
+          if (account.signer) {
+            if (!this._provider.wallet) {
+              throw new Error(
+                "This function requires the `Provider` interface implementor to have a `wallet` field."
+              );
+            }
+            this.set([...path, name], this._provider.wallet.publicKey);
+          }
 
-      const accountDescCasted: IdlAccount = accountDesc as IdlAccount;
-      const accountDescName = camelCase(accountDesc.name);
-
-      // PDA derived from IDL seeds.
-      if (
-        accountDescCasted.pda &&
-        accountDescCasted.pda.seeds.length > 0 &&
-        !this.get([...path, accountDescName])
-      ) {
-        if (Boolean(await this.autoPopulatePda(accountDescCasted, path))) {
-          found += 1;
+          // Set based on `address` field
+          if (account.address) {
+            this.set([...path, name], translateAddress(account.address));
+          }
         }
       }
     }
-    return found;
   }
 
-  private async resolveRelations(
-    accounts: IdlAccountItem[],
+  private async resolvePdasAndRelations(
+    accounts: IdlInstructionAccountItem[],
     path: string[] = []
   ): Promise {
     let found = 0;
-    for (let k = 0; k < accounts.length; k += 1) {
-      const accountDesc = accounts[k];
-      const subAccounts = (accountDesc as IdlAccounts).accounts;
-      if (subAccounts) {
-        found += await this.resolveRelations(subAccounts, [
-          ...path,
-          camelCase(accountDesc.name),
-        ]);
-      }
-      const relations = (accountDesc as IdlAccount).relations || [];
-      const accountDescName = camelCase(accountDesc.name);
-      const newPath = [...path, accountDescName];
-
-      // If we have this account and there's some missing accounts that are relations to this account, fetch them
-      const accountKey = this.get(newPath);
-      if (accountKey) {
-        const matching = relations.filter(
-          (rel) => !this.get([...path, camelCase(rel)])
+    for (const accountOrAccounts of accounts) {
+      const name = accountOrAccounts.name;
+      if (isCompositeAccounts(accountOrAccounts)) {
+        found += await this.resolvePdasAndRelations(
+          accountOrAccounts.accounts,
+          [...path, name]
         );
-
-        found += matching.length;
-        if (matching.length > 0) {
-          const account = await this._accountStore.fetchAccount({
-            publicKey: accountKey,
-          });
-          await Promise.all(
-            matching.map(async (rel) => {
-              const relName = camelCase(rel);
-
-              this.set([...path, relName], account[relName]);
-              return account[relName];
-            })
-          );
+      } else {
+        const account = accountOrAccounts;
+        if ((account.pda || account.relations) && !this.get([...path, name])) {
+          found++;
+
+          // Accounts might not get resolved successfully if a seed depends on
+          // another seed to be resolved *and* the accounts for resolution are
+          // out of order. In this case, skip the accounts that throw in order
+          // to resolve those accounts later.
+          try {
+            if (account.pda) {
+              const seeds = await Promise.all(
+                account.pda.seeds.map((seed) => this.toBuffer(seed, path))
+              );
+              if (seeds.some((seed) => !seed)) {
+                continue;
+              }
+
+              const programId = await this.parseProgramId(account, path);
+              const [pubkey] = PublicKey.findProgramAddressSync(
+                seeds as Buffer[],
+                programId
+              );
+
+              this.set([...path, name], pubkey);
+            }
+          } catch {}
+
+          try {
+            if (account.relations) {
+              const accountKey = this.get([...path, account.relations[0]]);
+              if (accountKey) {
+                const account = await this._accountStore.fetchAccount({
+                  publicKey: accountKey,
+                });
+                this.set([...path, name], account[name]);
+              }
+            }
+          } catch {}
         }
       }
     }
-    return found;
-  }
-
-  private async autoPopulatePda(accountDesc: IdlAccount, path: string[] = []) {
-    if (!accountDesc.pda || !accountDesc.pda.seeds)
-      throw new Error("Must have seeds");
-
-    const seeds: (Buffer | undefined)[] = await Promise.all(
-      accountDesc.pda.seeds.map((seedDesc: IdlSeed) =>
-        this.toBuffer(seedDesc, path)
-      )
-    );
-
-    if (seeds.some((seed) => typeof seed == "undefined")) {
-      return;
-    }
 
-    const programId = await this.parseProgramId(accountDesc, path);
-    if (!programId) {
-      return;
-    }
-    const [pubkey] = await PublicKey.findProgramAddress(
-      seeds as Buffer[],
-      programId
-    );
-
-    this.set([...path, camelCase(accountDesc.name)], pubkey);
+    return found;
   }
 
   private async parseProgramId(
-    accountDesc: IdlAccount,
+    account: IdlInstructionAccount,
     path: string[] = []
   ): Promise {
-    if (!accountDesc.pda?.programId) {
+    if (!account.pda?.program) {
       return this._programId;
     }
 
-    switch (accountDesc.pda.programId.kind) {
-      case "const":
-        return new PublicKey(
-          this.toBufferConst(accountDesc.pda.programId.value)
-        );
-      case "arg":
-        return this.argValue(accountDesc.pda.programId);
-      case "account":
-        return await this.accountValue(accountDesc.pda.programId, path);
-      default:
-        throw new Error(
-          `Unexpected program seed: ${accountDesc.pda.programId}`
-        );
+    const buf = await this.toBuffer(account.pda.program, path);
+    if (!buf) {
+      throw new Error(`Program seed not resolved: ${account.name}`);
     }
+
+    return new PublicKey(buf);
   }
 
   private async toBuffer(
-    seedDesc: IdlSeed,
+    seed: IdlSeed,
     path: string[] = []
   ): Promise {
-    switch (seedDesc.kind) {
+    switch (seed.kind) {
       case "const":
-        return this.toBufferConst(seedDesc);
+        return this.toBufferConst(seed);
       case "arg":
-        return await this.toBufferArg(seedDesc);
+        return await this.toBufferArg(seed);
       case "account":
-        return await this.toBufferAccount(seedDesc, path);
+        return await this.toBufferAccount(seed, path);
       default:
-        throw new Error(`Unexpected seed: ${seedDesc}`);
+        throw new Error(`Unexpected seed: ${seed}`);
     }
   }
 
-  /**
-   * Recursively get the type at some path of either a primitive or a user defined struct.
-   */
-  private getType(type: IdlType, path: string[] = []): string {
-    if (path.length > 0 && (type as any).defined) {
-      const subType = this._idlTypes.find(
-        (t) => t.name === (type as any).defined
-      );
-      if (!subType) {
-        throw new Error(`Cannot find type ${(type as any).defined}`);
-      }
-
-      const structType = subType.type as IdlTypeDefTyStruct; // enum not supported yet
-      const field = structType.fields.find((field) => field.name === path[0]);
-
-      return this.getType(field!.type, path.slice(1));
-    }
-
-    return type as string;
+  private toBufferConst(seed: IdlSeedConst): Buffer {
+    return this.toBufferValue("bytes", seed.value);
   }
 
-  private toBufferConst(seedDesc: IdlSeedConst): Buffer {
-    return this.toBufferValue(this.getType(seedDesc.type), seedDesc.value);
-  }
+  private async toBufferArg(seed: IdlSeedArg): Promise {
+    const [name, ...path] = seed.path.split(".");
 
-  private async toBufferArg(seedDesc: IdlSeedArg): Promise {
-    const argValue = this.argValue(seedDesc);
-    if (typeof argValue === "undefined") {
-      return;
+    const index = this._idlIx.args.findIndex((arg) => arg.name === name);
+    if (index === -1) {
+      throw new Error(`Unable to find argument for seed: ${name}`);
     }
-    return this.toBufferValue(
-      this.getType(seedDesc.type, (seedDesc.path || "").split(".").slice(1)),
-      argValue
-    );
-  }
-
-  private argValue(seedDesc: IdlSeedArg): any {
-    const split = seedDesc.path.split(".");
-    const seedArgName = camelCase(split[0]);
 
-    const idlArgPosition = this._idlIx.args.findIndex(
-      (argDesc: any) => argDesc.name === seedArgName
+    const value = path.reduce(
+      (acc, path) => (acc ?? {})[path],
+      this._args[index]
     );
-    if (idlArgPosition === -1) {
-      throw new Error(`Unable to find argument for seed: ${seedArgName}`);
+    if (value === undefined) {
+      return;
     }
 
-    return split
-      .slice(1)
-      .reduce((curr, path) => (curr || {})[path], this._args[idlArgPosition]);
+    const type = this.getType(this._idlIx.args[index].type, path);
+    return this.toBufferValue(type, value);
   }
 
   private async toBufferAccount(
-    seedDesc: IdlSeedAccount,
+    seed: IdlSeedAccount,
     path: string[] = []
   ): Promise {
-    const accountValue = await this.accountValue(seedDesc, path);
-    if (!accountValue) {
-      return;
-    }
-    return this.toBufferValue(seedDesc.type, accountValue);
-  }
-
-  private async accountValue(
-    seedDesc: IdlSeedAccount,
-    path: string[] = []
-  ): Promise {
-    const pathComponents = seedDesc.path.split(".");
-
-    const fieldName = pathComponents[0];
-    const fieldPubkey = this.get([...path, camelCase(fieldName)]);
+    const [name, ...paths] = seed.path.split(".");
+    const fieldPubkey = this.get([...path, name]);
+    if (!fieldPubkey) return;
 
-    if (fieldPubkey === null) {
-      throw new Error(`fieldPubkey is null`);
+    // The seed is a pubkey of the account.
+    if (!paths.length) {
+      return this.toBufferValue("pubkey", fieldPubkey);
     }
 
-    // The seed is a pubkey of the account.
-    if (pathComponents.length === 1) {
-      return fieldPubkey;
+    if (!seed.account) {
+      throw new Error(
+        `Seed account is required in order to resolve type: ${seed.path}`
+      );
     }
 
     // The key is account data.
     //
     // Fetch and deserialize it.
     const account = await this._accountStore.fetchAccount({
-      publicKey: fieldPubkey as PublicKey,
-      name: seedDesc.account,
+      publicKey: fieldPubkey,
+      name: seed.account,
     });
 
     // Dereference all fields in the path to get the field value
     // used in the seed.
-    const fieldValue = this.parseAccountValue(account, pathComponents.slice(1));
-    return fieldValue;
-  }
-
-  private parseAccountValue(account: T, path: Array): any {
-    let accountField: any;
-    while (path.length > 0) {
-      accountField = account[camelCase(path[0])];
-      path = path.slice(1);
+    let accountValue = account;
+    let currentPaths = paths;
+    while (currentPaths.length > 0) {
+      accountValue = accountValue[currentPaths[0]];
+      currentPaths = currentPaths.slice(1);
     }
-    return accountField;
+    if (accountValue === undefined) return;
+
+    const type = this.getType({ defined: { name: seed.account } }, paths);
+    return this.toBufferValue(type, accountValue);
   }
 
-  // Converts the given idl valaue into a Buffer. The values here must be
-  // primitives. E.g. no structs.
-  //
-  // TODO: add more types here as needed.
-  private toBufferValue(type: string | any, value: any): Buffer {
+  /**
+   * Converts the given idl valaue into a Buffer. The values here must be
+   * primitives, e.g. no structs.
+   */
+  private toBufferValue(type: any, value: any): Buffer {
     switch (type) {
       case "u8":
+      case "i8":
         return Buffer.from([value]);
       case "u16":
-        let b = Buffer.alloc(2);
-        b.writeUInt16LE(value);
-        return b;
+      case "i16":
+        return new BN(value).toArrayLike(Buffer, "le", 2);
       case "u32":
-        let buf = Buffer.alloc(4);
-        buf.writeUInt32LE(value);
-        return buf;
+      case "i32":
+        return new BN(value).toArrayLike(Buffer, "le", 4);
       case "u64":
-        let bU64 = Buffer.alloc(8);
-        bU64.writeBigUInt64LE(BigInt(value));
-        return bU64;
+      case "i64":
+        return new BN(value).toArrayLike(Buffer, "le", 8);
+      case "u128":
+      case "i128":
+        return new BN(value).toArrayLike(Buffer, "le", 16);
+      case "u256":
+      case "i256":
+        return new BN(value).toArrayLike(Buffer, "le", 32);
       case "string":
-        return Buffer.from(utf8.encode(value));
-      case "publicKey":
+        return Buffer.from(value);
+      case "pubkey":
         return value.toBuffer();
+      case "bytes":
+        return Buffer.from(value);
       default:
-        if (type.array) {
+        if (type?.array) {
           return Buffer.from(value);
         }
+
         throw new Error(`Unexpected seed type: ${type}`);
     }
   }
+
+  /**
+   * Recursively get the type at some path of either a primitive or a user
+   * defined struct.
+   */
+  private getType(
+    type: IdlType,
+    path: string[] = []
+  ): Extract {
+    const typeName = (type as IdlTypeDefined)?.defined?.name;
+    if (typeName) {
+      // Handle token account separately
+      if (typeName === "tokenAccount") {
+        switch (path.at(0)) {
+          case "mint":
+          case "owner":
+            return "pubkey";
+          case "amount":
+          case "delagatedAmount":
+            return "u64";
+          default:
+            throw new Error(`Unknown token account path: ${path}`);
+        }
+      }
+
+      const definedType = this._idlTypes.find((t) => t.name === typeName);
+      if (!definedType) {
+        throw new Error(`Type not found: ${typeName}`);
+      }
+
+      // Only named structs are supported
+      const [fieldName, ...subPath] = path;
+      const fields = (definedType.type as IdlTypeDefTyStruct)
+        .fields as IdlDefinedFieldsNamed;
+      const field = fields.find((field) => field.name === fieldName);
+      if (!field) {
+        throw new Error(`Field not found: ${fieldName}`);
+      }
+
+      return this.getType(field.type, subPath);
+    }
+
+    return type as Extract;
+  }
 }
 
-// TODO: this should be configureable to avoid unnecessary requests.
-export class AccountStore {
+// TODO: this should be configurable to avoid unnecessary requests.
+class AccountStore {
   private _cache = new Map();
   private _idls: Record> = {};
 
-  // todo: don't use the progrma use the account namespace.
   constructor(
     private _provider: Provider,
-    _accounts: AccountNamespace,
-    private _programId: PublicKey
-  ) {
-    this._idls[_programId.toBase58()] = _accounts;
-  }
-
-  private async ensureIdl(
+    accounts: AccountNamespace,
     programId: PublicKey
-  ): Promise | undefined> {
-    if (!this._idls[programId.toBase58()]) {
-      const idl = await Program.fetchIdl(programId, this._provider);
-      if (idl) {
-        const program = new Program(idl, programId, this._provider);
-        this._idls[programId.toBase58()] = program.account;
-      }
-    }
-
-    return this._idls[programId.toBase58()];
+  ) {
+    this._idls[programId.toBase58()] = accounts;
   }
 
   public async fetchAccount({
     publicKey,
     name,
-    programId = this._programId,
   }: {
     publicKey: PublicKey;
     name?: string;
     programId?: PublicKey;
   }): Promise {
-    const address = publicKey.toString();
+    const address = publicKey.toBase58();
     if (!this._cache.has(address)) {
-      if (name === "TokenAccount") {
-        const accountInfo = await this._provider.connection.getAccountInfo(
-          publicKey
-        );
-        if (accountInfo === null) {
-          throw new Error(`invalid account info for ${address}`);
-        }
-        const data = decodeTokenAccount(accountInfo.data);
-        this._cache.set(address, data);
-      } else if (name) {
-        const accounts = await this.ensureIdl(programId);
-        if (accounts) {
-          const accountFetcher = accounts[camelCase(name)];
-          if (accountFetcher) {
-            const account = await accountFetcher.fetch(publicKey);
-            this._cache.set(address, account);
-          }
-        }
+      const accountInfo = await this._provider.connection.getAccountInfo(
+        publicKey
+      );
+      if (accountInfo === null) {
+        throw new Error(`Account not found: ${address}`);
+      }
+
+      if (name === "tokenAccount") {
+        const account = decodeTokenAccount(accountInfo.data);
+        this._cache.set(address, account);
       } else {
-        const account = await this._provider.connection.getAccountInfo(
-          publicKey
-        );
-        if (account === null) {
-          throw new Error(`invalid account info for ${address}`);
-        }
-        const data = account.data;
-        const accounts = await this.ensureIdl(account.owner);
+        const accounts = await this.getAccountsNs(accountInfo.owner);
         if (accounts) {
-          const firstAccountLayout = Object.values(accounts)[0] as any;
-          if (!firstAccountLayout) {
-            throw new Error("No accounts for this program");
+          const accountNs = Object.values(accounts)[0] as any;
+          if (accountNs) {
+            const account = (
+              accountNs.coder.accounts as BorshAccountsCoder
+            ).decodeAny(accountInfo.data);
+            this._cache.set(address, account);
           }
-
-          const result = (
-            firstAccountLayout.coder.accounts as BorshAccountsCoder
-          ).decodeAny(data);
-          this._cache.set(address, result);
         }
       }
     }
+
     return this._cache.get(address);
   }
+
+  private async getAccountsNs(
+    programId: PublicKey
+  ): Promise | undefined> {
+    const programIdStr = programId.toBase58();
+    if (!this._idls[programIdStr]) {
+      const idl = await Program.fetchIdl(programId, this._provider);
+      if (idl) {
+        const program = new Program(idl, this._provider);
+        this._idls[programIdStr] = program.account;
+      }
+    }
+
+    return this._idls[programIdStr];
+  }
 }
diff --git a/ts/packages/anchor/src/program/common.ts b/ts/packages/anchor/src/program/common.ts
index 0023ce3f79..48460ab76f 100644
--- a/ts/packages/anchor/src/program/common.ts
+++ b/ts/packages/anchor/src/program/common.ts
@@ -1,6 +1,11 @@
 import EventEmitter from "eventemitter3";
 import { PublicKey } from "@solana/web3.js";
-import { Idl, IdlInstruction, IdlAccountItem, IdlStateMethod } from "../idl.js";
+import {
+  Idl,
+  IdlInstruction,
+  IdlInstructionAccountItem,
+  isCompositeAccounts,
+} from "../idl.js";
 import { Accounts } from "./context.js";
 
 export type Subscription = {
@@ -19,11 +24,7 @@ export function parseIdlErrors(idl: Idl): Map {
   return errors;
 }
 
-// Allow either IdLInstruction or IdlStateMethod since the types share fields.
-export function toInstruction(
-  idlIx: IdlInstruction | IdlStateMethod,
-  ...args: any[]
-) {
+export function toInstruction(idlIx: IdlInstruction, ...args: any[]) {
   if (idlIx.args.length != args.length) {
     throw new Error("Invalid argument length");
   }
@@ -39,15 +40,15 @@ export function toInstruction(
 
 // Throws error if any account required for the `ix` is not given.
 export function validateAccounts(
-  ixAccounts: IdlAccountItem[],
+  ixAccounts: IdlInstructionAccountItem[],
   accounts: Accounts = {}
 ) {
   ixAccounts.forEach((acc) => {
-    if ("accounts" in acc) {
+    if (isCompositeAccounts(acc)) {
       validateAccounts(acc.accounts, accounts[acc.name] as Accounts);
     } else {
-      if (accounts[acc.name] === undefined) {
-        throw new Error(`Invalid arguments: ${acc.name} not provided.`);
+      if (!accounts[acc.name]) {
+        throw new Error(`Account \`${acc.name}\` not provided.`);
       }
     }
   });
diff --git a/ts/packages/anchor/src/program/context.ts b/ts/packages/anchor/src/program/context.ts
index ef1d37fdbb..f7b975cd1d 100644
--- a/ts/packages/anchor/src/program/context.ts
+++ b/ts/packages/anchor/src/program/context.ts
@@ -5,7 +5,11 @@ import {
   TransactionInstruction,
 } from "@solana/web3.js";
 import { Address } from "./common.js";
-import { IdlAccountItem, IdlAccounts, IdlInstruction } from "../idl.js";
+import {
+  IdlInstructionAccountItem,
+  IdlInstructionAccounts,
+  IdlInstruction,
+} from "../idl.js";
 
 /**
  * Context provides all non-argument inputs for generating Anchor transactions.
@@ -50,11 +54,6 @@ export type Context = {
    * Commitment parameters to use for a transaction.
    */
   options?: ConfirmOptions;
-
-  /**
-   * An optional override for the default instruction discriminator.
-   */
-  discriminator?: Buffer;
 };
 
 /**
@@ -66,15 +65,20 @@ export type Context = {
  * If multiple accounts are nested in the rust program, then they should be
  * nested here.
  */
-export type Accounts = {
+export type Accounts<
+  A extends IdlInstructionAccountItem = IdlInstructionAccountItem
+> = {
   [N in A["name"]]: Account;
 };
 
-type Account = A extends IdlAccounts
-  ? Accounts
-  : A extends { isOptional: true }
-  ? Address | null
-  : Address;
+type Account =
+  A extends IdlInstructionAccounts
+    ? Accounts
+    : A extends { optional: true }
+    ? Address | null
+    : A extends { signer: true }
+    ? Address | undefined
+    : Address;
 
 export function splitArgsAndCtx(
   idlIx: IdlInstruction,
diff --git a/ts/packages/anchor/src/program/event.ts b/ts/packages/anchor/src/program/event.ts
index 6c8888627a..b10a2746d1 100644
--- a/ts/packages/anchor/src/program/event.ts
+++ b/ts/packages/anchor/src/program/event.ts
@@ -1,8 +1,8 @@
-import { PublicKey } from "@solana/web3.js";
-import { IdlEvent, IdlEventField } from "../idl.js";
+import { Commitment, PublicKey } from "@solana/web3.js";
 import { Coder } from "../coder/index.js";
-import { DecodeType } from "./namespace/types.js";
+import { IdlEvent, IdlField } from "../idl.js";
 import Provider from "../provider.js";
+import { DecodeType } from "./namespace/types.js";
 
 const PROGRAM_LOG = "Program log: ";
 const PROGRAM_DATA = "Program data: ";
@@ -15,10 +15,12 @@ export type Event<
   Defined = Record
 > = {
   name: E["name"];
-  data: EventData;
+  // TODO:
+  // data: EventData;
+  data: any;
 };
 
-export type EventData = {
+export type EventData = {
   [N in T["name"]]: DecodeType<(T & { name: N })["type"], Defined>;
 };
 
@@ -71,7 +73,8 @@ export class EventManager {
 
   public addEventListener(
     eventName: string,
-    callback: (event: any, slot: number, signature: string) => void
+    callback: (event: any, slot: number, signature: string) => void,
+    commitment?: Commitment
   ): number {
     let listener = this._listenerIdCount;
     this._listenerIdCount += 1;
@@ -114,7 +117,8 @@ export class EventManager {
             });
           }
         }
-      }
+      },
+      commitment
     );
 
     return listener;
diff --git a/ts/packages/anchor/src/program/index.ts b/ts/packages/anchor/src/program/index.ts
index d9722a0aee..f073de9c2f 100644
--- a/ts/packages/anchor/src/program/index.ts
+++ b/ts/packages/anchor/src/program/index.ts
@@ -1,22 +1,28 @@
+import { Commitment, PublicKey } from "@solana/web3.js";
 import { inflate } from "pako";
-import { PublicKey } from "@solana/web3.js";
+import { BorshCoder, Coder } from "../coder/index.js";
+import {
+  Idl,
+  IdlInstruction,
+  convertIdlToCamelCase,
+  decodeIdlAccount,
+  idlAddress,
+} from "../idl.js";
 import Provider, { getProvider } from "../provider.js";
-import { Idl, idlAddress, decodeIdlAccount, IdlInstruction } from "../idl.js";
-import { Coder, BorshCoder } from "../coder/index.js";
+import { utf8 } from "../utils/bytes/index.js";
+import { CustomAccountResolver } from "./accounts-resolver.js";
+import { Address, translateAddress } from "./common.js";
+import { EventManager } from "./event.js";
 import NamespaceFactory, {
-  RpcNamespace,
-  InstructionNamespace,
-  TransactionNamespace,
   AccountNamespace,
-  SimulateNamespace,
+  IdlEvents,
+  InstructionNamespace,
   MethodsNamespace,
+  RpcNamespace,
+  SimulateNamespace,
+  TransactionNamespace,
   ViewNamespace,
-  IdlEvents,
 } from "./namespace/index.js";
-import { utf8 } from "../utils/bytes/index.js";
-import { EventManager } from "./event.js";
-import { Address, translateAddress } from "./common.js";
-import { CustomAccountResolver } from "./accounts-resolver.js";
 
 export * from "./common.js";
 export * from "./context.js";
@@ -224,13 +230,25 @@ export class Program {
   private _programId: PublicKey;
 
   /**
-   * IDL defining the program's interface.
+   * IDL in camelCase format to work in TypeScript.
+   *
+   * See {@link rawIdl} field if you need the original IDL.
    */
   public get idl(): IDL {
     return this._idl;
   }
   private _idl: IDL;
 
+  /**
+   * Raw IDL i.e. the original IDL without camelCase conversion.
+   *
+   * See {@link idl} field if you need the camelCased version of the IDL.
+   */
+  public get rawIdl(): Idl {
+    return this._rawIdl;
+  }
+  private _rawIdl: Idl;
+
   /**
    * Coder for serializing requests.
    */
@@ -254,7 +272,6 @@ export class Program {
 
   /**
    * @param idl       The interface definition.
-   * @param programId The on-chain address of the program.
    * @param provider  The network and wallet context to use. If not provided
    *                  then uses [[getProvider]].
    * @param getCustomResolver A function that returns a custom account resolver
@@ -263,34 +280,30 @@ export class Program {
    */
   public constructor(
     idl: IDL,
-    programId: Address,
-    provider?: Provider,
+    provider: Provider = getProvider(),
     coder?: Coder,
     getCustomResolver?: (
       instruction: IdlInstruction
     ) => CustomAccountResolver | undefined
   ) {
-    programId = translateAddress(programId);
-
-    if (!provider) {
-      provider = getProvider();
-    }
+    const camelCasedIdl = convertIdlToCamelCase(idl);
 
     // Fields.
-    this._idl = idl;
+    this._idl = camelCasedIdl;
+    this._rawIdl = idl;
     this._provider = provider;
-    this._programId = programId;
-    this._coder = coder ?? new BorshCoder(idl);
+    this._programId = translateAddress(idl.address);
+    this._coder = coder ?? new BorshCoder(camelCasedIdl);
     this._events = new EventManager(this._programId, provider, this._coder);
 
     // Dynamic namespaces.
     const [rpc, instruction, transaction, account, simulate, methods, views] =
       NamespaceFactory.build(
-        idl,
+        camelCasedIdl,
         this._coder,
-        programId,
+        this._programId,
         provider,
-        getCustomResolver ?? (() => undefined)
+        getCustomResolver
       );
     this.rpc = rpc;
     this.instruction = instruction;
@@ -321,7 +334,7 @@ export class Program {
       throw new Error(`IDL not found for program: ${address.toString()}`);
     }
 
-    return new Program(idl, programId, provider);
+    return new Program(idl, provider);
   }
 
   /**
@@ -359,14 +372,15 @@ export class Program {
    *                  program logs.
    */
   public addEventListener>(
-    eventName: E,
+    eventName: E & string,
     callback: (
       event: IdlEvents[E],
       slot: number,
       signature: string
-    ) => void
+    ) => void,
+    commitment?: Commitment
   ): number {
-    return this._events.addEventListener(eventName, callback);
+    return this._events.addEventListener(eventName, callback, commitment);
   }
 
   /**
diff --git a/ts/packages/anchor/src/program/namespace/account.ts b/ts/packages/anchor/src/program/namespace/account.ts
index 2adf3f90e2..87e53e155c 100644
--- a/ts/packages/anchor/src/program/namespace/account.ts
+++ b/ts/packages/anchor/src/program/namespace/account.ts
@@ -1,4 +1,3 @@
-import camelCase from "camelcase";
 import EventEmitter from "eventemitter3";
 import {
   Signer,
@@ -12,7 +11,7 @@ import {
   Context,
 } from "@solana/web3.js";
 import Provider, { getProvider } from "../../provider.js";
-import { Idl, IdlAccountDef } from "../../idl.js";
+import { Idl, IdlAccount } from "../../idl.js";
 import { Coder, BorshCoder } from "../../coder/index.js";
 import { Subscription, Address, translateAddress } from "../common.js";
 import { AllAccountsMap, IdlAccounts } from "./types.js";
@@ -25,25 +24,21 @@ export default class AccountFactory {
     programId: PublicKey,
     provider?: Provider
   ): AccountNamespace {
-    const accountFns = {} as AccountNamespace;
-
-    idl.accounts?.forEach((idlAccount) => {
-      const name = camelCase(idlAccount.name);
-      accountFns[name] = new AccountClient(
+    return (idl.accounts ?? []).reduce((accountFns, acc) => {
+      accountFns[acc.name] = new AccountClient(
         idl,
-        idlAccount,
+        acc,
         programId,
         provider,
         coder
       );
-    });
-
-    return accountFns;
+      return accountFns;
+    }, {}) as AccountNamespace;
   }
 }
 
 type NullableIdlAccount = IDL["accounts"] extends undefined
-  ? IdlAccountDef
+  ? IdlAccount
   : NonNullable[number];
 
 /**
@@ -66,15 +61,17 @@ type NullableIdlAccount = IDL["accounts"] extends undefined
  *
  * For the full API, see the [[AccountClient]] reference.
  */
-export type AccountNamespace = {
-  [N in keyof AllAccountsMap]: AccountClient;
+export type AccountNamespace = {
+  [A in keyof AllAccountsMap]: AccountClient;
 };
 
 export class AccountClient<
   IDL extends Idl = Idl,
-  N extends keyof IdlAccounts = keyof IdlAccounts,
-  A extends NullableIdlAccount = NullableIdlAccount,
-  T = IdlAccounts[N]
+  A extends keyof IdlAccounts = keyof IdlAccounts,
+  N extends NullableIdlAccount = NullableIdlAccount,
+  T = IdlAccounts[A] extends Record
+    ? IdlAccounts[A]
+    : never
 > {
   /**
    * Returns the number of bytes in this account.
@@ -108,17 +105,11 @@ export class AccountClient<
   }
   private _coder: Coder;
 
-  /**
-   * Returns the idl account.
-   */
-  get idlAccount(): A {
-    return this._idlAccount;
-  }
-  private _idlAccount: A;
+  private _idlAccount: N;
 
   constructor(
     idl: IDL,
-    idlAccount: A,
+    idlAccount: N,
     programId: PublicKey,
     provider?: Provider,
     coder?: Coder
@@ -127,7 +118,7 @@ export class AccountClient<
     this._programId = programId;
     this._provider = provider ?? getProvider();
     this._coder = coder ?? new BorshCoder(idl);
-    this._size = this._coder.accounts.size(idlAccount);
+    this._size = this._coder.accounts.size(idlAccount.name);
   }
 
   /**
diff --git a/ts/packages/anchor/src/program/namespace/index.ts b/ts/packages/anchor/src/program/namespace/index.ts
index 7cd23d8af6..b294282c61 100644
--- a/ts/packages/anchor/src/program/namespace/index.ts
+++ b/ts/packages/anchor/src/program/namespace/index.ts
@@ -1,4 +1,3 @@
-import camelCase from "camelcase";
 import { PublicKey } from "@solana/web3.js";
 import { Coder } from "../../coder/index.js";
 import Provider from "../../provider.js";
@@ -60,8 +59,7 @@ export default class NamespaceFactory {
     idl.instructions.forEach((idlIx) => {
       const ixItem = InstructionFactory.build(
         idlIx,
-        (ixName, ix, discriminator) =>
-          coder.instruction.encode(ixName, ix, discriminator),
+        (ixName, ix) => coder.instruction.encode(ixName, ix),
         programId
       );
       const txItem = TransactionFactory.build(idlIx, ixItem);
@@ -87,9 +85,9 @@ export default class NamespaceFactory {
         viewItem,
         account,
         idl.types || [],
-        getCustomResolver && getCustomResolver(idlIx)
+        getCustomResolver?.(idlIx)
       );
-      const name = camelCase(idlIx.name);
+      const name = idlIx.name;
 
       instruction[name] = ixItem;
       transaction[name] = txItem;
diff --git a/ts/packages/anchor/src/program/namespace/instruction.ts b/ts/packages/anchor/src/program/namespace/instruction.ts
index 4d19930ac7..fe0a28d03c 100644
--- a/ts/packages/anchor/src/program/namespace/instruction.ts
+++ b/ts/packages/anchor/src/program/namespace/instruction.ts
@@ -5,10 +5,10 @@ import {
 } from "@solana/web3.js";
 import {
   Idl,
-  IdlAccount,
-  IdlAccountItem,
-  IdlAccounts,
+  IdlInstructionAccountItem,
+  IdlInstructionAccounts,
   IdlInstruction,
+  isCompositeAccounts,
 } from "../../idl.js";
 import { IdlError } from "../../error.js";
 import {
@@ -41,7 +41,6 @@ export default class InstructionNamespaceFactory {
       ...args: InstructionContextFnArgs
     ): TransactionInstruction => {
       const [ixArgs, ctx] = splitArgsAndCtx(idlIx, [...args]);
-      const { discriminator } = ctx;
       validateAccounts(idlIx.accounts, ctx.accounts);
       validateInstruction(idlIx, ...args);
 
@@ -58,11 +57,7 @@ export default class InstructionNamespaceFactory {
       return new TransactionInstruction({
         keys,
         programId,
-        data: encodeFn(
-          idlIx.name,
-          toInstruction(idlIx, ...ixArgs),
-          discriminator
-        ),
+        data: encodeFn(idlIx.name, toInstruction(idlIx, ...ixArgs)),
       });
     };
 
@@ -81,7 +76,7 @@ export default class InstructionNamespaceFactory {
 
   public static accountsArray(
     ctx: Accounts | undefined,
-    accounts: readonly IdlAccountItem[],
+    accounts: readonly IdlInstructionAccountItem[],
     programId: PublicKey,
     ixName?: string
   ): AccountMeta[] {
@@ -90,42 +85,38 @@ export default class InstructionNamespaceFactory {
     }
 
     return accounts
-      .map((acc: IdlAccountItem) => {
-        // Nested accounts.
-        const nestedAccounts: IdlAccountItem[] | undefined =
-          "accounts" in acc ? acc.accounts : undefined;
-        if (nestedAccounts !== undefined) {
+      .map((acc) => {
+        if (isCompositeAccounts(acc)) {
           const rpcAccs = ctx[acc.name] as Accounts;
           return InstructionNamespaceFactory.accountsArray(
             rpcAccs,
-            (acc as IdlAccounts).accounts,
+            (acc as IdlInstructionAccounts).accounts,
             programId,
             ixName
           ).flat();
-        } else {
-          const account: IdlAccount = acc as IdlAccount;
-          let pubkey: PublicKey;
-          try {
-            pubkey = translateAddress(ctx[acc.name] as Address);
-          } catch (err) {
-            throw new Error(
-              `Wrong input type for account "${
-                acc.name
-              }" in the instruction accounts object${
-                ixName !== undefined ? ' for instruction "' + ixName + '"' : ""
-              }. Expected PublicKey or string.`
-            );
-          }
-
-          const optional = account.isOptional && pubkey.equals(programId);
-          const isWritable = account.isMut && !optional;
-          const isSigner = account.isSigner && !optional;
-          return {
-            pubkey,
-            isWritable,
-            isSigner,
-          };
         }
+
+        let pubkey: PublicKey;
+        try {
+          pubkey = translateAddress(ctx[acc.name] as Address);
+        } catch (err) {
+          throw new Error(
+            `Wrong input type for account "${
+              acc.name
+            }" in the instruction accounts object${
+              ixName !== undefined ? ' for instruction "' + ixName + '"' : ""
+            }. Expected PublicKey or string.`
+          );
+        }
+
+        const isOptional = acc.optional && pubkey.equals(programId);
+        const isWritable = Boolean(acc.writable && !isOptional);
+        const isSigner = Boolean(acc.signer && !isOptional);
+        return {
+          pubkey,
+          isWritable,
+          isSigner,
+        };
       })
       .flat();
   }
@@ -162,7 +153,7 @@ export default class InstructionNamespaceFactory {
  */
 export type InstructionNamespace<
   IDL extends Idl = Idl,
-  I extends IdlInstruction = IDL["instructions"][number]
+  I extends IdlInstruction = AllInstructions
 > = MakeInstructionsNamespace<
   IDL,
   I,
@@ -196,8 +187,7 @@ type IxProps = {
 
 export type InstructionEncodeFn = (
   ixName: I["name"],
-  ix: any,
-  discriminator?: Buffer
+  ix: any
 ) => Buffer;
 
 // Throws error if any argument required for the `ix` is not given.
diff --git a/ts/packages/anchor/src/program/namespace/methods.ts b/ts/packages/anchor/src/program/namespace/methods.ts
index 7bd5c861fe..64c70ca2f9 100644
--- a/ts/packages/anchor/src/program/namespace/methods.ts
+++ b/ts/packages/anchor/src/program/namespace/methods.ts
@@ -7,7 +7,13 @@ import {
   TransactionInstruction,
   TransactionSignature,
 } from "@solana/web3.js";
-import { Idl, IdlAccountItem, IdlAccounts, IdlTypeDef } from "../../idl.js";
+import {
+  Idl,
+  IdlInstructionAccount,
+  IdlInstructionAccountItem,
+  IdlInstructionAccounts,
+  IdlTypeDef,
+} from "../../idl.js";
 import Provider from "../../provider.js";
 import {
   AccountsGeneric,
@@ -66,19 +72,57 @@ export class MethodsBuilderFactory {
   }
 }
 
-export type PartialAccounts =
-  Partial<{
-    [N in A["name"]]: PartialAccount;
-  }>;
+type ResolvedAccounts<
+  A extends IdlInstructionAccountItem = IdlInstructionAccountItem
+> = PartialUndefined>;
+
+type ResolvedAccountsRecursive<
+  A extends IdlInstructionAccountItem = IdlInstructionAccountItem
+> = OmitNever<{
+  [N in A["name"]]: ResolvedAccount;
+}>;
+
+type ResolvedAccount<
+  A extends IdlInstructionAccountItem = IdlInstructionAccountItem
+> = A extends IdlInstructionAccounts
+  ? ResolvedAccountsRecursive
+  : A extends NonNullable>
+  ? never
+  : A extends NonNullable>
+  ? never
+  : A extends NonNullable>
+  ? never
+  : A extends { signer: true }
+  ? Address | undefined
+  : PartialAccount;
+
+type PartialUndefined<
+  T,
+  P extends keyof T = {
+    [K in keyof T]: undefined extends T[K] ? K : never;
+  }[keyof T]
+> = Partial> & Pick>;
+
+type OmitNever> = {
+  [K in keyof T as T[K] extends never ? never : K]: T[K];
+};
+
+export type PartialAccounts<
+  A extends IdlInstructionAccountItem = IdlInstructionAccountItem
+> = Partial<{
+  [N in A["name"]]: PartialAccount;
+}>;
 
-type PartialAccount = A extends IdlAccounts
+type PartialAccount<
+  A extends IdlInstructionAccountItem = IdlInstructionAccountItem
+> = A extends IdlInstructionAccounts
   ? PartialAccounts
-  : A extends { isOptional: true }
+  : A extends { optional: true }
   ? Address | null
   : Address;
 
 export function isPartialAccounts(
-  partialAccount: PartialAccount
+  partialAccount: any
 ): partialAccount is PartialAccounts {
   return (
     typeof partialAccount === "object" &&
@@ -87,7 +131,7 @@ export function isPartialAccounts(
   );
 }
 
-export function flattenPartialAccounts(
+export function flattenPartialAccounts(
   partialAccounts: PartialAccounts,
   throwOnNull: boolean
 ): AccountsGeneric {
@@ -108,122 +152,136 @@ export function flattenPartialAccounts(
   return toReturn;
 }
 
-type SplInterface =
-  | "spl_transfer_hook_interface::initialize_extra_account_metas"
-  | "spl_transfer_hook_interface::execute";
-
-export class MethodsBuilder> {
-  private readonly _accounts: AccountsGeneric = {};
+export class MethodsBuilder<
+  IDL extends Idl,
+  I extends AllInstructions,
+  A extends I["accounts"][number] = I["accounts"][number]
+> {
+  private _accounts: AccountsGeneric = {};
   private _remainingAccounts: Array = [];
   private _signers: Array = [];
   private _preInstructions: Array = [];
   private _postInstructions: Array = [];
   private _accountsResolver: AccountsResolver;
-  private _autoResolveAccounts: boolean = true;
-  private _args: Array;
-  private _discriminator?: Buffer;
+  private _resolveAccounts: boolean = true;
 
   constructor(
-    _args: Array,
+    private _args: Array,
     private _ixFn: InstructionFn,
     private _txFn: TransactionFn,
     private _rpcFn: RpcFn,
     private _simulateFn: SimulateFn,
     private _viewFn: ViewFn | undefined,
-    _provider: Provider,
-    private _programId: PublicKey,
-    _idlIx: AllInstructions,
-    _accountNamespace: AccountNamespace,
-    _idlTypes: IdlTypeDef[],
-    _customResolver?: CustomAccountResolver
+    provider: Provider,
+    programId: PublicKey,
+    idlIx: AllInstructions,
+    accountNamespace: AccountNamespace,
+    idlTypes: IdlTypeDef[],
+    customResolver?: CustomAccountResolver
   ) {
-    this._args = _args;
     this._accountsResolver = new AccountsResolver(
       _args,
       this._accounts,
-      _provider,
-      _programId,
-      _idlIx,
-      _accountNamespace,
-      _idlTypes,
-      _customResolver
+      provider,
+      programId,
+      idlIx,
+      accountNamespace,
+      idlTypes,
+      customResolver
     );
   }
 
-  public args(_args: Array): void {
-    this._args = _args;
-    this._accountsResolver.args(_args);
+  public args(args: Array): void {
+    this._args = args;
+    this._accountsResolver.args(args);
   }
 
-  public async pubkeys(): Promise<
-    Partial>
-  > {
-    if (this._autoResolveAccounts) {
-      await this._accountsResolver.resolve();
-    }
-    return this._accounts as unknown as Partial<
-      InstructionAccountAddresses
-    >;
-  }
-
-  public interface(splInterface: SplInterface): MethodsBuilder {
-    if (
-      splInterface ===
-      "spl_transfer_hook_interface::initialize_extra_account_metas"
-    ) {
-      this._discriminator = Buffer.from([43, 34, 13, 49, 167, 88, 235, 235]);
-    } else if (splInterface === "spl_transfer_hook_interface::execute") {
-      this._discriminator = Buffer.from([105, 37, 101, 197, 75, 251, 102, 26]);
-    } else {
-      throw new Error(`Unsupported interface: ${splInterface}`);
-    }
-    return this;
+  /**
+   * Set instruction accounts with account resolution.
+   *
+   * This method only accepts accounts that cannot be resolved.
+   *
+   * See {@link accountsPartial} for overriding the account resolution or
+   * {@link accountsStrict} for strictly specifying all accounts.
+   */
+  public accounts(accounts: ResolvedAccounts) {
+    // @ts-ignore
+    return this.accountsPartial(accounts);
   }
 
-  public accounts(
-    accounts: PartialAccounts
-  ): MethodsBuilder {
-    this._autoResolveAccounts = true;
+  /**
+   * Set instruction accounts with account resolution.
+   *
+   * There is no functional difference between this method and {@link accounts}
+   * method, the only difference is this method allows specifying all accounts
+   * even if they can be resolved. On the other hand, {@link accounts} method
+   * doesn't accept accounts that can be resolved.
+   */
+  public accountsPartial(accounts: PartialAccounts) {
+    this._resolveAccounts = true;
     this._accountsResolver.resolveOptionals(accounts);
     return this;
   }
 
-  public accountsStrict(
-    accounts: Accounts
-  ): MethodsBuilder {
-    this._autoResolveAccounts = false;
+  /**
+   * Set instruction accounts without account resolution.
+   *
+   * All accounts strictly need to be specified when this method is used.
+   *
+   * See {@link accounts} and {@link accountsPartial} methods for automatically
+   * resolving accounts.
+   */
+  public accountsStrict(accounts: Accounts) {
+    this._resolveAccounts = false;
     this._accountsResolver.resolveOptionals(accounts);
     return this;
   }
 
-  public signers(signers: Array): MethodsBuilder {
+  public signers(signers: Array) {
     this._signers = this._signers.concat(signers);
     return this;
   }
 
-  public remainingAccounts(
-    accounts: Array
-  ): MethodsBuilder {
+  public remainingAccounts(accounts: Array) {
     this._remainingAccounts = this._remainingAccounts.concat(accounts);
     return this;
   }
 
-  public preInstructions(
-    ixs: Array
-  ): MethodsBuilder {
-    this._preInstructions = this._preInstructions.concat(ixs);
+  public preInstructions(ixs: Array, prepend = false) {
+    if (prepend) {
+      this._preInstructions = ixs.concat(this._preInstructions);
+    } else {
+      this._preInstructions = this._preInstructions.concat(ixs);
+    }
     return this;
   }
 
-  public postInstructions(
-    ixs: Array
-  ): MethodsBuilder {
+  public postInstructions(ixs: Array) {
     this._postInstructions = this._postInstructions.concat(ixs);
     return this;
   }
 
+  /**
+   * Get the public keys of the instruction accounts.
+   *
+   * The return type is an object with account names as keys and their public
+   * keys as their values.
+   *
+   * Note that an account key is `undefined` if the account hasn't yet been
+   * specified or resolved.
+   */
+  public async pubkeys(): Promise<
+    Partial>
+  > {
+    if (this._resolveAccounts) {
+      await this._accountsResolver.resolve();
+    }
+    // @ts-ignore
+    return this._accounts;
+  }
+
   public async rpc(options?: ConfirmOptions): Promise {
-    if (this._autoResolveAccounts) {
+    if (this._resolveAccounts) {
       await this._accountsResolver.resolve();
     }
 
@@ -234,24 +292,23 @@ export class MethodsBuilder> {
       remainingAccounts: this._remainingAccounts,
       preInstructions: this._preInstructions,
       postInstructions: this._postInstructions,
-      options: options,
-      discriminator: this._discriminator,
+      options,
     });
   }
 
   public async rpcAndKeys(options?: ConfirmOptions): Promise<{
-    pubkeys: Partial>;
+    pubkeys: InstructionAccountAddresses;
     signature: TransactionSignature;
   }> {
     const pubkeys = await this.pubkeys();
     return {
-      pubkeys,
+      pubkeys: pubkeys as Required>,
       signature: await this.rpc(options),
     };
   }
 
   public async view(options?: ConfirmOptions): Promise {
-    if (this._autoResolveAccounts) {
+    if (this._resolveAccounts) {
       await this._accountsResolver.resolve();
     }
 
@@ -266,14 +323,14 @@ export class MethodsBuilder> {
       remainingAccounts: this._remainingAccounts,
       preInstructions: this._preInstructions,
       postInstructions: this._postInstructions,
-      options: options,
+      options,
     });
   }
 
   public async simulate(
     options?: ConfirmOptions
   ): Promise> {
-    if (this._autoResolveAccounts) {
+    if (this._resolveAccounts) {
       await this._accountsResolver.resolve();
     }
 
@@ -284,12 +341,12 @@ export class MethodsBuilder> {
       remainingAccounts: this._remainingAccounts,
       preInstructions: this._preInstructions,
       postInstructions: this._postInstructions,
-      options: options,
+      options,
     });
   }
 
   public async instruction(): Promise {
-    if (this._autoResolveAccounts) {
+    if (this._resolveAccounts) {
       await this._accountsResolver.resolve();
     }
 
@@ -300,13 +357,15 @@ export class MethodsBuilder> {
       remainingAccounts: this._remainingAccounts,
       preInstructions: this._preInstructions,
       postInstructions: this._postInstructions,
-      discriminator: this._discriminator,
     });
   }
 
   /**
-   * Convenient shortcut to get instructions and pubkeys via
-   * const { pubkeys, instructions } = await prepare();
+   * Convenient shortcut to get instructions and pubkeys via:
+   *
+   * ```ts
+   * const { pubkeys, instructions } = await method.prepare();
+   * ```
    */
   public async prepare(): Promise<{
     pubkeys: Partial>;
@@ -316,12 +375,12 @@ export class MethodsBuilder> {
     return {
       instruction: await this.instruction(),
       pubkeys: await this.pubkeys(),
-      signers: await this._signers,
+      signers: this._signers,
     };
   }
 
   public async transaction(): Promise {
-    if (this._autoResolveAccounts) {
+    if (this._resolveAccounts) {
       await this._accountsResolver.resolve();
     }
 
@@ -332,7 +391,6 @@ export class MethodsBuilder> {
       remainingAccounts: this._remainingAccounts,
       preInstructions: this._preInstructions,
       postInstructions: this._postInstructions,
-      discriminator: this._discriminator,
     });
   }
 }
diff --git a/ts/packages/anchor/src/program/namespace/simulate.ts b/ts/packages/anchor/src/program/namespace/simulate.ts
index f73a821511..8735fa26e9 100644
--- a/ts/packages/anchor/src/program/namespace/simulate.ts
+++ b/ts/packages/anchor/src/program/namespace/simulate.ts
@@ -8,6 +8,7 @@ import { Coder } from "../../coder/index.js";
 import { Idl, IdlEvent } from "../../idl.js";
 import { translateError } from "../../error.js";
 import {
+  AllEvents,
   AllInstructions,
   IdlTypes,
   InstructionContextFn,
@@ -50,11 +51,11 @@ export default class SimulateFactory {
         throw new Error("Simulated logs not found");
       }
 
-      const events: Event>[] = [];
+      const events = [];
       if (idl.events) {
         let parser = new EventParser(programId, coder);
         for (const event of parser.parseLogs(logs)) {
-          events.push(event);
+          events.push(event as AllEvents[number]);
         }
       }
       return { events, raw: logs };
@@ -104,13 +105,9 @@ export type SimulateNamespace<
 > = MakeInstructionsNamespace<
   IDL,
   I,
-  Promise, IdlTypes>>
+  Promise[number], IdlTypes>>
 >;
 
-type NullableEvents = IDL["events"] extends undefined
-  ? IdlEvent
-  : NonNullable[number];
-
 /**
  * SimulateFn is a single method generated from an IDL. It simulates a method
  * against a cluster configured by the provider, returning a list of all the
@@ -123,7 +120,7 @@ export type SimulateFn<
 > = InstructionContextFn<
   IDL,
   I,
-  Promise, IdlTypes>>
+  Promise[number], IdlTypes>>
 >;
 
 export type SimulateResponse = {
diff --git a/ts/packages/anchor/src/program/namespace/types.ts b/ts/packages/anchor/src/program/namespace/types.ts
index 52a21fe520..932e5d0c87 100644
--- a/ts/packages/anchor/src/program/namespace/types.ts
+++ b/ts/packages/anchor/src/program/namespace/types.ts
@@ -1,19 +1,20 @@
 import { PublicKey } from "@solana/web3.js";
 import BN from "bn.js";
-import { Idl } from "../../";
 import {
-  IdlAccounts as IdlIdlAccounts,
-  IdlAccountItem,
-  IdlEnumFields,
-  IdlEnumFieldsNamed,
-  IdlEnumFieldsTuple,
+  Idl,
+  IdlInstructionAccounts as IdlInstructionAccounts,
+  IdlInstructionAccountItem,
   IdlField,
   IdlInstruction,
   IdlType,
   IdlTypeDef,
-  IdlTypeDefTyAlias,
   IdlTypeDefTyEnum,
   IdlTypeDefTyStruct,
+  IdlTypeDefTyType,
+  IdlDefinedFields,
+  IdlDefinedFieldsNamed,
+  IdlDefinedFieldsTuple,
+  IdlArrayLen,
 } from "../../idl";
 import { Accounts, Context } from "../context";
 import { MethodsBuilder } from "./methods";
@@ -21,40 +22,43 @@ import { MethodsBuilder } from "./methods";
 /**
  * All instructions for an IDL.
  */
-export type AllInstructions = IDL["instructions"][number];
+export type AllInstructions = I["instructions"][number];
 
 /**
  * Returns a type of instruction name to the IdlInstruction.
  */
-export type InstructionMap = {
+type InstructionMap = {
   [K in I["name"]]: I & { name: K };
 };
 
 /**
  * Returns a type of instruction name to the IdlInstruction.
  */
-export type AllInstructionsMap = InstructionMap<
-  AllInstructions
+export type AllInstructionsMap = InstructionMap<
+  AllInstructions
 >;
 
 /**
  * All accounts for an IDL.
  */
-export type AllAccounts = IDL["accounts"] extends undefined
-  ? IdlTypeDef
-  : NonNullable[number];
+export type AllAccounts = ResolveIdlTypePointer;
 
 /**
  * Returns a type of instruction name to the IdlInstruction.
  */
-export type AccountMap = {
-  [K in I["name"]]: I & { name: K };
+type AccountMap = {
+  [K in I[number]["name"]]: I & { name: K };
 };
 
 /**
  * Returns a type of instruction name to the IdlInstruction.
  */
-export type AllAccountsMap = AccountMap>;
+export type AllAccountsMap = AccountMap>;
+
+/**
+ * All events for an IDL.
+ */
+export type AllEvents = ResolveIdlTypePointer;
 
 export type MakeInstructionsNamespace<
   IDL extends Idl,
@@ -99,12 +103,14 @@ export type InstructionAccountAddresses<
   I extends AllInstructions
 > = InstructionAccountsAddresses;
 
-type InstructionAccountsAddresses = {
+type InstructionAccountsAddresses<
+  A extends IdlInstructionAccountItem = IdlInstructionAccountItem
+> = {
   [N in A["name"]]: InstructionAccountsAddress;
 };
 
-type InstructionAccountsAddress =
-  A extends IdlIdlAccounts
+type InstructionAccountsAddress =
+  A extends IdlInstructionAccounts
     ? InstructionAccountsAddresses
     : PublicKey;
 
@@ -115,7 +121,7 @@ export type MethodsFn<
 > = (...args: ArgsTuple>) => Ret;
 
 type TypeMap = {
-  publicKey: PublicKey;
+  pubkey: PublicKey;
   bool: boolean;
   string: string;
   bytes: Buffer;
@@ -129,15 +135,15 @@ export type DecodeType = IdlType extends T
   ? unknown
   : T extends keyof TypeMap
   ? TypeMap[T]
-  : T extends { defined: keyof Defined }
-  ? Defined[T["defined"]]
+  : T extends { defined: { name: keyof Defined } }
+  ? Defined[T["defined"]["name"]]
   : T extends { option: IdlType }
   ? DecodeType | null
   : T extends { coption: IdlType }
   ? DecodeType | null
   : T extends { vec: IdlType }
   ? DecodeType[]
-  : T extends { array: [defined: IdlType, size: number] }
+  : T extends { array: [defined: IdlType, size: IdlArrayLen] }
   ? DecodeType[]
   : unknown;
 
@@ -160,33 +166,23 @@ type UnboxToUnion = T extends (infer U)[]
   ? UnboxToUnion
   : T;
 
-type SnakeToCamelCase = S extends `${infer T}_${infer U}`
-  ? `${T}${Capitalize>}`
-  : S;
-
-/**
- * decode single enum.field
- */
-declare type DecodeEnumField = F extends IdlType
+type DecodeDefinedField = F extends IdlType
   ? DecodeType
   : never;
 
 /**
  * decode enum variant: named or tuple
  */
-declare type DecodeEnumFields<
-  F extends IdlEnumFields,
+type DecodeDefinedFields<
+  F extends IdlDefinedFields,
   Defined
-> = F extends IdlEnumFieldsNamed
+> = F extends IdlDefinedFieldsNamed
   ? {
-      [F2 in F[number] as SnakeToCamelCase]: DecodeEnumField<
-        F2["type"],
-        Defined
-      >;
+      [F2 in F[number] as F2["name"]]: DecodeDefinedField;
     }
-  : F extends IdlEnumFieldsTuple
+  : F extends IdlDefinedFieldsTuple
   ? {
-      [F3 in keyof F as Exclude]: DecodeEnumField<
+      [F3 in keyof F as Exclude]: DecodeDefinedField<
         F[F3],
         Defined
       >;
@@ -194,7 +190,7 @@ declare type DecodeEnumFields<
   : Record;
 
 type DecodeEnumVariants = {
-  [V in I["variants"][number] as Uncapitalize]: DecodeEnumFields<
+  [V in I["variants"][number] as V["name"]]: DecodeDefinedFields<
     NonNullable,
     Defined
   >;
@@ -211,12 +207,13 @@ type DecodeEnum = XorEnumVariants<
   DecodeEnumVariants
 >;
 
-type DecodeStruct = {
-  [F in I["fields"][number] as F["name"]]: DecodeType;
-};
+type DecodeStruct = DecodeDefinedFields<
+  NonNullable,
+  Defined
+>;
 
-type DecodeAlias = DecodeType<
-  I["value"],
+type DecodeAlias = DecodeType<
+  I["alias"],
   Defined
 >;
 
@@ -227,7 +224,7 @@ export type TypeDef<
   ? DecodeEnum
   : I["type"] extends IdlTypeDefTyStruct
   ? DecodeStruct
-  : I["type"] extends IdlTypeDefTyAlias
+  : I["type"] extends IdlTypeDefTyType
   ? DecodeAlias
   : never;
 
@@ -241,8 +238,9 @@ type DecodedHelper = {
 
 type UnknownType = "__unknown_defined_type__";
 /**
- * empty "defined" object to produce UnknownType instead of never/unknown during idl types decoding
- *  */
+ * Empty "defined" object to produce `UnknownType` instead of never/unknown
+ * during IDL types decoding.
+ */
 type EmptyDefined = Record;
 
 type RecursiveDepth2<
@@ -267,8 +265,8 @@ type RecursiveDepth4<
 > = DecodedHelper;
 
 /**
- * typescript can't handle truly recursive type (RecursiveTypes instead of RecursiveDepth2).
- * Hence we're doing "recursion" of depth=4 manually
+ * TypeScript can't handle truly recursive type (RecursiveTypes instead of RecursiveDepth2).
+ * Hence we're doing recursion of depth=4 manually
  *  */
 type RecursiveTypes<
   T extends IdlTypeDef[],
@@ -280,27 +278,35 @@ type RecursiveTypes<
     ? RecursiveDepth2>
     : Decoded;
 
-export type IdlTypes = RecursiveTypes>;
+export type IdlTypes = RecursiveTypes>;
 
-type IdlEventType<
-  I extends Idl,
-  Event extends NonNullable[number],
-  Defined
-> = {
-  [F in Event["fields"][number] as F["name"]]: DecodeType;
-};
+export type IdlErrors = NonNullable[number];
 
-export type IdlEvents> = {
-  [E in NonNullable[number] as E["name"]]: IdlEventType<
-    I,
-    E,
-    Defined
-  >;
-};
+export type IdlAccounts = ResolveIdlPointerSection<
+  I,
+  "accounts"
+>;
+
+export type IdlEvents = ResolveIdlPointerSection;
+
+type IdlPointerSection = keyof Pick;
 
-export type IdlAccounts = TypeDefDictionary<
-  NonNullable,
-  IdlTypes
+type ResolveIdlPointerSection<
+  I extends Idl,
+  K extends IdlPointerSection,
+  T extends ResolveIdlTypePointer = ResolveIdlTypePointer
+> = TypeDefDictionary>;
+
+type ResolveIdlTypePointer<
+  I extends Idl,
+  Key extends IdlPointerSection
+> = FilterTuple<
+  NonNullable,
+  { name: NonNullable[number]["name"] }
 >;
 
-export type IdlErrorInfo = NonNullable[number];
+type FilterTuple = T extends [infer Head, ...infer Tail]
+  ? [Head] extends [F]
+    ? [Head, ...FilterTuple]
+    : FilterTuple
+  : [];
diff --git a/ts/packages/anchor/src/program/namespace/views.ts b/ts/packages/anchor/src/program/namespace/views.ts
index da8ffb42a2..d39cc0b44b 100644
--- a/ts/packages/anchor/src/program/namespace/views.ts
+++ b/ts/packages/anchor/src/program/namespace/views.ts
@@ -1,5 +1,5 @@
 import { PublicKey } from "@solana/web3.js";
-import { Idl, IdlAccount } from "../../idl.js";
+import { Idl, IdlInstructionAccount } from "../../idl.js";
 import { SimulateFn } from "./simulate.js";
 import {
   AllInstructions,
@@ -16,9 +16,11 @@ export default class ViewFactory {
     simulateFn: SimulateFn,
     idl: IDL
   ): ViewFn | undefined {
-    const isMut = idlIx.accounts.find((a: IdlAccount) => a.isMut);
+    const isWritable = idlIx.accounts.find(
+      (a: IdlInstructionAccount) => a.writable
+    );
     const hasReturn = !!idlIx.returns;
-    if (isMut || !hasReturn) return;
+    if (isWritable || !hasReturn) return;
 
     const view: ViewFn = async (...args) => {
       let simulationResult = await simulateFn(...args);
@@ -29,15 +31,14 @@ export default class ViewFactory {
       if (!returnLog) {
         throw new Error("View expected return log");
       }
+
       let returnData = decode(returnLog.slice(returnPrefix.length));
       let returnType = idlIx.returns;
       if (!returnType) {
         throw new Error("View expected return type");
       }
-      const coder = IdlCoder.fieldLayout(
-        { type: returnType },
-        Array.from([...(idl.accounts ?? []), ...(idl.types ?? [])])
-      );
+
+      const coder = IdlCoder.fieldLayout({ type: returnType }, idl.types);
       return coder.decode(returnData);
     };
     return view;
diff --git a/ts/packages/anchor/src/provider.ts b/ts/packages/anchor/src/provider.ts
index 0731732ebb..743c1b65b7 100644
--- a/ts/packages/anchor/src/provider.ts
+++ b/ts/packages/anchor/src/provider.ts
@@ -11,6 +11,7 @@ import {
   SendOptions,
   VersionedTransaction,
   RpcResponseAndContext,
+  Keypair,
 } from "@solana/web3.js";
 import { bs58 } from "./utils/bytes/index.js";
 import { isBrowser, isVersionedTransaction } from "./utils/common.js";
@@ -22,6 +23,7 @@ import {
 export default interface Provider {
   readonly connection: Connection;
   readonly publicKey?: PublicKey;
+  readonly wallet?: Wallet;
 
   send?(
     tx: Transaction | VersionedTransaction,
@@ -63,7 +65,7 @@ export class AnchorProvider implements Provider {
   constructor(
     readonly connection: Connection,
     readonly wallet: Wallet,
-    readonly opts: ConfirmOptions
+    readonly opts: ConfirmOptions = AnchorProvider.defaultOptions()
   ) {
     this.publicKey = wallet?.publicKey;
   }
@@ -83,11 +85,14 @@ export class AnchorProvider implements Provider {
    *
    * (This api is for Node only.)
    */
-  static local(url?: string, opts?: ConfirmOptions): AnchorProvider {
+  static local(
+    url?: string,
+    opts: ConfirmOptions = AnchorProvider.defaultOptions()
+  ): AnchorProvider {
     if (isBrowser) {
       throw new Error(`Provider local is not available on browser.`);
     }
-    opts = opts ?? AnchorProvider.defaultOptions();
+
     const connection = new Connection(
       url ?? "http://127.0.0.1:8899",
       opts.preflightCommitment
@@ -171,8 +176,10 @@ export class AnchorProvider implements Provider {
             ? tx.signatures?.[0] || new Uint8Array()
             : tx.signature ?? new Uint8Array()
         );
+        const maxVer = isVersionedTransaction(tx) ? 0 : undefined;
         const failedTx = await this.connection.getTransaction(txSig, {
           commitment: "confirmed",
+          maxSupportedTransactionVersion: maxVer,
         });
         if (!failedTx) {
           throw err;
@@ -253,8 +260,10 @@ export class AnchorProvider implements Provider {
               ? tx.signatures?.[0] || new Uint8Array()
               : tx.signature ?? new Uint8Array()
           );
+          const maxVer = isVersionedTransaction(tx) ? 0 : undefined;
           const failedTx = await this.connection.getTransaction(txSig, {
             commitment: "confirmed",
+            maxSupportedTransactionVersion: maxVer,
           });
           if (!failedTx) {
             throw err;
@@ -353,6 +362,8 @@ export interface Wallet {
     txs: T[]
   ): Promise;
   publicKey: PublicKey;
+  /** Keypair of the configured payer (Node only) */
+  payer?: Keypair;
 }
 
 // Copy of Connection.sendAndConfirmRawTransaction that throws
diff --git a/ts/packages/anchor/src/workspace.ts b/ts/packages/anchor/src/workspace.ts
index fe890ce655..7ae3e8ed2f 100644
--- a/ts/packages/anchor/src/workspace.ts
+++ b/ts/packages/anchor/src/workspace.ts
@@ -2,6 +2,7 @@ import * as toml from "toml";
 import { snakeCase } from "snake-case";
 import { Program } from "./program/index.js";
 import { isBrowser } from "./utils/common.js";
+import { Idl } from "./idl.js";
 
 /**
  * The `workspace` namespace provides a convenience API to automatically
@@ -66,17 +67,11 @@ const workspace = new Proxy(
         );
       }
 
-      const idl = JSON.parse(fs.readFileSync(idlPath));
-      if (!programId) {
-        if (!idl.metadata?.address) {
-          throw new Error(
-            `IDL for program \`${programName}\` does not have \`metadata.address\` field.\n` +
-              "To add the missing field, run `anchor deploy` or `anchor test`."
-          );
-        }
-        programId = idl.metadata.address;
+      const idl: Idl = JSON.parse(fs.readFileSync(idlPath));
+      if (programId) {
+        idl.address = programId;
       }
-      workspaceCache[programName] = new Program(idl, programId);
+      workspaceCache[programName] = new Program(idl);
 
       return workspaceCache[programName];
     },
diff --git a/ts/packages/anchor/tests/coder-accounts.spec.ts b/ts/packages/anchor/tests/coder-accounts.spec.ts
index c3da53324a..6a36dcc9f9 100644
--- a/ts/packages/anchor/tests/coder-accounts.spec.ts
+++ b/ts/packages/anchor/tests/coder-accounts.spec.ts
@@ -1,29 +1,38 @@
 import * as assert from "assert";
-import { BorshCoder } from "../src";
-import { DISCRIMINATOR_SIZE } from "../src/coder/borsh/discriminator";
-import { sha256 } from "@noble/hashes/sha256";
+import { BorshCoder, Idl } from "../src";
 
 describe("coder.accounts", () => {
   test("Can encode and decode user-defined accounts, including those with consecutive capital letters", () => {
-    const idl = {
-      version: "0.0.0",
-      name: "basic_0",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_0",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [
         {
           name: "initialize",
+          discriminator: [],
           accounts: [],
           args: [],
         },
       ],
       accounts: [
+        {
+          name: "MemberDAO",
+          discriminator: [0, 1, 2, 3, 4, 5, 6, 7],
+        },
+      ],
+      types: [
         {
           name: "MemberDAO",
           type: {
-            kind: "struct" as const,
+            kind: "struct",
             fields: [
               {
                 name: "name",
-                type: "string" as const,
+                type: "string",
               },
             ],
           },
@@ -37,11 +46,6 @@ describe("coder.accounts", () => {
     };
 
     coder.accounts.encode("MemberDAO", memberDAO).then((encoded) => {
-      // start of encoded account = account discriminator
-      assert.deepEqual(
-        encoded.subarray(0, DISCRIMINATOR_SIZE),
-        Buffer.from(sha256("account:MemberDAO").slice(0, DISCRIMINATOR_SIZE))
-      );
       assert.deepEqual(coder.accounts.decode("MemberDAO", encoded), memberDAO);
     });
   });
diff --git a/ts/packages/anchor/tests/coder-instructions.spec.ts b/ts/packages/anchor/tests/coder-instructions.spec.ts
new file mode 100644
index 0000000000..a87519c3c5
--- /dev/null
+++ b/ts/packages/anchor/tests/coder-instructions.spec.ts
@@ -0,0 +1,56 @@
+import * as assert from "assert";
+import { BorshCoder } from "../src";
+import { Idl, IdlType } from "../src/idl";
+import { toInstruction } from "../src/program/common";
+
+describe("coder.instructions", () => {
+  test("Can encode and decode type aliased instruction arguments (byte array)", () => {
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "test",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
+      instructions: [
+        {
+          name: "initialize",
+          discriminator: [0, 1, 2, 3, 4, 5, 6, 7],
+          accounts: [],
+          args: [
+            {
+              name: "arg",
+              type: {
+                defined: {
+                  name: "AliasTest",
+                },
+              },
+            },
+          ],
+        },
+      ],
+      types: [
+        {
+          name: "AliasTest",
+          type: {
+            kind: "type",
+            alias: {
+              array: ["u8", 3] as [IdlType, number],
+            },
+          },
+        },
+      ],
+    };
+
+    const idlIx = idl.instructions[0];
+    const expected = [1, 2, 3];
+
+    const coder = new BorshCoder(idl);
+    const ix = toInstruction(idlIx, expected);
+
+    const encoded = coder.instruction.encode(idlIx.name, ix);
+    const decoded = coder.instruction.decode(encoded);
+
+    assert.deepStrictEqual(decoded?.data[idlIx.args[0].name], expected);
+  });
+});
diff --git a/ts/packages/anchor/tests/coder-types.spec.ts b/ts/packages/anchor/tests/coder-types.spec.ts
index 533ac24b8c..9c36b3ca9a 100644
--- a/ts/packages/anchor/tests/coder-types.spec.ts
+++ b/ts/packages/anchor/tests/coder-types.spec.ts
@@ -1,32 +1,37 @@
 import * as assert from "assert";
-import { BorshCoder } from "../src";
+import { BorshCoder, Idl } from "../src";
 import BN from "bn.js";
 
 describe("coder.types", () => {
   test("Can encode and decode user-defined types", () => {
-    const idl = {
-      version: "0.0.0",
-      name: "basic_0",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_0",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [
         {
           name: "initialize",
           accounts: [],
           args: [],
+          discriminator: [],
         },
       ],
       types: [
         {
           name: "MintInfo",
           type: {
-            kind: "struct" as const,
+            kind: "struct",
             fields: [
               {
                 name: "minted",
-                type: "bool" as const,
+                type: "bool",
               },
               {
                 name: "metadataUrl",
-                type: "string" as const,
+                type: "string",
               },
             ],
           },
@@ -45,29 +50,34 @@ describe("coder.types", () => {
   });
 
   test("Can encode and decode 256-bit integers", () => {
-    const idl = {
-      version: "0.0.0",
-      name: "basic_0",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_0",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [
         {
           name: "initialize",
           accounts: [],
           args: [],
+          discriminator: [],
         },
       ],
       types: [
         {
           name: "IntegerTest",
           type: {
-            kind: "struct" as const,
+            kind: "struct",
             fields: [
               {
                 name: "unsigned",
-                type: "u256" as const,
+                type: "u256",
               },
               {
                 name: "signed",
-                type: "i256" as const,
+                type: "i256",
               },
             ],
           },
diff --git a/ts/packages/anchor/tests/events.spec.ts b/ts/packages/anchor/tests/events.spec.ts
index f02fc00ad4..09441b1b75 100644
--- a/ts/packages/anchor/tests/events.spec.ts
+++ b/ts/packages/anchor/tests/events.spec.ts
@@ -1,6 +1,6 @@
 import { PublicKey } from "@solana/web3.js";
 import { EventParser } from "../src/program/event";
-import { BorshCoder } from "../src";
+import { BorshCoder, Idl } from "../src";
 
 describe("Events", () => {
   it("Parses multiple instructions", () => {
@@ -11,14 +11,19 @@ describe("Events", () => {
       "Program J2XMGdW2qQLx7rAdwWtSZpTXDgAQ988BLP9QTgUZvm54 consumed 17867 of 200000 compute units",
       "Program J2XMGdW2qQLx7rAdwWtSZpTXDgAQ988BLP9QTgUZvm54 success",
     ];
-    const idl = {
-      version: "0.0.0",
-      name: "basic_0",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_0",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [
         {
           name: "initialize",
           accounts: [],
           args: [],
+          discriminator: [],
         },
       ],
     };
@@ -39,14 +44,19 @@ describe("Events", () => {
       "Program J2XMGdW2qQLx7rAdwWtSZpTXDgAQ988BLP9QTgUZvm54 consumed 17867 of 200000 compute units",
       "Program J2XMGdW2qQLx7rAdwWtSZpTXDgAQ988BLP9QTgUZvm54 success",
     ];
-    const idl = {
-      version: "0.0.0",
-      name: "basic_0",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_0",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [
         {
           name: "initialize",
           accounts: [],
           args: [],
+          discriminator: [],
         },
       ],
     };
@@ -83,31 +93,43 @@ describe("Events", () => {
       "Program J2XMGdW2qQLx7rAdwWtSZpTXDgAQ988BLP9QTgUZvm54 success",
     ];
 
-    const idl = {
-      version: "0.0.0",
-      name: "basic_1",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_1",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [
         {
           name: "initialize",
           accounts: [],
           args: [],
+          discriminator: [],
         },
       ],
       events: [
         {
           name: "NftSold",
-          fields: [
-            {
-              name: "nftMintAddress",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-            {
-              name: "accountAddress",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-          ],
+          discriminator: [82, 21, 49, 86, 87, 54, 132, 103],
+        },
+      ],
+      types: [
+        {
+          name: "NftSold",
+          type: {
+            kind: "struct",
+            fields: [
+              {
+                name: "nftMintAddress",
+                type: "pubkey",
+              },
+              {
+                name: "accountAddress",
+                type: "pubkey",
+              },
+            ],
+          },
         },
       ],
     };
@@ -116,6 +138,7 @@ describe("Events", () => {
     const programId = new PublicKey(
       "J2XMGdW2qQLx7rAdwWtSZpTXDgAQ988BLP9QTgUZvm54"
     );
+
     const eventParser = new EventParser(programId, coder);
 
     const gen = eventParser.parseLogs(logs);
@@ -143,42 +166,41 @@ describe("Events", () => {
       "Program J2XMGdW2qQLx7rAdwWtSZpTXDgAQ988BLP9QTgUZvm54 success",
     ];
 
-    const idl = {
-      version: "0.0.0",
-      name: "basic_2",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_2",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [
         {
           name: "cancelListing",
+          discriminator: [],
           accounts: [
             {
               name: "globalState",
-              isMut: true,
-              isSigner: false,
+              writable: true,
             },
             {
               name: "nftHolderAccount",
-              isMut: true,
-              isSigner: false,
+              writable: true,
             },
             {
               name: "listingAccount",
-              isMut: true,
-              isSigner: false,
+              writable: true,
             },
             {
               name: "nftAssociatedAccount",
-              isMut: true,
-              isSigner: false,
+              writable: true,
             },
             {
               name: "signer",
-              isMut: true,
-              isSigner: true,
+              writable: true,
+              signer: true,
             },
             {
               name: "tokenProgram",
-              isMut: false,
-              isSigner: false,
             },
           ],
           args: [],
@@ -187,23 +209,29 @@ describe("Events", () => {
       events: [
         {
           name: "ListingClosed",
-          fields: [
-            {
-              name: "initializer",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-            {
-              name: "nftMintAddress",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-            {
-              name: "accountAddress",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-          ],
+          discriminator: [86, 219, 253, 196, 184, 194, 176, 78],
+        },
+      ],
+      types: [
+        {
+          name: "ListingClosed",
+          type: {
+            kind: "struct",
+            fields: [
+              {
+                name: "initializer",
+                type: "pubkey",
+              },
+              {
+                name: "nftMintAddress",
+                type: "pubkey",
+              },
+              {
+                name: "accountAddress",
+                type: "pubkey",
+              },
+            ],
+          },
         },
       ],
     };
@@ -239,30 +267,40 @@ describe("Events", () => {
       "Program 5VcVB7jEjdWJBkriXxayCrUUkwfhrPK3rXtnkxxUvMFP success",
     ];
 
-    const idl = {
-      version: "0.0.0",
-      name: "basic_2",
+    const idl: Idl = {
+      address: "Test111111111111111111111111111111111111111",
+      metadata: {
+        name: "basic_2",
+        version: "0.0.0",
+        spec: "0.1.0",
+      },
       instructions: [],
       events: [
         {
           name: "ListingClosed",
-          fields: [
-            {
-              name: "initializer",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-            {
-              name: "nftMintAddress",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-            {
-              name: "accountAddress",
-              type: "publicKey" as "publicKey",
-              index: false,
-            },
-          ],
+          discriminator: [],
+        },
+      ],
+      types: [
+        {
+          name: "ListingClosed",
+          type: {
+            kind: "struct",
+            fields: [
+              {
+                name: "initializer",
+                type: "pubkey",
+              },
+              {
+                name: "nftMintAddress",
+                type: "pubkey",
+              },
+              {
+                name: "accountAddress",
+                type: "pubkey",
+              },
+            ],
+          },
         },
       ],
     };
diff --git a/ts/packages/anchor/tests/transaction.spec.ts b/ts/packages/anchor/tests/transaction.spec.ts
index 4a3e69aea1..afc2cf5218 100644
--- a/ts/packages/anchor/tests/transaction.spec.ts
+++ b/ts/packages/anchor/tests/transaction.spec.ts
@@ -1,6 +1,6 @@
 import TransactionFactory from "../src/program/namespace/transaction";
 import InstructionFactory from "../src/program/namespace/instruction";
-import { BorshCoder } from "../src";
+import { BorshCoder, Idl } from "../src";
 import { PublicKey, TransactionInstruction } from "@solana/web3.js";
 
 describe("Transaction", () => {
@@ -14,14 +14,19 @@ describe("Transaction", () => {
     programId: PublicKey.default,
     data: Buffer.from("post"),
   });
-  const idl = {
-    version: "0.0.0",
-    name: "basic_0",
+  const idl: Idl = {
+    address: "Test111111111111111111111111111111111111111",
+    metadata: {
+      name: "basic_0",
+      version: "0.0.0",
+      spec: "0.1.0",
+    },
     instructions: [
       {
         name: "initialize",
         accounts: [],
         args: [],
+        discriminator: [],
       },
     ],
   };
diff --git a/ts/packages/borsh/package.json b/ts/packages/borsh/package.json
index cdfbf97ae1..40024cf8c7 100644
--- a/ts/packages/borsh/package.json
+++ b/ts/packages/borsh/package.json
@@ -1,6 +1,6 @@
 {
   "name": "@coral-xyz/borsh",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "description": "Anchor Borsh",
   "main": "dist/index.js",
   "types": "dist/index.d.ts",
diff --git a/ts/packages/spl-associated-token-account/package.json b/ts/packages/spl-associated-token-account/package.json
index e00c62dc8c..7ad43ae5fd 100644
--- a/ts/packages/spl-associated-token-account/package.json
+++ b/ts/packages/spl-associated-token-account/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-associated-token-account/src/coder/accounts.ts b/ts/packages/spl-associated-token-account/src/coder/accounts.ts
index 40a0ea8563..aa0fe2a8ff 100644
--- a/ts/packages/spl-associated-token-account/src/coder/accounts.ts
+++ b/ts/packages/spl-associated-token-account/src/coder/accounts.ts
@@ -39,10 +39,10 @@ export class SplAssociatedTokenAccountAccountsCoder
     }
   }
 
-  public size(idlAccount: IdlTypeDef): number {
-    switch (idlAccount.name) {
+  public size(accountName: A): number {
+    switch (accountName) {
       default: {
-        throw new Error(`Invalid account name: ${idlAccount.name}`);
+        throw new Error(`Invalid account name: ${accountName}`);
       }
     }
   }
diff --git a/ts/packages/spl-associated-token-account/src/program.ts b/ts/packages/spl-associated-token-account/src/program.ts
index feaec79b18..ad12af5fe4 100644
--- a/ts/packages/spl-associated-token-account/src/program.ts
+++ b/ts/packages/spl-associated-token-account/src/program.ts
@@ -16,126 +16,109 @@ export function splAssociatedTokenAccountProgram(
   params?: GetProgramParams
 ): Program {
   return new Program(
-    IDL,
-    params?.programId ?? SPL_ASSOCIATED_TOKEN_ACCOUNT_PROGRAM_ID,
+    params?.programId ? { ...IDL, address: params.programId.toString() } : IDL,
     params?.provider,
     new SplAssociatedTokenAccountCoder(IDL)
   );
 }
 
 type SplAssociatedTokenAccount = {
-  version: "1.1.1";
-  name: "spl_associated_token_account";
+  address: string;
+  metadata: {
+    name: "splAssociatedTokenAccount";
+    version: "1.1.1";
+    spec: "0.1.0";
+  };
   instructions: [
     {
       name: "create";
+      discriminator: [0];
       accounts: [
         {
           name: "fundingAddress";
-          isMut: true;
-          isSigner: true;
+          writable: true;
+          signer: true;
         },
         {
           name: "associatedAccountAddress";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "walletAddress";
-          isMut: false;
-          isSigner: false;
         },
         {
           name: "tokenMintAddress";
-          isMut: false;
-          isSigner: false;
         },
         {
           name: "systemProgram";
-          isMut: false;
-          isSigner: false;
+          address: "11111111111111111111111111111111";
         },
         {
           name: "tokenProgram";
-          isMut: false;
-          isSigner: false;
+          address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
         }
       ];
       args: [];
     },
     {
       name: "createIdempotent";
+      discriminator: [1];
       accounts: [
         {
           name: "fundingAddress";
-          isMut: true;
-          isSigner: true;
+          writable: true;
+          signer: true;
         },
         {
           name: "associatedAccountAddress";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "walletAddress";
-          isMut: false;
-          isSigner: false;
         },
         {
           name: "tokenMintAddress";
-          isMut: false;
-          isSigner: false;
         },
         {
           name: "systemProgram";
-          isMut: false;
-          isSigner: false;
+          address: "11111111111111111111111111111111";
         },
         {
           name: "tokenProgram";
-          isMut: false;
-          isSigner: false;
+          address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
         }
       ];
       args: [];
     },
     {
       name: "recoverNested";
+      discriminator: [2];
       accounts: [
         {
           name: "nestedAssociatedAccountAddress";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "nestedTokenMintAddress";
-          isMut: false;
-          isSigner: false;
         },
         {
           name: "destinationAssociatedAccountAddress";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "ownerAssociatedAccountAddress";
-          isMut: false;
-          isSigner: false;
         },
         {
           name: "ownerTokenMintAddress";
-          isMut: false;
-          isSigner: false;
         },
         {
           name: "walletAddress";
-          isMut: true;
-          isSigner: true;
+          writable: true;
+          signer: true;
         },
         {
           name: "tokenProgram";
-          isMut: false;
-          isSigner: false;
+          address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA";
         }
       ];
       args: [];
@@ -144,125 +127,109 @@ type SplAssociatedTokenAccount = {
   errors: [
     {
       code: 0;
-      name: "InvalidOwner";
+      name: "invalidOwner";
       msg: "Associated token account owner does not match address derivation";
     }
   ];
 };
 
 const IDL: SplAssociatedTokenAccount = {
-  version: "1.1.1",
-  name: "spl_associated_token_account",
+  address: "ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL",
+  metadata: {
+    name: "splAssociatedTokenAccount",
+    version: "1.1.1",
+    spec: "0.1.0",
+  },
   instructions: [
     {
       name: "create",
+      discriminator: [0],
       accounts: [
         {
           name: "fundingAddress",
-          isMut: true,
-          isSigner: true,
+          writable: true,
+          signer: true,
         },
         {
           name: "associatedAccountAddress",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "walletAddress",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "tokenMintAddress",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "systemProgram",
-          isMut: false,
-          isSigner: false,
+          address: "11111111111111111111111111111111",
         },
         {
           name: "tokenProgram",
-          isMut: false,
-          isSigner: false,
+          address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
         },
       ],
       args: [],
     },
     {
       name: "createIdempotent",
+      discriminator: [1],
       accounts: [
         {
           name: "fundingAddress",
-          isMut: true,
-          isSigner: true,
+          writable: true,
+          signer: true,
         },
         {
           name: "associatedAccountAddress",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "walletAddress",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "tokenMintAddress",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "systemProgram",
-          isMut: false,
-          isSigner: false,
+          address: "11111111111111111111111111111111",
         },
         {
           name: "tokenProgram",
-          isMut: false,
-          isSigner: false,
+          address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
         },
       ],
       args: [],
     },
     {
       name: "recoverNested",
+      discriminator: [2],
       accounts: [
         {
           name: "nestedAssociatedAccountAddress",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "nestedTokenMintAddress",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "destinationAssociatedAccountAddress",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "ownerAssociatedAccountAddress",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "ownerTokenMintAddress",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "walletAddress",
-          isMut: true,
-          isSigner: true,
+          writable: true,
+          signer: true,
         },
         {
           name: "tokenProgram",
-          isMut: false,
-          isSigner: false,
+          address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
         },
       ],
       args: [],
@@ -271,7 +238,7 @@ const IDL: SplAssociatedTokenAccount = {
   errors: [
     {
       code: 0,
-      name: "InvalidOwner",
+      name: "invalidOwner",
       msg: "Associated token account owner does not match address derivation",
     },
   ],
diff --git a/ts/packages/spl-binary-option/package.json b/ts/packages/spl-binary-option/package.json
index 5291c4cff2..ec5ab97da0 100644
--- a/ts/packages/spl-binary-option/package.json
+++ b/ts/packages/spl-binary-option/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-binary-oracle-pair/package.json b/ts/packages/spl-binary-oracle-pair/package.json
index 3f3a5b498b..d84135810c 100644
--- a/ts/packages/spl-binary-oracle-pair/package.json
+++ b/ts/packages/spl-binary-oracle-pair/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-feature-proposal/package.json b/ts/packages/spl-feature-proposal/package.json
index 6569964802..b1795aebac 100644
--- a/ts/packages/spl-feature-proposal/package.json
+++ b/ts/packages/spl-feature-proposal/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-governance/package.json b/ts/packages/spl-governance/package.json
index 5cb617f646..3d1282d85c 100644
--- a/ts/packages/spl-governance/package.json
+++ b/ts/packages/spl-governance/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-governance/program/lib.rs b/ts/packages/spl-governance/program/lib.rs
index 9856aad6bd..414a97ceab 100644
--- a/ts/packages/spl-governance/program/lib.rs
+++ b/ts/packages/spl-governance/program/lib.rs
@@ -813,7 +813,7 @@ pub struct ProposalV1 {
     /// The number of instructions included in the proposal
     pub instructions_count: u16,
 
-    /// The index of the the next instruction to be added
+    /// The index of the next instruction to be added
     pub instructions_next_index: u16,
 
     /// When the Proposal was created and entered Draft state
@@ -1232,7 +1232,7 @@ pub struct ProposalOption {
     /// The number of transactions included in the option
     pub transactions_count: u16,
 
-    /// The index of the the next transaction to be added
+    /// The index of the next transaction to be added
     pub transactions_next_index: u16,
 }
 
diff --git a/ts/packages/spl-memo/package.json b/ts/packages/spl-memo/package.json
index 61045c7119..88efed8148 100644
--- a/ts/packages/spl-memo/package.json
+++ b/ts/packages/spl-memo/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0"
+    "@coral-xyz/anchor": "=0.30.1"
   },
   "devDependencies": {
     "@rollup/plugin-commonjs": "=21.0.2",
diff --git a/ts/packages/spl-name-service/package.json b/ts/packages/spl-name-service/package.json
index c3b00ba0b7..2cae8b0eda 100644
--- a/ts/packages/spl-name-service/package.json
+++ b/ts/packages/spl-name-service/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-record/package.json b/ts/packages/spl-record/package.json
index daece8391a..e4df4a98a2 100644
--- a/ts/packages/spl-record/package.json
+++ b/ts/packages/spl-record/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-stake-pool/package.json b/ts/packages/spl-stake-pool/package.json
index 4e334dc041..d8e9d07111 100644
--- a/ts/packages/spl-stake-pool/package.json
+++ b/ts/packages/spl-stake-pool/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-stateless-asks/package.json b/ts/packages/spl-stateless-asks/package.json
index 3cc5c018ad..31d01dc43f 100644
--- a/ts/packages/spl-stateless-asks/package.json
+++ b/ts/packages/spl-stateless-asks/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-token-lending/package.json b/ts/packages/spl-token-lending/package.json
index 05ed885046..d38348e80c 100644
--- a/ts/packages/spl-token-lending/package.json
+++ b/ts/packages/spl-token-lending/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-token-swap/package.json b/ts/packages/spl-token-swap/package.json
index 158438422c..1a8cc2a845 100644
--- a/ts/packages/spl-token-swap/package.json
+++ b/ts/packages/spl-token-swap/package.json
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-token/package.json b/ts/packages/spl-token/package.json
index 3e5f606f70..fffbfd1877 100644
--- a/ts/packages/spl-token/package.json
+++ b/ts/packages/spl-token/package.json
@@ -1,7 +1,7 @@
 {
   "name": "@coral-xyz/spl-token",
   "description": "Anchor client for Solana Program Library Token",
-  "version": "0.29.0",
+  "version": "0.30.1",
   "author": "acheron ",
   "license": "Apache-2.0",
   "repository": {
@@ -27,7 +27,7 @@
     "watch": "tsc -p tsconfig.cjs.json --watch"
   },
   "dependencies": {
-    "@coral-xyz/anchor": "=0.29.0",
+    "@coral-xyz/anchor": "=0.30.1",
     "@native-to-anchor/buffer-layout": "=0.1.0"
   },
   "devDependencies": {
diff --git a/ts/packages/spl-token/src/coder/accounts.ts b/ts/packages/spl-token/src/coder/accounts.ts
index 176879c77f..5e0d1fcd29 100644
--- a/ts/packages/spl-token/src/coder/accounts.ts
+++ b/ts/packages/spl-token/src/coder/accounts.ts
@@ -78,8 +78,8 @@ export class SplTokenAccountsCoder
     }
   }
 
-  public size(idlAccount: IdlTypeDef): number {
-    switch (idlAccount.name) {
+  public size(accountName: A): number {
+    switch (accountName) {
       case "mint": {
         return 82;
       }
@@ -90,7 +90,7 @@ export class SplTokenAccountsCoder
         return 355;
       }
       default: {
-        throw new Error(`Invalid account name: ${idlAccount.name}`);
+        throw new Error(`Invalid account name: ${accountName}`);
       }
     }
   }
diff --git a/ts/packages/spl-token/src/program.ts b/ts/packages/spl-token/src/program.ts
index 18fdf16999..04642cae2b 100644
--- a/ts/packages/spl-token/src/program.ts
+++ b/ts/packages/spl-token/src/program.ts
@@ -14,112 +14,103 @@ interface GetProgramParams {
 
 export function splTokenProgram(params?: GetProgramParams): Program {
   return new Program(
-    IDL,
-    params?.programId ?? SPL_TOKEN_PROGRAM_ID,
+    params?.programId ? { ...IDL, address: params.programId.toString() } : IDL,
     params?.provider,
     new SplTokenCoder(IDL)
   );
 }
 
 type SplToken = {
-  version: "3.3.0";
-  name: "spl_token";
+  address: string;
+  metadata: {
+    name: "splToken";
+    version: "3.3.0";
+    spec: "0.1.0";
+  };
   instructions: [
     {
-      name: "initializeMint";
+      name: "amountToUiAmount";
+      discriminator: [23];
       accounts: [
         {
           name: "mint";
-          isMut: true;
-          isSigner: false;
-        },
-        {
-          name: "rent";
-          isMut: false;
-          isSigner: false;
         }
       ];
       args: [
         {
-          name: "decimals";
-          type: "u8";
-        },
-        {
-          name: "mintAuthority";
-          type: "publicKey";
-        },
-        {
-          name: "freezeAuthority";
-          type: {
-            defined: "COption";
-          };
+          name: "amount";
+          type: "u64";
         }
       ];
     },
     {
-      name: "initializeAccount";
+      name: "approve";
+      discriminator: [4];
       accounts: [
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
+          name: "source";
+          writable: true;
         },
         {
-          name: "mint";
-          isMut: false;
-          isSigner: false;
+          name: "delegate";
         },
         {
           name: "owner";
-          isMut: false;
-          isSigner: false;
-        },
+          signer: true;
+        }
+      ];
+      args: [
         {
-          name: "rent";
-          isMut: false;
-          isSigner: false;
+          name: "amount";
+          type: "u64";
         }
       ];
-      args: [];
     },
     {
-      name: "initializeMultisig";
+      name: "approveChecked";
+      discriminator: [13];
       accounts: [
         {
-          name: "multisig";
-          isMut: true;
-          isSigner: false;
+          name: "source";
+          writable: true;
         },
         {
-          name: "rent";
-          isMut: false;
-          isSigner: false;
+          name: "mint";
+        },
+        {
+          name: "delegate";
+        },
+        {
+          name: "owner";
+          signer: true;
         }
       ];
       args: [
         {
-          name: "m";
+          name: "amount";
+          type: "u64";
+        },
+        {
+          name: "decimals";
           type: "u8";
         }
       ];
     },
     {
-      name: "transfer";
+      name: "burn";
+      discriminator: [8];
       accounts: [
         {
-          name: "source";
-          isMut: true;
-          isSigner: false;
+          name: "account";
+          writable: true;
         },
         {
-          name: "destination";
-          isMut: true;
-          isSigner: false;
+          name: "mint";
+          writable: true;
         },
         {
           name: "authority";
-          isMut: false;
-          isSigner: true;
+          signer: true;
         }
       ];
       args: [
@@ -130,313 +121,288 @@ type SplToken = {
       ];
     },
     {
-      name: "approve";
+      name: "burnChecked";
+      discriminator: [15];
       accounts: [
         {
-          name: "source";
-          isMut: true;
-          isSigner: false;
+          name: "account";
+          writable: true;
         },
         {
-          name: "delegate";
-          isMut: false;
-          isSigner: false;
+          name: "mint";
+          writable: true;
         },
         {
-          name: "owner";
-          isMut: false;
-          isSigner: true;
+          name: "authority";
+          signer: true;
         }
       ];
       args: [
         {
           name: "amount";
           type: "u64";
+        },
+        {
+          name: "decimals";
+          type: "u8";
         }
       ];
     },
     {
-      name: "revoke";
+      name: "closeAccount";
+      discriminator: [9];
       accounts: [
         {
-          name: "source";
-          isMut: true;
-          isSigner: false;
+          name: "account";
+          writable: true;
+        },
+        {
+          name: "destination";
+          writable: true;
         },
         {
           name: "owner";
-          isMut: false;
-          isSigner: true;
+          signer: true;
         }
       ];
       args: [];
     },
     {
-      name: "setAuthority";
+      name: "freezeAccount";
+      discriminator: [10];
       accounts: [
         {
-          name: "owned";
-          isMut: true;
-          isSigner: false;
+          name: "account";
+          writable: true;
         },
         {
-          name: "owner";
-          isMut: false;
-          isSigner: true;
+          name: "mint";
         },
         {
-          name: "signer";
-          isMut: false;
-          isSigner: true;
+          name: "owner";
+          signer: true;
         }
       ];
-      args: [
-        {
-          name: "authorityType";
-          type: {
-            defined: "AuthorityType";
-          };
-        },
+      args: [];
+    },
+    {
+      name: "getAccountDataSize";
+      discriminator: [21];
+      accounts: [
         {
-          name: "newAuthority";
-          type: {
-            defined: "COption";
-          };
+          name: "mint";
         }
       ];
+      args: [];
     },
     {
-      name: "mintTo";
+      name: "initializeAccount";
+      discriminator: [1];
       accounts: [
         {
-          name: "mint";
-          isMut: true;
-          isSigner: false;
+          name: "account";
+          writable: true;
         },
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
+          name: "mint";
         },
         {
           name: "owner";
-          isMut: false;
-          isSigner: true;
-        }
-      ];
-      args: [
+        },
         {
-          name: "amount";
-          type: "u64";
+          name: "rent";
+          address: "SysvarRent111111111111111111111111111111111";
         }
       ];
+      args: [];
     },
     {
-      name: "burn";
+      name: "initializeAccount2";
+      discriminator: [16];
       accounts: [
         {
           name: "account";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "mint";
-          isMut: true;
-          isSigner: false;
         },
         {
-          name: "authority";
-          isMut: false;
-          isSigner: true;
+          name: "rent";
+          address: "SysvarRent111111111111111111111111111111111";
         }
       ];
       args: [
         {
-          name: "amount";
-          type: "u64";
+          name: "owner";
+          type: "pubkey";
         }
       ];
     },
     {
-      name: "closeAccount";
+      name: "initializeAccount3";
+      discriminator: [18];
       accounts: [
         {
           name: "account";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
-          name: "destination";
-          isMut: true;
-          isSigner: false;
-        },
+          name: "mint";
+        }
+      ];
+      args: [
         {
           name: "owner";
-          isMut: false;
-          isSigner: true;
+          type: "pubkey";
         }
       ];
-      args: [];
     },
     {
-      name: "freezeAccount";
+      name: "initializeImmutableOwner";
+      discriminator: [22];
       accounts: [
         {
           name: "account";
-          isMut: true;
-          isSigner: false;
-        },
-        {
-          name: "mint";
-          isMut: false;
-          isSigner: false;
-        },
-        {
-          name: "owner";
-          isMut: false;
-          isSigner: true;
+          writable: true;
         }
       ];
       args: [];
     },
     {
-      name: "thawAccount";
+      name: "initializeMint";
+      discriminator: [0];
       accounts: [
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
+          name: "mint";
+          writable: true;
         },
         {
-          name: "mint";
-          isMut: false;
-          isSigner: false;
+          name: "rent";
+          address: "SysvarRent111111111111111111111111111111111";
+        }
+      ];
+      args: [
+        {
+          name: "decimals";
+          type: "u8";
         },
         {
-          name: "owner";
-          isMut: false;
-          isSigner: true;
+          name: "mintAuthority";
+          type: "pubkey";
+        },
+        {
+          name: "freezeAuthority";
+          type: {
+            coption: "pubkey";
+          };
         }
       ];
-      args: [];
     },
     {
-      name: "transferChecked";
+      name: "initializeMint2";
+      discriminator: [20];
       accounts: [
-        {
-          name: "source";
-          isMut: true;
-          isSigner: false;
-        },
         {
           name: "mint";
-          isMut: false;
-          isSigner: false;
+          writable: true;
+        }
+      ];
+      args: [
+        {
+          name: "decimals";
+          type: "u8";
         },
         {
-          name: "destination";
-          isMut: true;
-          isSigner: false;
+          name: "mintAuthority";
+          type: "pubkey";
         },
         {
-          name: "authority";
-          isMut: false;
-          isSigner: true;
+          name: "freezeAuthority";
+          type: {
+            coption: "pubkey";
+          };
         }
       ];
-      args: [
+    },
+    {
+      name: "initializeMultisig";
+      discriminator: [2];
+      accounts: [
         {
-          name: "amount";
-          type: "u64";
+          name: "multisig";
+          writable: true;
         },
         {
-          name: "decimals";
+          name: "rent";
+          address: "SysvarRent111111111111111111111111111111111";
+        }
+      ];
+      args: [
+        {
+          name: "m";
           type: "u8";
         }
       ];
     },
     {
-      name: "approveChecked";
+      name: "initializeMultisig2";
+      discriminator: [19];
       accounts: [
         {
-          name: "source";
-          isMut: true;
-          isSigner: false;
-        },
-        {
-          name: "mint";
-          isMut: false;
-          isSigner: false;
-        },
-        {
-          name: "delegate";
-          isMut: false;
-          isSigner: false;
+          name: "multisig";
+          writable: true;
         },
         {
-          name: "owner";
-          isMut: false;
-          isSigner: true;
+          name: "signer";
         }
       ];
       args: [
         {
-          name: "amount";
-          type: "u64";
-        },
-        {
-          name: "decimals";
+          name: "m";
           type: "u8";
         }
       ];
     },
     {
-      name: "mintToChecked";
+      name: "mintTo";
+      discriminator: [7];
       accounts: [
         {
           name: "mint";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "account";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "owner";
-          isMut: false;
-          isSigner: true;
+          signer: true;
         }
       ];
       args: [
         {
           name: "amount";
           type: "u64";
-        },
-        {
-          name: "decimals";
-          type: "u8";
         }
       ];
     },
     {
-      name: "burnChecked";
+      name: "mintToChecked";
+      discriminator: [14];
       accounts: [
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
+          name: "mint";
+          writable: true;
         },
         {
-          name: "mint";
-          isMut: true;
-          isSigner: false;
+          name: "account";
+          writable: true;
         },
         {
-          name: "authority";
-          isMut: false;
-          isSigner: true;
+          name: "owner";
+          signer: true;
         }
       ];
       args: [
@@ -451,163 +417,150 @@ type SplToken = {
       ];
     },
     {
-      name: "initializeAccount2";
+      name: "revoke";
+      discriminator: [5];
       accounts: [
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
+          name: "source";
+          writable: true;
         },
         {
-          name: "mint";
-          isMut: false;
-          isSigner: false;
+          name: "owner";
+          signer: true;
+        }
+      ];
+      args: [];
+    },
+    {
+      name: "setAuthority";
+      discriminator: [6];
+      accounts: [
+        {
+          name: "owned";
+          writable: true;
         },
         {
-          name: "rent";
-          isMut: false;
-          isSigner: false;
+          name: "owner";
+          signer: true;
+        },
+        {
+          name: "signer";
+          signer: true;
         }
       ];
       args: [
         {
-          name: "owner";
-          type: "publicKey";
+          name: "authorityType";
+          type: {
+            defined: {
+              name: "authorityType";
+            };
+          };
+        },
+        {
+          name: "newAuthority";
+          type: {
+            coption: "pubkey";
+          };
         }
       ];
     },
     {
       name: "syncNative";
+      discriminator: [17];
       accounts: [
         {
           name: "account";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         }
       ];
       args: [];
     },
     {
-      name: "initializeAccount3";
+      name: "thawAccount";
+      discriminator: [11];
       accounts: [
         {
           name: "account";
-          isMut: true;
-          isSigner: false;
+          writable: true;
         },
         {
           name: "mint";
-          isMut: false;
-          isSigner: false;
-        }
-      ];
-      args: [
+        },
         {
           name: "owner";
-          type: "publicKey";
+          signer: true;
         }
       ];
+      args: [];
     },
     {
-      name: "initializeMultisig2";
+      name: "transfer";
+      discriminator: [3];
       accounts: [
         {
-          name: "multisig";
-          isMut: true;
-          isSigner: false;
+          name: "source";
+          writable: true;
         },
         {
-          name: "signer";
-          isMut: false;
-          isSigner: false;
+          name: "destination";
+          writable: true;
+        },
+        {
+          name: "authority";
+          signer: true;
         }
       ];
       args: [
         {
-          name: "m";
-          type: "u8";
+          name: "amount";
+          type: "u64";
         }
       ];
     },
     {
-      name: "initializeMint2";
+      name: "transferChecked";
+      discriminator: [12];
       accounts: [
         {
-          name: "mint";
-          isMut: true;
-          isSigner: false;
-        }
-      ];
-      args: [
-        {
-          name: "decimals";
-          type: "u8";
-        },
-        {
-          name: "mintAuthority";
-          type: "publicKey";
+          name: "source";
+          writable: true;
         },
-        {
-          name: "freezeAuthority";
-          type: {
-            defined: "COption";
-          };
-        }
-      ];
-    },
-    {
-      name: "getAccountDataSize";
-      accounts: [
         {
           name: "mint";
-          isMut: false;
-          isSigner: false;
-        }
-      ];
-      args: [];
-    },
-    {
-      name: "initializeImmutableOwner";
-      accounts: [
+        },
         {
-          name: "account";
-          isMut: true;
-          isSigner: false;
-        }
-      ];
-      args: [];
-    },
-    {
-      name: "amountToUiAmount";
-      accounts: [
+          name: "destination";
+          writable: true;
+        },
         {
-          name: "mint";
-          isMut: false;
-          isSigner: false;
+          name: "authority";
+          signer: true;
         }
       ];
       args: [
         {
           name: "amount";
           type: "u64";
+        },
+        {
+          name: "decimals";
+          type: "u8";
         }
       ];
     },
     {
       name: "uiAmountToAmount";
+      discriminator: [24];
       accounts: [
         {
           name: "mint";
-          isMut: false;
-          isSigner: false;
         }
       ];
       args: [
         {
           name: "uiAmount";
-          type: {
-            defined: "&'astr";
-          };
+          type: "string";
         }
       ];
     }
@@ -615,353 +568,312 @@ type SplToken = {
   accounts: [
     {
       name: "mint";
-      type: {
-        kind: "struct";
-        fields: [
-          {
-            name: "mintAuthority";
-            type: {
-              defined: "COption";
-            };
-          },
-          {
-            name: "supply";
-            type: "u64";
-          },
-          {
-            name: "decimals";
-            type: "u8";
-          },
-          {
-            name: "isInitialized";
-            type: "bool";
-          },
-          {
-            name: "freezeAuthority";
-            type: {
-              defined: "COption";
-            };
-          }
-        ];
-      };
-    },
-    {
-      name: "account";
-      type: {
-        kind: "struct";
-        fields: [
-          {
-            name: "mint";
-            type: "publicKey";
-          },
-          {
-            name: "owner";
-            type: "publicKey";
-          },
-          {
-            name: "amount";
-            type: "u64";
-          },
-          {
-            name: "delegate";
-            type: {
-              defined: "COption";
-            };
-          },
-          {
-            name: "state";
-            type: {
-              defined: "AccountState";
-            };
-          },
-          {
-            name: "isNative";
-            type: {
-              defined: "COption";
-            };
-          },
-          {
-            name: "delegatedAmount";
-            type: "u64";
-          },
-          {
-            name: "closeAuthority";
-            type: {
-              defined: "COption";
-            };
-          }
-        ];
-      };
+      discriminator: [];
     },
     {
       name: "multisig";
-      type: {
-        kind: "struct";
-        fields: [
-          {
-            name: "m";
-            type: "u8";
-          },
-          {
-            name: "n";
-            type: "u8";
-          },
-          {
-            name: "isInitialized";
-            type: "bool";
-          },
-          {
-            name: "signers";
-            type: {
-              array: ["publicKey", 11];
-            };
-          }
-        ];
-      };
-    }
-  ];
-  types: [
-    {
-      name: "AccountState";
-      type: {
-        kind: "enum";
-        variants: [
-          {
-            name: "Uninitialized";
-          },
-          {
-            name: "Initialized";
-          },
-          {
-            name: "Frozen";
-          }
-        ];
-      };
+      discriminator: [];
     },
     {
-      name: "AuthorityType";
-      type: {
-        kind: "enum";
-        variants: [
-          {
-            name: "MintTokens";
-          },
-          {
-            name: "FreezeAccount";
-          },
-          {
-            name: "AccountOwner";
-          },
-          {
-            name: "CloseAccount";
-          }
-        ];
-      };
+      name: "account";
+      discriminator: [];
     }
   ];
   errors: [
     {
       code: 0;
-      name: "NotRentExempt";
+      name: "notRentExempt";
       msg: "Lamport balance below rent-exempt threshold";
     },
     {
       code: 1;
-      name: "InsufficientFunds";
+      name: "insufficientFunds";
       msg: "Insufficient funds";
     },
     {
       code: 2;
-      name: "InvalidMint";
+      name: "invalidMint";
       msg: "Invalid Mint";
     },
     {
       code: 3;
-      name: "MintMismatch";
+      name: "mintMismatch";
       msg: "Account not associated with this Mint";
     },
     {
       code: 4;
-      name: "OwnerMismatch";
+      name: "ownerMismatch";
       msg: "Owner does not match";
     },
     {
       code: 5;
-      name: "FixedSupply";
+      name: "fixedSupply";
       msg: "Fixed supply";
     },
     {
       code: 6;
-      name: "AlreadyInUse";
+      name: "alreadyInUse";
       msg: "Already in use";
     },
     {
       code: 7;
-      name: "InvalidNumberOfProvidedSigners";
+      name: "invalidNumberOfProvidedSigners";
       msg: "Invalid number of provided signers";
     },
     {
       code: 8;
-      name: "InvalidNumberOfRequiredSigners";
+      name: "invalidNumberOfRequiredSigners";
       msg: "Invalid number of required signers";
     },
     {
       code: 9;
-      name: "UninitializedState";
+      name: "uninitializedState";
       msg: "State is unititialized";
     },
     {
       code: 10;
-      name: "NativeNotSupported";
+      name: "nativeNotSupported";
       msg: "Instruction does not support native tokens";
     },
     {
       code: 11;
-      name: "NonNativeHasBalance";
+      name: "nonNativeHasBalance";
       msg: "Non-native account can only be closed if its balance is zero";
     },
     {
       code: 12;
-      name: "InvalidInstruction";
+      name: "invalidInstruction";
       msg: "Invalid instruction";
     },
     {
       code: 13;
-      name: "InvalidState";
+      name: "invalidState";
       msg: "State is invalid for requested operation";
     },
     {
       code: 14;
-      name: "Overflow";
+      name: "overflow";
       msg: "Operation overflowed";
     },
     {
       code: 15;
-      name: "AuthorityTypeNotSupported";
+      name: "authorityTypeNotSupported";
       msg: "Account does not support specified authority type";
     },
     {
       code: 16;
-      name: "MintCannotFreeze";
+      name: "mintCannotFreeze";
       msg: "This token mint cannot freeze accounts";
     },
     {
       code: 17;
-      name: "AccountFrozen";
+      name: "accountFrozen";
       msg: "Account is frozen";
     },
     {
       code: 18;
-      name: "MintDecimalsMismatch";
+      name: "mintDecimalsMismatch";
       msg: "The provided decimals value different from the Mint decimals";
     },
     {
       code: 19;
-      name: "NonNativeNotSupported";
+      name: "nonNativeNotSupported";
       msg: "Instruction does not support non-native tokens";
     }
   ];
-};
-
-const IDL: SplToken = {
-  version: "3.3.0",
-  name: "spl_token",
-  instructions: [
+  types: [
     {
-      name: "initializeMint",
-      accounts: [
-        {
-          name: "mint",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "rent",
-          isMut: false,
-          isSigner: false,
-        },
-      ],
-      args: [
-        {
-          name: "decimals",
-          type: "u8",
-        },
-        {
-          name: "mintAuthority",
-          type: "publicKey",
-        },
-        {
-          name: "freezeAuthority",
-          type: {
-            defined: "COption",
+      name: "accountState";
+      type: {
+        kind: "enum";
+        variants: [
+          {
+            name: "uninitialized";
           },
-        },
-      ],
+          {
+            name: "initialized";
+          },
+          {
+            name: "frozen";
+          }
+        ];
+      };
     },
     {
-      name: "initializeAccount",
-      accounts: [
-        {
-          name: "account",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "mint",
-          isMut: false,
-          isSigner: false,
-        },
-        {
-          name: "owner",
-          isMut: false,
-          isSigner: false,
-        },
-        {
-          name: "rent",
-          isMut: false,
-          isSigner: false,
-        },
-      ],
-      args: [],
+      name: "authorityType";
+      type: {
+        kind: "enum";
+        variants: [
+          {
+            name: "mintTokens";
+          },
+          {
+            name: "freezeAccount";
+          },
+          {
+            name: "accountOwner";
+          },
+          {
+            name: "closeAccount";
+          }
+        ];
+      };
     },
     {
-      name: "initializeMultisig",
-      accounts: [
-        {
-          name: "multisig",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "rent",
-          isMut: false,
-          isSigner: false,
-        },
-      ],
-      args: [
-        {
-          name: "m",
-          type: "u8",
-        },
-      ],
+      name: "mint";
+      type: {
+        kind: "struct";
+        fields: [
+          {
+            name: "mintAuthority";
+            docs: [
+              "Optional authority used to mint new tokens. The mint authority may only be provided during",
+              "mint creation. If no mint authority is present then the mint has a fixed supply and no",
+              "further tokens may be minted."
+            ];
+            type: {
+              coption: "pubkey";
+            };
+          },
+          {
+            name: "supply";
+            docs: ["Total supply of tokens."];
+            type: "u64";
+          },
+          {
+            name: "decimals";
+            docs: [
+              "Number of base 10 digits to the right of the decimal place."
+            ];
+            type: "u8";
+          },
+          {
+            name: "isInitialized";
+            docs: ["Is `true` if this structure has been initialized"];
+            type: "bool";
+          },
+          {
+            name: "freezeAuthority";
+            docs: ["Optional authority to freeze token accounts."];
+            type: {
+              coption: "pubkey";
+            };
+          }
+        ];
+      };
     },
     {
-      name: "transfer",
+      name: "multisig";
+      type: {
+        kind: "struct";
+        fields: [
+          {
+            name: "m";
+            docs: ["Number of signers required"];
+            type: "u8";
+          },
+          {
+            name: "n";
+            docs: ["Number of valid signers"];
+            type: "u8";
+          },
+          {
+            name: "isInitialized";
+            docs: ["Is `true` if this structure has been initialized"];
+            type: "bool";
+          },
+          {
+            name: "signers";
+            docs: ["Signer public keys"];
+            type: {
+              array: ["pubkey", 11];
+            };
+          }
+        ];
+      };
+    },
+    {
+      name: "account";
+      type: {
+        kind: "struct";
+        fields: [
+          {
+            name: "mint";
+            docs: ["The mint associated with this account"];
+            type: "pubkey";
+          },
+          {
+            name: "owner";
+            docs: ["The owner of this account."];
+            type: "pubkey";
+          },
+          {
+            name: "amount";
+            docs: ["The amount of tokens this account holds."];
+            type: "u64";
+          },
+          {
+            name: "delegate";
+            docs: [
+              "If `delegate` is `Some` then `delegated_amount` represents",
+              "the amount authorized by the delegate"
+            ];
+            type: {
+              coption: "pubkey";
+            };
+          },
+          {
+            name: "state";
+            docs: ["The account's state"];
+            type: {
+              defined: {
+                name: "accountState";
+              };
+            };
+          },
+          {
+            name: "isNative";
+            docs: [
+              "If is_native.is_some, this is a native token, and the value logs the rent-exempt reserve. An",
+              "Account is required to be rent-exempt, so the value is used by the Processor to ensure that",
+              "wrapped SOL accounts do not drop below this threshold."
+            ];
+            type: {
+              coption: "u64";
+            };
+          },
+          {
+            name: "delegatedAmount";
+            docs: ["The amount delegated"];
+            type: "u64";
+          },
+          {
+            name: "closeAuthority";
+            docs: ["Optional authority to close the account."];
+            type: {
+              coption: "pubkey";
+            };
+          }
+        ];
+      };
+    }
+  ];
+};
+
+const IDL: SplToken = {
+  address: "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
+  metadata: {
+    name: "splToken",
+    version: "3.3.0",
+    spec: "0.1.0",
+  },
+  instructions: [
+    {
+      name: "amountToUiAmount",
+      discriminator: [23],
       accounts: [
         {
-          name: "source",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "destination",
-          isMut: true,
-          isSigner: false,
-        },
-        {
-          name: "authority",
-          isMut: false,
-          isSigner: true,
+          name: "mint",
         },
       ],
       args: [
@@ -973,21 +885,18 @@ const IDL: SplToken = {
     },
     {
       name: "approve",
+      discriminator: [4],
       accounts: [
         {
           name: "source",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "delegate",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "owner",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [
@@ -998,72 +907,50 @@ const IDL: SplToken = {
       ],
     },
     {
-      name: "revoke",
+      name: "approveChecked",
+      discriminator: [13],
       accounts: [
         {
           name: "source",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
-          name: "owner",
-          isMut: false,
-          isSigner: true,
+          name: "mint",
         },
-      ],
-      args: [],
-    },
-    {
-      name: "setAuthority",
-      accounts: [
         {
-          name: "owned",
-          isMut: true,
-          isSigner: false,
+          name: "delegate",
         },
         {
           name: "owner",
-          isMut: false,
-          isSigner: true,
-        },
-        {
-          name: "signer",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [
         {
-          name: "authorityType",
-          type: {
-            defined: "AuthorityType",
-          },
+          name: "amount",
+          type: "u64",
         },
         {
-          name: "newAuthority",
-          type: {
-            defined: "COption",
-          },
+          name: "decimals",
+          type: "u8",
         },
       ],
     },
     {
-      name: "mintTo",
+      name: "burn",
+      discriminator: [8],
       accounts: [
         {
-          name: "mint",
-          isMut: true,
-          isSigner: false,
+          name: "account",
+          writable: true,
         },
         {
-          name: "account",
-          isMut: true,
-          isSigner: false,
+          name: "mint",
+          writable: true,
         },
         {
-          name: "owner",
-          isMut: false,
-          isSigner: true,
+          name: "authority",
+          signer: true,
         },
       ],
       args: [
@@ -1074,22 +961,20 @@ const IDL: SplToken = {
       ],
     },
     {
-      name: "burn",
+      name: "burnChecked",
+      discriminator: [15],
       accounts: [
         {
           name: "account",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "mint",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "authority",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [
@@ -1097,335 +982,400 @@ const IDL: SplToken = {
           name: "amount",
           type: "u64",
         },
+        {
+          name: "decimals",
+          type: "u8",
+        },
       ],
     },
     {
       name: "closeAccount",
+      discriminator: [9],
       accounts: [
         {
           name: "account",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "destination",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "owner",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [],
     },
     {
       name: "freezeAccount",
+      discriminator: [10],
       accounts: [
         {
           name: "account",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
           name: "mint",
-          isMut: false,
-          isSigner: false,
         },
         {
           name: "owner",
-          isMut: false,
-          isSigner: true,
+          signer: true,
         },
       ],
       args: [],
     },
     {
-      name: "thawAccount",
+      name: "getAccountDataSize",
+      discriminator: [21],
       accounts: [
-        {
-          name: "account",
-          isMut: true,
-          isSigner: false,
-        },
         {
           name: "mint",
-          isMut: false,
-          isSigner: false,
-        },
-        {
-          name: "owner",
-          isMut: false,
-          isSigner: true,
         },
       ],
       args: [],
     },
     {
-      name: "transferChecked",
+      name: "initializeAccount",
+      discriminator: [1],
       accounts: [
         {
-          name: "source",
-          isMut: true,
-          isSigner: false,
+          name: "account",
+          writable: true,
         },
         {
           name: "mint",
-          isMut: false,
-          isSigner: false,
-        },
-        {
-          name: "destination",
-          isMut: true,
-          isSigner: false,
         },
         {
-          name: "authority",
-          isMut: false,
-          isSigner: true,
-        },
-      ],
-      args: [
-        {
-          name: "amount",
-          type: "u64",
+          name: "owner",
         },
         {
-          name: "decimals",
-          type: "u8",
+          name: "rent",
+          address: "SysvarRent111111111111111111111111111111111",
         },
       ],
+      args: [],
     },
     {
-      name: "approveChecked",
+      name: "initializeAccount2",
+      discriminator: [16],
       accounts: [
         {
-          name: "source",
-          isMut: true,
-          isSigner: false,
+          name: "account",
+          writable: true,
         },
         {
           name: "mint",
-          isMut: false,
-          isSigner: false,
         },
         {
-          name: "delegate",
-          isMut: false,
-          isSigner: false,
-        },
-        {
-          name: "owner",
-          isMut: false,
-          isSigner: true,
+          name: "rent",
+          address: "SysvarRent111111111111111111111111111111111",
         },
       ],
       args: [
         {
-          name: "amount",
-          type: "u64",
-        },
-        {
-          name: "decimals",
-          type: "u8",
+          name: "owner",
+          type: "pubkey",
         },
       ],
     },
     {
-      name: "mintToChecked",
+      name: "initializeAccount3",
+      discriminator: [18],
       accounts: [
-        {
-          name: "mint",
-          isMut: true,
-          isSigner: false,
-        },
         {
           name: "account",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
-          name: "owner",
-          isMut: false,
-          isSigner: true,
+          name: "mint",
         },
       ],
       args: [
         {
-          name: "amount",
-          type: "u64",
-        },
-        {
-          name: "decimals",
-          type: "u8",
+          name: "owner",
+          type: "pubkey",
         },
       ],
     },
     {
-      name: "burnChecked",
+      name: "initializeImmutableOwner",
+      discriminator: [22],
       accounts: [
         {
           name: "account",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
+      ],
+      args: [],
+    },
+    {
+      name: "initializeMint",
+      discriminator: [0],
+      accounts: [
         {
           name: "mint",
-          isMut: true,
-          isSigner: false,
+          writable: true,
         },
         {
-          name: "authority",
-          isMut: false,
-          isSigner: true,
+          name: "rent",
+          address: "SysvarRent111111111111111111111111111111111",
         },
       ],
       args: [
-        {
-          name: "amount",
-          type: "u64",
-        },
         {
           name: "decimals",
           type: "u8",
         },
+        {
+          name: "mintAuthority",
+          type: "pubkey",
+        },
+        {
+          name: "freezeAuthority",
+          type: {
+            coption: "pubkey",
+          },
+        },
       ],
     },
     {
-      name: "initializeAccount2",
+      name: "initializeMint2",
+      discriminator: [20],
       accounts: [
         {
-          name: "account",
-          isMut: true,
-          isSigner: false,
+          name: "mint",
+          writable: true,
         },
+      ],
+      args: [
         {
-          name: "mint",
-          isMut: false,
-          isSigner: false,
+          name: "decimals",
+          type: "u8",
         },
         {
-          name: "rent",
-          isMut: false,
-          isSigner: false,
+          name: "mintAuthority",
+          type: "pubkey",
         },
-      ],
-      args: [
         {
-          name: "owner",
-          type: "publicKey",
+          name: "freezeAuthority",
+          type: {
+            coption: "pubkey",
+          },
         },
       ],
     },
     {
-      name: "syncNative",
+      name: "initializeMultisig",
+      discriminator: [2],
       accounts: [
         {
-          name: "account",
-          isMut: true,
-          isSigner: false,
+          name: "multisig",
+          writable: true,
+        },
+        {
+          name: "rent",
+          address: "SysvarRent111111111111111111111111111111111",
+        },
+      ],
+      args: [
+        {
+          name: "m",
+          type: "u8",
         },
       ],
-      args: [],
     },
     {
-      name: "initializeAccount3",
+      name: "initializeMultisig2",
+      discriminator: [19],
       accounts: [
         {
-          name: "account",
-          isMut: true,
-          isSigner: false,
+          name: "multisig",
+          writable: true,
         },
         {
-          name: "mint",
-          isMut: false,
-          isSigner: false,
+          name: "signer",
         },
       ],
       args: [
         {
-          name: "owner",
-          type: "publicKey",
+          name: "m",
+          type: "u8",
         },
       ],
     },
     {
-      name: "initializeMultisig2",
+      name: "mintTo",
+      discriminator: [7],
       accounts: [
         {
-          name: "multisig",
-          isMut: true,
-          isSigner: false,
+          name: "mint",
+          writable: true,
         },
         {
-          name: "signer",
-          isMut: false,
-          isSigner: false,
+          name: "account",
+          writable: true,
+        },
+        {
+          name: "owner",
+          signer: true,
         },
       ],
       args: [
         {
-          name: "m",
-          type: "u8",
+          name: "amount",
+          type: "u64",
         },
       ],
     },
     {
-      name: "initializeMint2",
+      name: "mintToChecked",
+      discriminator: [14],
       accounts: [
         {
           name: "mint",
-          isMut: true,
-          isSigner: false,
+          writable: true,
+        },
+        {
+          name: "account",
+          writable: true,
+        },
+        {
+          name: "owner",
+          signer: true,
         },
       ],
       args: [
+        {
+          name: "amount",
+          type: "u64",
+        },
         {
           name: "decimals",
           type: "u8",
         },
+      ],
+    },
+    {
+      name: "revoke",
+      discriminator: [5],
+      accounts: [
+        {
+          name: "source",
+          writable: true,
+        },
         {
-          name: "mintAuthority",
-          type: "publicKey",
+          name: "owner",
+          signer: true,
+        },
+      ],
+      args: [],
+    },
+    {
+      name: "setAuthority",
+      discriminator: [6],
+      accounts: [
+        {
+          name: "owned",
+          writable: true,
         },
         {
-          name: "freezeAuthority",
+          name: "owner",
+          signer: true,
+        },
+        {
+          name: "signer",
+          signer: true,
+        },
+      ],
+      args: [
+        {
+          name: "authorityType",
+          type: {
+            defined: {
+              name: "authorityType",
+            },
+          },
+        },
+        {
+          name: "newAuthority",
           type: {
-            defined: "COption",
+            coption: "pubkey",
           },
         },
       ],
     },
     {
-      name: "getAccountDataSize",
+      name: "syncNative",
+      discriminator: [17],
       accounts: [
         {
-          name: "mint",
-          isMut: false,
-          isSigner: false,
+          name: "account",
+          writable: true,
         },
       ],
       args: [],
     },
     {
-      name: "initializeImmutableOwner",
+      name: "thawAccount",
+      discriminator: [11],
       accounts: [
         {
           name: "account",
-          isMut: true,
-          isSigner: false,
+          writable: true,
+        },
+        {
+          name: "mint",
+        },
+        {
+          name: "owner",
+          signer: true,
         },
       ],
       args: [],
     },
     {
-      name: "amountToUiAmount",
+      name: "transfer",
+      discriminator: [3],
       accounts: [
+        {
+          name: "source",
+          writable: true,
+        },
+        {
+          name: "destination",
+          writable: true,
+        },
+        {
+          name: "authority",
+          signer: true,
+        },
+      ],
+      args: [
+        {
+          name: "amount",
+          type: "u64",
+        },
+      ],
+    },
+    {
+      name: "transferChecked",
+      discriminator: [12],
+      accounts: [
+        {
+          name: "source",
+          writable: true,
+        },
         {
           name: "mint",
-          isMut: false,
-          isSigner: false,
+        },
+        {
+          name: "destination",
+          writable: true,
+        },
+        {
+          name: "authority",
+          signer: true,
         },
       ],
       args: [
@@ -1433,23 +1383,24 @@ const IDL: SplToken = {
           name: "amount",
           type: "u64",
         },
+        {
+          name: "decimals",
+          type: "u8",
+        },
       ],
     },
     {
       name: "uiAmountToAmount",
+      discriminator: [24],
       accounts: [
         {
           name: "mint",
-          isMut: false,
-          isSigner: false,
         },
       ],
       args: [
         {
           name: "uiAmount",
-          type: {
-            defined: "&'astr",
-          },
+          type: "string",
         },
       ],
     },
@@ -1457,250 +1408,294 @@ const IDL: SplToken = {
   accounts: [
     {
       name: "mint",
-      type: {
-        kind: "struct",
-        fields: [
-          {
-            name: "mintAuthority",
-            type: {
-              defined: "COption",
-            },
-          },
-          {
-            name: "supply",
-            type: "u64",
-          },
-          {
-            name: "decimals",
-            type: "u8",
-          },
-          {
-            name: "isInitialized",
-            type: "bool",
-          },
-          {
-            name: "freezeAuthority",
-            type: {
-              defined: "COption",
-            },
-          },
-        ],
-      },
-    },
-    {
-      name: "account",
-      type: {
-        kind: "struct",
-        fields: [
-          {
-            name: "mint",
-            type: "publicKey",
-          },
-          {
-            name: "owner",
-            type: "publicKey",
-          },
-          {
-            name: "amount",
-            type: "u64",
-          },
-          {
-            name: "delegate",
-            type: {
-              defined: "COption",
-            },
-          },
-          {
-            name: "state",
-            type: {
-              defined: "AccountState",
-            },
-          },
-          {
-            name: "isNative",
-            type: {
-              defined: "COption",
-            },
-          },
-          {
-            name: "delegatedAmount",
-            type: "u64",
-          },
-          {
-            name: "closeAuthority",
-            type: {
-              defined: "COption",
-            },
-          },
-        ],
-      },
+      discriminator: [],
     },
     {
       name: "multisig",
-      type: {
-        kind: "struct",
-        fields: [
-          {
-            name: "m",
-            type: "u8",
-          },
-          {
-            name: "n",
-            type: "u8",
-          },
-          {
-            name: "isInitialized",
-            type: "bool",
-          },
-          {
-            name: "signers",
-            type: {
-              array: ["publicKey", 11],
-            },
-          },
-        ],
-      },
-    },
-  ],
-  types: [
-    {
-      name: "AccountState",
-      type: {
-        kind: "enum",
-        variants: [
-          {
-            name: "Uninitialized",
-          },
-          {
-            name: "Initialized",
-          },
-          {
-            name: "Frozen",
-          },
-        ],
-      },
+      discriminator: [],
     },
     {
-      name: "AuthorityType",
-      type: {
-        kind: "enum",
-        variants: [
-          {
-            name: "MintTokens",
-          },
-          {
-            name: "FreezeAccount",
-          },
-          {
-            name: "AccountOwner",
-          },
-          {
-            name: "CloseAccount",
-          },
-        ],
-      },
+      name: "account",
+      discriminator: [],
     },
   ],
   errors: [
     {
       code: 0,
-      name: "NotRentExempt",
+      name: "notRentExempt",
       msg: "Lamport balance below rent-exempt threshold",
     },
     {
       code: 1,
-      name: "InsufficientFunds",
+      name: "insufficientFunds",
       msg: "Insufficient funds",
     },
     {
       code: 2,
-      name: "InvalidMint",
+      name: "invalidMint",
       msg: "Invalid Mint",
     },
     {
       code: 3,
-      name: "MintMismatch",
+      name: "mintMismatch",
       msg: "Account not associated with this Mint",
     },
     {
       code: 4,
-      name: "OwnerMismatch",
+      name: "ownerMismatch",
       msg: "Owner does not match",
     },
     {
       code: 5,
-      name: "FixedSupply",
+      name: "fixedSupply",
       msg: "Fixed supply",
     },
     {
       code: 6,
-      name: "AlreadyInUse",
+      name: "alreadyInUse",
       msg: "Already in use",
     },
     {
       code: 7,
-      name: "InvalidNumberOfProvidedSigners",
+      name: "invalidNumberOfProvidedSigners",
       msg: "Invalid number of provided signers",
     },
     {
       code: 8,
-      name: "InvalidNumberOfRequiredSigners",
+      name: "invalidNumberOfRequiredSigners",
       msg: "Invalid number of required signers",
     },
     {
       code: 9,
-      name: "UninitializedState",
+      name: "uninitializedState",
       msg: "State is unititialized",
     },
     {
       code: 10,
-      name: "NativeNotSupported",
+      name: "nativeNotSupported",
       msg: "Instruction does not support native tokens",
     },
     {
       code: 11,
-      name: "NonNativeHasBalance",
+      name: "nonNativeHasBalance",
       msg: "Non-native account can only be closed if its balance is zero",
     },
     {
       code: 12,
-      name: "InvalidInstruction",
+      name: "invalidInstruction",
       msg: "Invalid instruction",
     },
     {
       code: 13,
-      name: "InvalidState",
+      name: "invalidState",
       msg: "State is invalid for requested operation",
     },
     {
       code: 14,
-      name: "Overflow",
+      name: "overflow",
       msg: "Operation overflowed",
     },
     {
       code: 15,
-      name: "AuthorityTypeNotSupported",
+      name: "authorityTypeNotSupported",
       msg: "Account does not support specified authority type",
     },
     {
       code: 16,
-      name: "MintCannotFreeze",
+      name: "mintCannotFreeze",
       msg: "This token mint cannot freeze accounts",
     },
     {
       code: 17,
-      name: "AccountFrozen",
+      name: "accountFrozen",
       msg: "Account is frozen",
     },
     {
       code: 18,
-      name: "MintDecimalsMismatch",
+      name: "mintDecimalsMismatch",
       msg: "The provided decimals value different from the Mint decimals",
     },
     {
       code: 19,
-      name: "NonNativeNotSupported",
+      name: "nonNativeNotSupported",
       msg: "Instruction does not support non-native tokens",
     },
   ],
+  types: [
+    {
+      name: "accountState",
+      type: {
+        kind: "enum",
+        variants: [
+          {
+            name: "uninitialized",
+          },
+          {
+            name: "initialized",
+          },
+          {
+            name: "frozen",
+          },
+        ],
+      },
+    },
+    {
+      name: "authorityType",
+      type: {
+        kind: "enum",
+        variants: [
+          {
+            name: "mintTokens",
+          },
+          {
+            name: "freezeAccount",
+          },
+          {
+            name: "accountOwner",
+          },
+          {
+            name: "closeAccount",
+          },
+        ],
+      },
+    },
+    {
+      name: "mint",
+      type: {
+        kind: "struct",
+        fields: [
+          {
+            name: "mintAuthority",
+            docs: [
+              "Optional authority used to mint new tokens. The mint authority may only be provided during",
+              "mint creation. If no mint authority is present then the mint has a fixed supply and no",
+              "further tokens may be minted.",
+            ],
+            type: {
+              coption: "pubkey",
+            },
+          },
+          {
+            name: "supply",
+            docs: ["Total supply of tokens."],
+            type: "u64",
+          },
+          {
+            name: "decimals",
+            docs: [
+              "Number of base 10 digits to the right of the decimal place.",
+            ],
+            type: "u8",
+          },
+          {
+            name: "isInitialized",
+            docs: ["Is `true` if this structure has been initialized"],
+            type: "bool",
+          },
+          {
+            name: "freezeAuthority",
+            docs: ["Optional authority to freeze token accounts."],
+            type: {
+              coption: "pubkey",
+            },
+          },
+        ],
+      },
+    },
+    {
+      name: "multisig",
+      type: {
+        kind: "struct",
+        fields: [
+          {
+            name: "m",
+            docs: ["Number of signers required"],
+            type: "u8",
+          },
+          {
+            name: "n",
+            docs: ["Number of valid signers"],
+            type: "u8",
+          },
+          {
+            name: "isInitialized",
+            docs: ["Is `true` if this structure has been initialized"],
+            type: "bool",
+          },
+          {
+            name: "signers",
+            docs: ["Signer public keys"],
+            type: {
+              array: ["pubkey", 11],
+            },
+          },
+        ],
+      },
+    },
+    {
+      name: "account",
+      type: {
+        kind: "struct",
+        fields: [
+          {
+            name: "mint",
+            docs: ["The mint associated with this account"],
+            type: "pubkey",
+          },
+          {
+            name: "owner",
+            docs: ["The owner of this account."],
+            type: "pubkey",
+          },
+          {
+            name: "amount",
+            docs: ["The amount of tokens this account holds."],
+            type: "u64",
+          },
+          {
+            name: "delegate",
+            docs: [
+              "If `delegate` is `Some` then `delegated_amount` represents",
+              "the amount authorized by the delegate",
+            ],
+            type: {
+              coption: "pubkey",
+            },
+          },
+          {
+            name: "state",
+            docs: ["The account's state"],
+            type: {
+              defined: {
+                name: "accountState",
+              },
+            },
+          },
+          {
+            name: "isNative",
+            docs: [
+              "If is_native.is_some, this is a native token, and the value logs the rent-exempt reserve. An",
+              "Account is required to be rent-exempt, so the value is used by the Processor to ensure that",
+              "wrapped SOL accounts do not drop below this threshold.",
+            ],
+            type: {
+              coption: "u64",
+            },
+          },
+          {
+            name: "delegatedAmount",
+            docs: ["The amount delegated"],
+            type: "u64",
+          },
+          {
+            name: "closeAuthority",
+            docs: ["Optional authority to close the account."],
+            type: {
+              coption: "pubkey",
+            },
+          },
+        ],
+      },
+    },
+  ],
 };
diff --git a/ts/yarn.lock b/ts/yarn.lock
index a83061dc3b..7dcb93a659 100644
--- a/ts/yarn.lock
+++ b/ts/yarn.lock
@@ -24,6 +24,14 @@
   dependencies:
     "@babel/highlight" "^7.18.6"
 
+"@babel/code-frame@^7.23.5", "@babel/code-frame@^7.24.1":
+  version "7.24.2"
+  resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.24.2.tgz#718b4b19841809a58b29b68cde80bc5e1aa6d9ae"
+  integrity sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==
+  dependencies:
+    "@babel/highlight" "^7.24.2"
+    picocolors "^1.0.0"
+
 "@babel/compat-data@^7.20.0":
   version "7.20.5"
   resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.20.5.tgz#86f172690b093373a933223b4745deeb6049e733"
@@ -59,6 +67,16 @@
     "@jridgewell/gen-mapping" "^0.3.2"
     jsesc "^2.5.1"
 
+"@babel/generator@^7.24.1":
+  version "7.24.4"
+  resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.24.4.tgz#1fc55532b88adf952025d5d2d1e71f946cb1c498"
+  integrity sha512-Xd6+v6SnjWVx/nus+y0l1sxMOTOMBkyL4+BIdbALyatQnAe/SRVjANeDPSCYaX+i1iJmuGSKf3Z+E+V/va1Hvw==
+  dependencies:
+    "@babel/types" "^7.24.0"
+    "@jridgewell/gen-mapping" "^0.3.5"
+    "@jridgewell/trace-mapping" "^0.3.25"
+    jsesc "^2.5.1"
+
 "@babel/helper-compilation-targets@^7.20.0":
   version "7.20.0"
   resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.20.0.tgz#6bf5374d424e1b3922822f1d9bdaa43b1a139d0a"
@@ -74,20 +92,25 @@
   resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be"
   integrity sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==
 
-"@babel/helper-function-name@^7.19.0":
-  version "7.19.0"
-  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz#941574ed5390682e872e52d3f38ce9d1bef4648c"
-  integrity sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==
+"@babel/helper-environment-visitor@^7.22.20":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz#96159db61d34a29dba454c959f5ae4a649ba9167"
+  integrity sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==
+
+"@babel/helper-function-name@^7.23.0":
+  version "7.23.0"
+  resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz#1f9a3cdbd5b2698a670c30d2735f9af95ed52759"
+  integrity sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==
   dependencies:
-    "@babel/template" "^7.18.10"
-    "@babel/types" "^7.19.0"
+    "@babel/template" "^7.22.15"
+    "@babel/types" "^7.23.0"
 
-"@babel/helper-hoist-variables@^7.18.6":
-  version "7.18.6"
-  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678"
-  integrity sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==
+"@babel/helper-hoist-variables@^7.22.5":
+  version "7.22.5"
+  resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz#c01a007dac05c085914e8fb652b339db50d823bb"
+  integrity sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==
   dependencies:
-    "@babel/types" "^7.18.6"
+    "@babel/types" "^7.22.5"
 
 "@babel/helper-module-imports@^7.18.6":
   version "7.18.6"
@@ -129,16 +152,33 @@
   dependencies:
     "@babel/types" "^7.18.6"
 
+"@babel/helper-split-export-declaration@^7.22.6":
+  version "7.22.6"
+  resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz#322c61b7310c0997fe4c323955667f18fcefb91c"
+  integrity sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==
+  dependencies:
+    "@babel/types" "^7.22.5"
+
 "@babel/helper-string-parser@^7.19.4":
   version "7.19.4"
   resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63"
   integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==
 
+"@babel/helper-string-parser@^7.23.4":
+  version "7.24.1"
+  resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz#f99c36d3593db9540705d0739a1f10b5e20c696e"
+  integrity sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==
+
 "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1":
   version "7.19.1"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2"
   integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==
 
+"@babel/helper-validator-identifier@^7.22.20":
+  version "7.22.20"
+  resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz#c4ae002c61d2879e724581d96665583dbc1dc0e0"
+  integrity sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==
+
 "@babel/helper-validator-option@^7.18.6":
   version "7.18.6"
   resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.18.6.tgz#bf0d2b5a509b1f336099e4ff36e1a63aa5db4db8"
@@ -162,11 +202,26 @@
     chalk "^2.0.0"
     js-tokens "^4.0.0"
 
+"@babel/highlight@^7.24.2":
+  version "7.24.2"
+  resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.24.2.tgz#3f539503efc83d3c59080a10e6634306e0370d26"
+  integrity sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==
+  dependencies:
+    "@babel/helper-validator-identifier" "^7.22.20"
+    chalk "^2.4.2"
+    js-tokens "^4.0.0"
+    picocolors "^1.0.0"
+
 "@babel/parser@^7.1.0", "@babel/parser@^7.14.7", "@babel/parser@^7.18.10", "@babel/parser@^7.20.5":
   version "7.20.5"
   resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.20.5.tgz#7f3c7335fe417665d929f34ae5dceae4c04015e8"
   integrity sha512-r27t/cy/m9uKLXQNWWebeCUHgnAZq0CpG1OwKRxzJMP1vpSU4bSIK2hq+/cp0bQxetkXx38n09rNu8jVkcK/zA==
 
+"@babel/parser@^7.24.0", "@babel/parser@^7.24.1":
+  version "7.24.4"
+  resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.24.4.tgz#234487a110d89ad5a3ed4a8a566c36b9453e8c88"
+  integrity sha512-zTvEBcghmeBma9QIGunWevvBAp4/Qu9Bdq+2k0Ot4fVMD6v3dsC9WOcRSKk7tRRyBM/53yKMJko9xOatGQAwSg==
+
 "@babel/plugin-syntax-async-generators@^7.8.4":
   version "7.8.4"
   resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d"
@@ -274,23 +329,32 @@
     "@babel/parser" "^7.18.10"
     "@babel/types" "^7.18.10"
 
-"@babel/traverse@^7.20.1", "@babel/traverse@^7.20.5", "@babel/traverse@^7.7.2":
-  version "7.20.5"
-  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.20.5.tgz#78eb244bea8270fdda1ef9af22a5d5e5b7e57133"
-  integrity sha512-WM5ZNN3JITQIq9tFZaw1ojLU3WgWdtkxnhM1AegMS+PvHjkM5IXjmYEGY7yukz5XS4sJyEf2VzWjI8uAavhxBQ==
+"@babel/template@^7.22.15":
+  version "7.24.0"
+  resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.24.0.tgz#c6a524aa93a4a05d66aaf31654258fae69d87d50"
+  integrity sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==
   dependencies:
-    "@babel/code-frame" "^7.18.6"
-    "@babel/generator" "^7.20.5"
-    "@babel/helper-environment-visitor" "^7.18.9"
-    "@babel/helper-function-name" "^7.19.0"
-    "@babel/helper-hoist-variables" "^7.18.6"
-    "@babel/helper-split-export-declaration" "^7.18.6"
-    "@babel/parser" "^7.20.5"
-    "@babel/types" "^7.20.5"
-    debug "^4.1.0"
+    "@babel/code-frame" "^7.23.5"
+    "@babel/parser" "^7.24.0"
+    "@babel/types" "^7.24.0"
+
+"@babel/traverse@^7.20.1", "@babel/traverse@^7.20.5", "@babel/traverse@^7.7.2":
+  version "7.24.1"
+  resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.24.1.tgz#d65c36ac9dd17282175d1e4a3c49d5b7988f530c"
+  integrity sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==
+  dependencies:
+    "@babel/code-frame" "^7.24.1"
+    "@babel/generator" "^7.24.1"
+    "@babel/helper-environment-visitor" "^7.22.20"
+    "@babel/helper-function-name" "^7.23.0"
+    "@babel/helper-hoist-variables" "^7.22.5"
+    "@babel/helper-split-export-declaration" "^7.22.6"
+    "@babel/parser" "^7.24.1"
+    "@babel/types" "^7.24.0"
+    debug "^4.3.1"
     globals "^11.1.0"
 
-"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.19.0", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
+"@babel/types@^7.0.0", "@babel/types@^7.18.10", "@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.5", "@babel/types@^7.3.0", "@babel/types@^7.3.3":
   version "7.20.5"
   resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.20.5.tgz#e206ae370b5393d94dfd1d04cd687cace53efa84"
   integrity sha512-c9fst/h2/dcF7H+MJKZ2T0KjEQ8hY/BNnDk/H3XY8C4Aw/eWQXWn/lWntHF9ooUBnGmEvbfGrTgLWc+um0YDUg==
@@ -299,6 +363,15 @@
     "@babel/helper-validator-identifier" "^7.19.1"
     to-fast-properties "^2.0.0"
 
+"@babel/types@^7.22.5", "@babel/types@^7.23.0", "@babel/types@^7.24.0":
+  version "7.24.0"
+  resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.24.0.tgz#3b951f435a92e7333eba05b7566fd297960ea1bf"
+  integrity sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==
+  dependencies:
+    "@babel/helper-string-parser" "^7.23.4"
+    "@babel/helper-validator-identifier" "^7.22.20"
+    to-fast-properties "^2.0.0"
+
 "@bcoe/v8-coverage@^0.2.3":
   version "0.2.3"
   resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39"
@@ -678,16 +751,35 @@
     "@jridgewell/sourcemap-codec" "^1.4.10"
     "@jridgewell/trace-mapping" "^0.3.9"
 
+"@jridgewell/gen-mapping@^0.3.5":
+  version "0.3.5"
+  resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz#dcce6aff74bdf6dad1a95802b69b04a2fcb1fb36"
+  integrity sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==
+  dependencies:
+    "@jridgewell/set-array" "^1.2.1"
+    "@jridgewell/sourcemap-codec" "^1.4.10"
+    "@jridgewell/trace-mapping" "^0.3.24"
+
 "@jridgewell/resolve-uri@3.1.0", "@jridgewell/resolve-uri@^3.0.3":
   version "3.1.0"
   resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78"
   integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==
 
+"@jridgewell/resolve-uri@^3.1.0":
+  version "3.1.2"
+  resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6"
+  integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==
+
 "@jridgewell/set-array@^1.0.0", "@jridgewell/set-array@^1.0.1":
   version "1.1.2"
   resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72"
   integrity sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==
 
+"@jridgewell/set-array@^1.2.1":
+  version "1.2.1"
+  resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.2.1.tgz#558fb6472ed16a4c850b889530e6b36438c49280"
+  integrity sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==
+
 "@jridgewell/source-map@^0.3.2":
   version "0.3.2"
   resolved "https://registry.yarnpkg.com/@jridgewell/source-map/-/source-map-0.3.2.tgz#f45351aaed4527a298512ec72f81040c998580fb"
@@ -701,6 +793,11 @@
   resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz#add4c98d341472a289190b424efbdb096991bb24"
   integrity sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==
 
+"@jridgewell/sourcemap-codec@^1.4.14":
+  version "1.4.15"
+  resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32"
+  integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==
+
 "@jridgewell/trace-mapping@0.3.9":
   version "0.3.9"
   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz#6534fd5933a53ba7cbf3a17615e273a0d1273ff9"
@@ -709,6 +806,14 @@
     "@jridgewell/resolve-uri" "^3.0.3"
     "@jridgewell/sourcemap-codec" "^1.4.10"
 
+"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.25":
+  version "0.3.25"
+  resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz#15f190e98895f3fc23276ee14bc76b675c2e50f0"
+  integrity sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==
+  dependencies:
+    "@jridgewell/resolve-uri" "^3.1.0"
+    "@jridgewell/sourcemap-codec" "^1.4.14"
+
 "@jridgewell/trace-mapping@^0.3.9":
   version "0.3.17"
   resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz#793041277af9073b0951a7fe0f0d8c4c98c36985"
@@ -1588,7 +1693,7 @@ chalk@4.1.0:
     ansi-styles "^4.1.0"
     supports-color "^7.1.0"
 
-chalk@^2.0.0:
+chalk@^2.0.0, chalk@^2.4.2:
   version "2.4.2"
   resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424"
   integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==
diff --git a/version-bump.sh b/version-bump.sh
index 725ab1b762..731c0d1151 100755
--- a/version-bump.sh
+++ b/version-bump.sh
@@ -18,25 +18,23 @@ case "$(uname)" in
   Darwin*) sedi=(-i "")
 esac
 
-# Don't replace version with the following globs
-skip_globs=":!**/yarn.lock :!Cargo.lock :!package.json :!tests/bench/bench.json :!bench/*.md"
-
-git grep -l $(cat VERSION) -- $skip_globs |
+# Only replace version with the following globs
+allow_globs=":**/Cargo.toml **/Makefile docs/src/pages/docs/*.md client/src/lib.rs"
+git grep -l $(cat VERSION) -- $allow_globs |
     xargs sed "${sedi[@]}" \
     -e "s/$(cat VERSION)/$version/g"
 
-# Potential for collisions in package.json files, handle those separately
+# Potential for collisions in `package.json` files, handle those separately
 # Replace only matching "version": "x.xx.x" and "@coral-xyz/anchor": "x.xx.x"
-git grep -l $(cat VERSION) -- '**/package.json' | \
+git grep -l $(cat VERSION) -- "**/package.json" | \
     xargs sed "${sedi[@]}" \
     -e "s/@coral-xyz\/anchor\": \"$(cat VERSION)\"/@coral-xyz\/anchor\": \"$version\"/g" \
     -e "s/\"version\": \"$(cat VERSION)\"/\"version\": \"$version\"/g"
 
-# Potential for collisions in Cargo.lock, use cargo update to update it
-cargo update --workspace
-
-# Insert version number into CHANGELOG.md
-sed "${sedi[@]}" -e "s/## \[Unreleased\]/## [Unreleased]\n\n## [$version] - $(date '+%Y-%m-%d')/g" CHANGELOG.md
+# Insert version number into CHANGELOG
+sed "${sedi[@]}" -e \
+    "s/## \[Unreleased\]/## [Unreleased]\n\n### Features\n\n### Fixes\n\n### Breaking\n\n## [$version] - $(date '+%Y-%m-%d')/g" \
+    CHANGELOG.md
 
 pushd ts && yarn && popd
 pushd tests && yarn && popd