diff --git a/.github/.env b/.github/.env index 0273f9e5..544a1168 100644 --- a/.github/.env +++ b/.github/.env @@ -1,8 +1,8 @@ CARGO_TERM_COLOR=always NODE_VERSION=20.x PROGRAMS=["mpl-core"] -RUST_VERSION=1.75.0 -SOLANA_VERSION=1.17.25 +RUST_VERSION=1.88.0 +SOLANA_VERSION=2.3.5 COMMIT_USER_NAME=github-actions COMMIT_USER_EMAIL=github-actions@github.com -DEPLOY_SOLANA_VERSION=1.18.14 +DEPLOY_SOLANA_VERSION=2.3.5 diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 00000000..2a30ae63 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,12 @@ +version: 2 +updates: + # We use pnpm for package management. + - package-ecosystem: 'npm' + # We only have a package.json in the root. + directory: '/' + # Check weekly to prevent too many PRs. + schedule: + interval: 'weekly' + allow: + # Starting slow by only checking our own packages for updates. + - dependency-name: '@metaplex-foundation/*' diff --git a/.github/workflows/build-programs.yml b/.github/workflows/build-programs.yml index 97fa4237..5c77d7a6 100644 --- a/.github/workflows/build-programs.yml +++ b/.github/workflows/build-programs.yml @@ -1,81 +1,89 @@ name: Build Programs on: - workflow_call: - inputs: - rust: - type: string - solana: - type: string - git_ref: - type: string - workflow_dispatch: - inputs: - rust: - description: Rust version - default: 1.70.0 - required: true - type: string - solana: - description: Solana version - default: 1.16.17 - required: true - type: string + workflow_call: + inputs: + rust: + type: string + solana: + type: string + git_ref: + type: string + workflow_dispatch: + inputs: + rust: + description: Rust version + default: 1.83.0 + required: true + type: string + solana: + description: Solana version + default: 2.2.1 + required: true + type: string env: - CACHE: true + CACHE: true jobs: - build_programs: - name: Build - runs-on: ubuntu-latest - steps: - - name: Git checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.git_ref }} + build_programs: + name: Build + runs-on: ubuntu-latest + steps: + - name: Git checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.git_ref }} - - name: Load environment variables - run: cat .github/.env >> $GITHUB_ENV + - name: Load environment variables + run: cat .github/.env >> $GITHUB_ENV - - name: Install Rust - uses: metaplex-foundation/actions/install-rust@v1 - with: - toolchain: ${{ inputs.rust || env.RUST_VERSION }} + - name: Install Rust + uses: metaplex-foundation/actions/install-rust@v1 + with: + toolchain: ${{ inputs.rust || env.RUST_VERSION }} - - name: Install Solana - uses: metaplex-foundation/actions/install-solana@v1 - with: - version: ${{ inputs.solana || env.SOLANA_VERSION }} - cache: ${{ env.CACHE }} + - name: Install Solana + uses: metaplex-foundation/actions/install-solana@v1 + with: + version: ${{ inputs.solana || env.SOLANA_VERSION }} + cache: ${{ env.CACHE }} - - name: Cache program dependencies - if: env.CACHE == 'true' - uses: metaplex-foundation/actions/cache-programs@v1 + - name: Install modern SBF build tools + run: | + cargo install solana-cargo-build-sbf --version 4.0.0 --locked + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - - name: Build programs - shell: bash - working-directory: configs/scripts/program - run: ./build.sh - env: - PROGRAMS: ${{ env.PROGRAMS }} + - name: Install Protobuf Compiler + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler - - name: Sanitize Ref - id: sanitize - shell: bash - run: | - REF="${{ inputs.git_ref }}" - if [ -z "$REF" ]; then - REF="default" - fi - SANITIZED=${REF//\//-} - echo "sanitized=$SANITIZED" >> "$GITHUB_OUTPUT" - - - name: Upload program builds - uses: actions/upload-artifact@v4 - with: - name: program-builds-${{ steps.sanitize.outputs.sanitized }} - # First wildcard ensures exported paths are consistently under the programs folder. - path: ./program*/.bin/*.so - include-hidden-files: true - if-no-files-found: error + - name: Cache program dependencies + if: env.CACHE == 'true' + uses: metaplex-foundation/actions/cache-programs@v1 + + - name: Build programs + shell: bash + working-directory: configs/scripts/program + run: ./build.sh + env: + PROGRAMS: ${{ env.PROGRAMS }} + + - name: Sanitize Ref + id: sanitize + shell: bash + run: | + REF="${{ inputs.git_ref }}" + if [ -z "$REF" ]; then + REF="default" + fi + SANITIZED=${REF//\//-} + echo "sanitized=$SANITIZED" >> "$GITHUB_OUTPUT" + + - name: Upload program builds + uses: actions/upload-artifact@v4 + with: + name: program-builds-${{ steps.sanitize.outputs.sanitized }} + # First wildcard ensures exported paths are consistently under the programs folder. + path: ./program*/.bin/*.so + include-hidden-files: true + if-no-files-found: error diff --git a/.github/workflows/build-rust-client.yml b/.github/workflows/build-rust-client.yml index d3e001bc..45fd1d07 100644 --- a/.github/workflows/build-rust-client.yml +++ b/.github/workflows/build-rust-client.yml @@ -1,75 +1,78 @@ name: Build Rust Client on: - workflow_call: - inputs: - rust: - type: string - solana: - type: string - git_ref: - type: string - workflow_dispatch: - inputs: - rust: - description: Rust version - default: 1.70.0 - required: true - type: string - solana: - description: Solana version - default: 1.16.17 - required: true - type: string + workflow_call: + inputs: + rust: + type: string + solana: + type: string + git_ref: + type: string + workflow_dispatch: + inputs: + rust: + description: Rust version + default: 1.83.0 + required: true + type: string + solana: + description: Solana version + default: 2.2.1 + required: true + type: string env: - CACHE: true + CACHE: true jobs: - build_sdk: - name: Build - runs-on: ubuntu-latest - steps: - - name: Git checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.git_ref }} + build_sdk: + name: Build + runs-on: ubuntu-latest + steps: + - name: Git checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.git_ref }} - - name: Load environment variables - run: cat .github/.env >> $GITHUB_ENV + - name: Load environment variables + run: cat .github/.env >> $GITHUB_ENV - - name: Install Rust - uses: metaplex-foundation/actions/install-rust@v1 - with: - toolchain: ${{ inputs.rust || env.RUST_VERSION }} + - name: Install Rust + uses: metaplex-foundation/actions/install-rust@v1 + with: + toolchain: ${{ inputs.rust || env.RUST_VERSION }} - - name: Install Solana - uses: metaplex-foundation/actions/install-solana@v1 - with: - version: ${{ inputs.solana || env.SOLANA_VERSION }} - cache: ${{ env.CACHE }} + - name: Install Solana + uses: metaplex-foundation/actions/install-solana@v1 + with: + version: ${{ inputs.solana || env.SOLANA_VERSION }} + cache: ${{ env.CACHE }} - - name: Cache Rust client test dependencies - uses: metaplex-foundation/actions/cache-crate@v1 - with: - folder: ./clients/rust - key: rust-client-test + - name: Install Protobuf Compiler + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler - - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all-targets --all-features --no-deps --manifest-path ./clients/rust/Cargo.toml + - name: Cache Rust client test dependencies + uses: metaplex-foundation/actions/cache-crate@v1 + with: + folder: ./clients/rust + key: rust-client-test - - name: Build Rust client - shell: bash - working-directory: clients/rust - run: cargo build --all-features --release + - name: Run cargo clippy (default feature set) + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-targets --no-deps --manifest-path ./clients/rust/Cargo.toml - - name: Upload Rust client builds - uses: actions/upload-artifact@v4 - with: - name: rust-client-builds - # First wildcard ensures exported paths are consistently under the clients folder. - path: ./targe*/release/*mpl_core* - if-no-files-found: error + - name: Build Rust client (default feature set) + shell: bash + working-directory: clients/rust + run: cargo build --release + + - name: Upload Rust client builds + uses: actions/upload-artifact@v4 + with: + name: rust-client-builds + # First wildcard ensures exported paths are consistently under the clients folder. + path: ./targe*/release/*mpl_core* + if-no-files-found: error diff --git a/.github/workflows/publish-js-client.yml b/.github/workflows/publish-js-client.yml index fa53b190..05ee123f 100644 --- a/.github/workflows/publish-js-client.yml +++ b/.github/workflows/publish-js-client.yml @@ -3,6 +3,11 @@ name: Publish JS Client on: workflow_dispatch: inputs: + git_ref: + description: Release tag (release/genesis@0.9.2) or commit to publish from + required: false + type: string + default: '' bump: description: Version bump required: true @@ -31,35 +36,74 @@ env: CACHE: true jobs: + check_tag: + name: "Check tag" + runs-on: ubuntu-latest + outputs: + type: ${{ steps.set_type.outputs.type }} + steps: + - name: Check tag + id: set_type + run: | + if [[ "${{ inputs.git_ref }}" =~ ^release/genesis@* ]]; then + echo type="release" >> $GITHUB_OUTPUT + else + echo type="ref" >> $GITHUB_OUTPUT + fi + build_programs: name: Programs uses: ./.github/workflows/build-programs.yml secrets: inherit + needs: check_tag + if: needs.check_tag.outputs.type == 'ref' + with: + git_ref: ${{ inputs.git_ref }} test_js: name: JS client - needs: build_programs + needs: [build_programs, check_tag] uses: ./.github/workflows/test-js-client.yml secrets: inherit + if: needs.check_tag.outputs.type == 'ref' + with: + git_ref: ${{ inputs.git_ref }} publish_js: name: JS client / Publish runs-on: ubuntu-latest - needs: test_js + needs: [check_tag, test_js] + if: | + always() + && (needs.test_js.result == 'success' || needs.test_js.result == 'skipped') permissions: contents: write + packages: write + pull-requests: write + id-token: write steps: - name: Git checkout uses: actions/checkout@v4 + with: + ref: ${{ inputs.git_ref || github.ref }} - name: Load environment variables run: cat .github/.env >> $GITHUB_ENV + - name: Install pnpm + uses: pnpm/action-setup@v4 + with: + version: 8.9.0 + - name: Install Node.js - uses: metaplex-foundation/actions/install-node-with-pnpm@v1 + uses: actions/setup-node@v4 with: - version: ${{ env.NODE_VERSION }} - cache: ${{ env.CACHE }} + node-version: ${{ env.NODE_VERSION }} + registry-url: 'https://registry.npmjs.org' + cache: 'pnpm' + + - name: Install npm >= 11.5.1 + run: npm install -g "npm@>=11.5.1" - name: Install dependencies uses: metaplex-foundation/actions/install-node-dependencies@v1 @@ -83,29 +127,26 @@ jobs: fi echo "new_version=$(pnpm pkg get version | sed 's/"//g')" >> $GITHUB_OUTPUT - - name: Set publishing config - run: pnpm config set '//registry.npmjs.org/:_authToken' "${NODE_AUTH_TOKEN}" - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} - - name: Publish working-directory: ./clients/js - run: pnpm publish --no-git-checks --tag ${{ inputs.tag }} - - - name: Commit and tag new version - uses: stefanzweifel/git-auto-commit-action@v4 - with: - commit_message: Deploy JS client v${{ steps.bump.outputs.new_version }} - tagging_message: js@v${{ steps.bump.outputs.new_version }} + run: npm publish --access public --tag ${{ inputs.tag }} - - name: Create GitHub release - if: github.event.inputs.create_release == 'true' - uses: ncipollo/release-action@v1 + - name: Create release pull request + if: ${{ github.event.inputs.create_release == 'true' }} + uses: peter-evans/create-pull-request@v6 with: - tag: js@v${{ steps.bump.outputs.new_version }} + commit-message: 'chore: release JS client v${{ steps.bump.outputs.new_version }}' + branch: release/js-client-v${{ steps.bump.outputs.new_version }} + title: 'chore: release JS client v${{ steps.bump.outputs.new_version }}' + body: | + ## Summary + - publish-js-client workflow bumped the package to `${{ steps.bump.outputs.new_version }}` + - once merged, run the release workflow to tag `js@v${{ steps.bump.outputs.new_version }}` + labels: release deploy_js_docs: name: JS client / Deploy docs + if: ${{ github.event.inputs.create_release == 'true' }} runs-on: ubuntu-latest needs: publish_js environment: @@ -115,7 +156,7 @@ jobs: - name: Git checkout uses: actions/checkout@v4 with: - ref: ${{ github.ref }} + ref: ${{ inputs.git_ref || github.ref }} - name: Load environment variables run: cat .github/.env >> $GITHUB_ENV diff --git a/.github/workflows/test-programs.yml b/.github/workflows/test-programs.yml index ea5d880d..83831cf3 100644 --- a/.github/workflows/test-programs.yml +++ b/.github/workflows/test-programs.yml @@ -1,65 +1,74 @@ name: Test Programs on: - workflow_call: - inputs: - program_matrix: - type: string - git_ref: - type: string + workflow_call: + inputs: + program_matrix: + type: string + git_ref: + type: string env: - CACHE: true + CACHE: true jobs: - test_programs: - name: Test - runs-on: ubuntu-latest - strategy: - matrix: - program: ${{ fromJson(inputs.program_matrix) }} - steps: - - name: Git checkout - uses: actions/checkout@v4 - with: - ref: ${{ inputs.git_ref }} + test_programs: + name: Test + runs-on: ubuntu-latest + strategy: + matrix: + program: ${{ fromJson(inputs.program_matrix) }} + steps: + - name: Git checkout + uses: actions/checkout@v4 + with: + ref: ${{ inputs.git_ref }} - - name: Load environment variables - run: cat .github/.env >> $GITHUB_ENV + - name: Load environment variables + run: cat .github/.env >> $GITHUB_ENV - - name: Install Rust - uses: metaplex-foundation/actions/install-rust@v1 - with: - toolchain: ${{ env.RUST_VERSION }} + - name: Install Rust + uses: metaplex-foundation/actions/install-rust@v1 + with: + toolchain: ${{ env.RUST_VERSION }} - - name: Install Solana - uses: metaplex-foundation/actions/install-solana@v1 - with: - version: ${{ env.SOLANA_VERSION }} - cache: ${{ env.CACHE }} + - name: Install Solana + uses: metaplex-foundation/actions/install-solana@v1 + with: + version: ${{ env.SOLANA_VERSION }} + cache: ${{ env.CACHE }} - - name: Cache program dependencies - if: env.CACHE == 'true' - uses: metaplex-foundation/actions/cache-program@v1 - with: - folder: ./programs/${{ matrix.program }} - key: program-${{ matrix.program }} + - name: Install modern SBF test tools + run: | + cargo install solana-cargo-build-sbf --version 4.0.0 --locked + cargo install solana-cargo-test-sbf --version 4.0.0 --locked + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" - - name: Run cargo fmt - uses: actions-rs/cargo@v1 - with: - command: fmt - args: --all --manifest-path ./programs/${{ matrix.program }}/Cargo.toml -- --check + - name: Install Protobuf Compiler + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler - - name: Run cargo clippy - uses: actions-rs/cargo@v1 - with: - command: clippy - args: --all-targets --all-features --no-deps --manifest-path ./programs/${{ matrix.program }}/Cargo.toml + - name: Cache program dependencies + if: env.CACHE == 'true' + uses: metaplex-foundation/actions/cache-program@v1 + with: + folder: ./programs/${{ matrix.program }} + key: program-${{ matrix.program }} - - name: Run tests - shell: bash - working-directory: configs/scripts/program - run: RUST_LOG=error ./test.sh - env: - PROGRAM: ${{ matrix.program }} + - name: Run cargo fmt + uses: actions-rs/cargo@v1 + with: + command: fmt + args: --all --manifest-path ./programs/${{ matrix.program }}/Cargo.toml -- --check + + - name: Run cargo clippy + uses: actions-rs/cargo@v1 + with: + command: clippy + args: --all-targets --all-features --no-deps --manifest-path ./programs/${{ matrix.program }}/Cargo.toml + + - name: Run tests + shell: bash + working-directory: configs/scripts/program + run: RUST_LOG=error ./test.sh + env: + PROGRAM: ${{ matrix.program }} diff --git a/.github/workflows/test-rust-client.yml b/.github/workflows/test-rust-client.yml index 7a7dd253..e8b4fff8 100644 --- a/.github/workflows/test-rust-client.yml +++ b/.github/workflows/test-rust-client.yml @@ -35,6 +35,15 @@ jobs: version: ${{ env.SOLANA_VERSION }} cache: ${{ env.CACHE }} + - name: Install modern SBF test tools + run: | + cargo install solana-cargo-build-sbf --version 4.0.0 --locked + cargo install solana-cargo-test-sbf --version 4.0.0 --locked + echo "$HOME/.cargo/bin" >> "$GITHUB_PATH" + + - name: Install Protobuf Compiler + run: sudo apt-get update && sudo apt-get install -y protobuf-compiler + - name: Cache Rust client test dependencies uses: metaplex-foundation/actions/cache-crate@v1 with: @@ -59,4 +68,4 @@ jobs: - name: Run tests shell: bash working-directory: configs/scripts/client - run: RUST_LOG=error ./test-rust.sh \ No newline at end of file + run: RUST_LOG=error ./test-rust.sh diff --git a/.npmrc b/.npmrc new file mode 100644 index 00000000..865aaa9f --- /dev/null +++ b/.npmrc @@ -0,0 +1 @@ +only-built-dependencies[]="" \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..29379fa7 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,88 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Essential Commands + +### Building and Development +- `pnpm install` - Install workspace dependencies +- `pnpm programs:build` - Build all Rust programs and fetch dependencies +- `pnpm programs:test` - Run Rust program tests +- `pnpm programs:debug` - Run Rust program tests with logs enabled +- `pnpm clients:js:test` - Run JavaScript client tests +- `pnpm clients:rust:test` - Run Rust client tests +- `pnpm generate` - Generate IDLs and clients (shortcut for both commands below) +- `pnpm generate:idls` - Generate IDLs from Rust programs using Shank +- `pnpm generate:clients` - Generate client libraries using Kinobi + +### Testing and Quality +- `pnpm lint` - Run linting for both JS client and Rust programs +- `pnpm lint:fix` - Auto-fix linting issues and format code +- `cd clients/js && pnpm test` - Run specific JS client tests +- `cd clients/js && pnpm build` - Build JS client +- `cargo test-bpf` - Run Rust program tests (from program directory) +- `cargo build-bpf` - Build Rust program (from program directory) + +### Local Development +- `pnpm validator` - Start local validator with program deployed +- `pnpm validator:debug` - Start local validator with logs +- `pnpm validator:stop` - Stop local validator +- `pnpm validator:logs` - Show validator logs + +## Architecture Overview + +### Multi-Language Workspace Structure +This repository contains both Rust programs and multiple client libraries: +- **Rust Program**: `programs/mpl-core/` - The on-chain Solana program +- **JavaScript Client**: `clients/js/` - Umi-compatible JS library +- **Rust Client**: `clients/rust/` - Rust client library +- **Python Client**: `clients/python/` - Python client (minimal) + +### Program Architecture (Rust) +The core program follows a modular plugin-based architecture: +- **State Management**: `state/` - Asset, Collection, and other core data structures +- **Plugin System**: `plugins/` - Extensible plugin architecture with three categories: + - `internal/authority_managed/` - Collection-level plugins (royalties, attributes, etc.) + - `internal/owner_managed/` - Asset-level plugins (freeze, burn, transfer delegates) + - `internal/permanent/` - Immutable plugins (edition, permanent delegates) + - `external/` - External plugin adapters for third-party extensions +- **Processors**: `processor/` - Instruction handlers for all program operations +- **Instructions**: Core operations like create, transfer, burn, plugin management + +### Client Generation Workflow +1. Rust program code defines the on-chain interface using Shank annotations +2. `pnpm generate:idls` extracts IDL (Interface Definition Language) files +3. `pnpm generate:clients` uses Kinobi to generate client code from IDLs +4. Generated client code appears in `clients/js/src/generated/` +5. Hand-written client code in `clients/js/src/` provides higher-level APIs + +### Key Plugin Types +- **FreezeDelegate**: Allows freezing/unfreezing assets +- **BurnDelegate**: Permits burning assets +- **TransferDelegate**: Enables transfers on behalf of owner +- **Royalties**: Collection-level royalty enforcement +- **Attributes**: On-chain metadata storage +- **MasterEdition**: Print/edition functionality +- **External Adapters**: Third-party plugin integration (Oracle, AppData, etc.) + +## Development Patterns + +### Code Generation +- Never edit files in `clients/js/src/generated/` - they are auto-generated +- Run `pnpm generate` after making changes to Rust program interfaces +- Use Kinobi visitors in `configs/kinobi.cjs` for client customization + +### Testing +- Program tests are written in Rust using the standard test framework +- Client tests use AVA framework and require a running validator +- Tests often use generated keypairs and work with both individual assets and collections + +### Plugin Development +- New internal plugins go in appropriate `plugins/internal/` subdirectory +- External plugin adapters use the external plugin system +- Plugins have distinct authority models (owner-managed vs authority-managed) + +### Asset Hierarchy +- **Collections**: Optional grouping mechanism with shared plugins +- **Assets**: Core NFT-like digital assets that can belong to collections +- **Plugin Inheritance**: Assets inherit authority-managed plugins from their collection \ No newline at end of file diff --git a/Cargo.lock b/Cargo.lock index 259f1af9..4994d51b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,58 +1,39 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] -name = "Inflector" -version = "0.11.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe438c63458706e03479442743baae6c88256498e6431708f6dfc520a26515d3" -dependencies = [ - "lazy_static", - "regex", -] - -[[package]] -name = "addr2line" -version = "0.21.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a30b2e23b9e17a9f90641c7ab1549cd9b44f296d3ccbf309d2863cfe398a0cb" -dependencies = [ - "gimli", -] - -[[package]] -name = "adler" -version = "1.0.2" +name = "adler2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" [[package]] name = "aead" -version = "0.4.3" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b613b8e1e3cf911a086f53f03bf286f52fd7a7258e4fa606f0ef220d39d8877" +checksum = "d122413f284cf2d62fb1b7db97e02edb8cda96d769b16e443a4f6195e35662b0" dependencies = [ + "crypto-common 0.1.7", "generic-array", ] [[package]] name = "aes" -version = "0.7.5" +version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e8b47f52ea9bae42228d07ec09eb676433d7c4ed1ebdf0f1d1c29ed446f1ab8" +checksum = "b169f7a6d4742236a0a00c541b845991d0ac43e546831af1249753ab4c3aa3a0" dependencies = [ "cfg-if", "cipher", - "cpufeatures", - "opaque-debug", + "cpufeatures 0.2.17", ] [[package]] name = "aes-gcm-siv" -version = "0.10.3" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589c637f0e68c877bbd59a4599bbe849cac8e5f3e4b5a3ebae8f528cd218dcdc" +checksum = "ae0784134ba9375416d469ec31e7c5f9fa94405049cf08c5ce5b4698be673e0d" dependencies = [ "aead", "aes", @@ -63,25 +44,180 @@ dependencies = [ "zeroize", ] +[[package]] +name = "agave-feature-set" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a2c365c0245cbb8959de725fc2b44c754b673fdf34c9a7f9d4a25c35a7bf1" +dependencies = [ + "ahash 0.8.12", + "solana-epoch-schedule 2.2.1", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", + "solana-sha256-hasher 2.3.0", + "solana-svm-feature-set 2.3.13", +] + +[[package]] +name = "agave-feature-set" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85c1a889e5b7a9ceecc95a39bb617af24d3195e3e7af116e2843976fb4fd1fec" +dependencies = [ + "ahash 0.8.12", + "solana-epoch-schedule 3.1.0", + "solana-hash 3.1.0", + "solana-pubkey 3.0.0", + "solana-sha256-hasher 3.1.0", + "solana-svm-feature-set 3.0.0", +] + +[[package]] +name = "agave-io-uring" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17a7d154d80d58b3fd910b15801d9e3344fa2bbb67c45b101b274f8fe91b678c" +dependencies = [ + "io-uring", + "libc", + "log", + "slab", + "smallvec", +] + +[[package]] +name = "agave-precompiles" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d60d73657792af7f2464e9181d13c3979e94bb09841d9ffa014eef4ef0492b77" +dependencies = [ + "agave-feature-set 2.3.13", + "bincode", + "digest 0.10.7", + "ed25519-dalek 1.0.1", + "libsecp256k1", + "openssl", + "sha3", + "solana-ed25519-program 2.2.3", + "solana-message 2.4.0", + "solana-precompile-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-secp256k1-program 2.2.3", + "solana-secp256r1-program 2.2.4", +] + +[[package]] +name = "agave-precompiles" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "786ca0e8053b48d99829b6f6b7313d3f086fe0a4e22ef3c9992faceed76b72cf" +dependencies = [ + "agave-feature-set 3.0.0", + "bincode", + "digest 0.10.7", + "ed25519-dalek 1.0.1", + "libsecp256k1", + "openssl", + "sha3", + "solana-ed25519-program 3.0.0", + "solana-message 3.1.0", + "solana-precompile-error 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-secp256k1-program 3.0.1", + "solana-secp256r1-program 3.0.0", +] + +[[package]] +name = "agave-reserved-account-keys" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d815041e37f0eaa520c8d336c45dc12f9310b2f10065c2d3e9ea5eecc8a28ade" +dependencies = [ + "agave-feature-set 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "agave-syscalls" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d5c09b9517973a1486b3e1b232d95db032c3ed8d208b1169c18e533f05dccfe5" +dependencies = [ + "bincode", + "libsecp256k1", + "num-traits", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-big-mod-exp 3.0.0", + "solana-blake3-hasher 3.1.0", + "solana-bn254 3.2.1", + "solana-clock 3.0.1", + "solana-cpi 3.1.0", + "solana-curve25519 3.0.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-keccak-hasher 3.1.0", + "solana-loader-v3-interface 6.1.1", + "solana-poseidon 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-sbpf 0.12.2", + "solana-sdk-ids 3.1.0", + "solana-secp256k1-recover 3.1.1", + "solana-sha256-hasher 3.1.0", + "solana-stable-layout 3.0.1", + "solana-stake-interface 2.0.2", + "solana-svm-callback 3.0.0", + "solana-svm-feature-set 3.0.0", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-type-overrides", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", + "solana-transaction-context 3.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "agave-transaction-view" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a29f64028bf2b9ffa9a5b33ea092799bf2a2669d627ee267db4e96f65478f071" +dependencies = [ + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-packet 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", + "solana-signature 3.4.0", + "solana-svm-transaction", +] + [[package]] name = "ahash" -version = "0.7.7" +version = "0.7.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a824f2aa7e75a0c98c5a504fceb80649e9c35265d44525b5f94de4771a395cd" +checksum = "891477e0c6a8957309ee5c45a6368af3ae14bb510732d2684ffa19af310920f9" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.17", "once_cell", "version_check", ] [[package]] name = "ahash" -version = "0.8.6" +version = "0.8.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91429305e9f0a25f6205c5b8e0d2db09e0708a7a6df0f42212bb56c32c8ac97a" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" dependencies = [ "cfg-if", - "getrandom 0.2.12", + "getrandom 0.3.4", "once_cell", "version_check", "zerocopy", @@ -89,19 +225,13 @@ dependencies = [ [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] -[[package]] -name = "aliasable" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "250f629c0161ad8107cf89319e990051fae62832fd343083bea452d93e2205fd" - [[package]] name = "alloc-no-stdlib" version = "2.0.4" @@ -117,13 +247,44 @@ dependencies = [ "alloc-no-stdlib", ] +[[package]] +name = "allocator-api2" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923" + +[[package]] +name = "anchor-attribute-access-control" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f70fd141a4d18adf11253026b32504f885447048c7494faf5fa83b01af9c0cf" +dependencies = [ + "anchor-syn 0.31.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + [[package]] name = "anchor-attribute-access-control" -version = "0.30.0" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a883ca44ef14b2113615fc6d3a85fefc68b5002034e88db37f7f1f802f88aa9" +dependencies = [ + "anchor-syn 0.32.1", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-account" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dd7368e171b3a317885dc08ec0f74eed9d0ad6c726cc819593aed81440dca926" +checksum = "715a261c57c7679581e06f07a74fa2af874ac30f86bd8ea07cca4a7e5388a064" dependencies = [ - "anchor-syn", + "anchor-syn 0.31.1", + "bs58", "proc-macro2", "quote", "syn 1.0.109", @@ -131,12 +292,12 @@ dependencies = [ [[package]] name = "anchor-attribute-account" -version = "0.30.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f527df85a8cba3f2bea04e46ed71b66e525ea378c7fec538aa205f4520b73e31" +checksum = "61c4d97763b29030412b4b80715076377edc9cc63bc3c9e667297778384b9fd2" dependencies = [ - "anchor-syn", - "bs58 0.5.1", + "anchor-syn 0.32.1", + "bs58", "proc-macro2", "quote", "syn 1.0.109", @@ -144,33 +305,67 @@ dependencies = [ [[package]] name = "anchor-attribute-constant" -version = "0.30.0" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "730d6df8ae120321c5c25e0779e61789e4b70dc8297102248902022f286102e4" +dependencies = [ + "anchor-syn 0.31.1", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-constant" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae3328bbf9bbd517a51621b1ba6cbec06cbbc25e8cfc7403bddf69bcf088206" +dependencies = [ + "anchor-syn 0.32.1", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-error" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3eb1dc1845cf8636c2e046a274ca074dabd3884ac8ed11cc4ed64b7e8ef5a318" +checksum = "27e6e449cc3a37b2880b74dcafb8e5a17b954c0e58e376432d7adc646fb333ef" dependencies = [ - "anchor-syn", + "anchor-syn 0.31.1", "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-error" -version = "0.30.0" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf2398a6d9e16df1ee9d7d37d970a8246756de898c8dd16ef6bdbe4da20cf39a" +dependencies = [ + "anchor-syn 0.32.1", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-attribute-event" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f382e41514c59a77ffa7bb1a47df9a0359564a749b6934485c742c11962e540" +checksum = "d7710e4c54adf485affcd9be9adec5ef8846d9c71d7f31e16ba86ff9fc1dd49f" dependencies = [ - "anchor-syn", + "anchor-syn 0.31.1", + "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "anchor-attribute-event" -version = "0.30.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "473a122aeed3f6b666438236338d2ef7833ee5fdc5688e1baa80185d61088a53" +checksum = "f12758f4ec2f0e98d4d56916c6fe95cb23d74b8723dd902c762c5ef46ebe7b65" dependencies = [ - "anchor-syn", + "anchor-syn 0.32.1", "proc-macro2", "quote", "syn 1.0.109", @@ -178,14 +373,14 @@ dependencies = [ [[package]] name = "anchor-attribute-program" -version = "0.30.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f88c7ffe2eb40aeac43ffd0d74a6671581158aedfaa0552330a2ef92fa5c889" +checksum = "05ecfd49b2aeadeb32f35262230db402abed76ce87e27562b34f61318b2ec83c" dependencies = [ "anchor-lang-idl", - "anchor-syn", + "anchor-syn 0.31.1", "anyhow", - "bs58 0.5.1", + "bs58", "heck 0.3.3", "proc-macro2", "quote", @@ -193,25 +388,77 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "anchor-attribute-program" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c7193b5af2649813584aae6e3569c46fd59616a96af2083c556b13136c3830f" +dependencies = [ + "anchor-lang-idl", + "anchor-syn 0.32.1", + "anyhow", + "bs58", + "heck 0.3.3", + "proc-macro2", + "quote", + "serde_json", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-accounts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be89d160793a88495af462a7010b3978e48e30a630c91de47ce2c1d3cb7a6149" +dependencies = [ + "anchor-syn 0.31.1", + "quote", + "syn 1.0.109", +] + [[package]] name = "anchor-derive-accounts" -version = "0.30.0" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d332d1a13c0fca1a446de140b656e66110a5e8406977dcb6a41e5d6f323760b0" +dependencies = [ + "anchor-syn 0.32.1", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-serde" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed9b97c99dcec135aae0ff908c14bcfcd3e78cfc16a0c6f245135038f0e6d390" +checksum = "abc6ee78acb7bfe0c2dd2abc677aaa4789c0281a0c0ef01dbf6fe85e0fd9e6e4" dependencies = [ - "anchor-syn", + "anchor-syn 0.31.1", + "borsh-derive-internal", + "proc-macro2", "quote", "syn 1.0.109", ] [[package]] name = "anchor-derive-serde" -version = "0.30.0" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8656e4af182edaeae665fa2d2d7ee81148518b5bd0be9a67f2a381bb17da7d46" +dependencies = [ + "anchor-syn 0.32.1", + "borsh-derive-internal", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "anchor-derive-space" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbece98f6ad9c37070edc0841326c9623a249346cd74f433e7cef69b14f7f31d" +checksum = "134a01c0703f6fd355a0e472c033f6f3e41fac1ef6e370b20c50f4c8d022cea7" dependencies = [ - "anchor-syn", - "borsh-derive-internal 0.10.3", "proc-macro2", "quote", "syn 1.0.109", @@ -219,9 +466,9 @@ dependencies = [ [[package]] name = "anchor-derive-space" -version = "0.30.0" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8badbe2648bc99a85ee05a7a5f9512e5e2af8ffac71476a69350cb278057ac53" +checksum = "dcff2a083560cd79817db07d89a4de39a2c4b2eaa00c1742cf0df49b25ff2bed" dependencies = [ "proc-macro2", "quote", @@ -230,63 +477,128 @@ dependencies = [ [[package]] name = "anchor-lang" -version = "0.30.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e41feb9c1cd9f4b0fad1c004fc8f289183f3ce27e9db38fa6e434470c716fb1e" -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", - "arrayref", +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6bab117055905e930f762c196e08f861f8dfe7241b92cee46677a3b15561a0a" +dependencies = [ + "anchor-attribute-access-control 0.31.1", + "anchor-attribute-account 0.31.1", + "anchor-attribute-constant 0.31.1", + "anchor-attribute-error 0.31.1", + "anchor-attribute-event 0.31.1", + "anchor-attribute-program 0.31.1", + "anchor-derive-accounts 0.31.1", + "anchor-derive-serde 0.31.1", + "anchor-derive-space 0.31.1", "base64 0.21.7", "bincode", - "borsh 0.10.3", + "borsh 0.10.4", "bytemuck", - "getrandom 0.2.12", - "solana-program", - "thiserror", + "solana-program 2.3.0", + "thiserror 1.0.69", +] + +[[package]] +name = "anchor-lang" +version = "0.32.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e67d85d5376578f12d840c29ff323190f6eecd65b00a0b5f2b2f232751d049cc" +dependencies = [ + "anchor-attribute-access-control 0.32.1", + "anchor-attribute-account 0.32.1", + "anchor-attribute-constant 0.32.1", + "anchor-attribute-error 0.32.1", + "anchor-attribute-event 0.32.1", + "anchor-attribute-program 0.32.1", + "anchor-derive-accounts 0.32.1", + "anchor-derive-serde 0.32.1", + "anchor-derive-space 0.32.1", + "base64 0.21.7", + "bincode", + "borsh 0.10.4", + "bytemuck", + "solana-account-info 2.3.0", + "solana-clock 2.2.3", + "solana-cpi 2.2.1", + "solana-define-syscall 2.3.0", + "solana-feature-gate-interface 2.2.2", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-invoke", + "solana-loader-v3-interface 3.0.0", + "solana-msg 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-program-option 2.2.1", + "solana-program-pack 2.2.1", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", + "solana-sysvar 2.3.0", + "solana-sysvar-id 2.2.1", + "thiserror 1.0.69", ] [[package]] name = "anchor-lang-idl" -version = "0.1.0" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b29da81eae478b1bb846749b06b8a2cb9c6f9ed26ca793b0c916793fdf36adab" +checksum = "32e8599d21995f68e296265aa5ab0c3cef582fd58afec014d01bd0bce18a4418" dependencies = [ + "anchor-lang-idl-spec", "anyhow", + "heck 0.3.3", "serde", "serde_json", + "sha2 0.10.9", +] + +[[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.30.0" +version = "0.31.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac53f2378bc08e89e20c2b893c01986ffd34cfbc69a17e35bd6f754753e9fdad" +checksum = "5dc7a6d90cc643df0ed2744862cdf180587d1e5d28936538c18fc8908489ed67" dependencies = [ "anyhow", - "bs58 0.5.1", + "bs58", "heck 0.3.3", "proc-macro2", "quote", "serde", "serde_json", - "sha2 0.10.8", + "sha2 0.10.9", "syn 1.0.109", - "thiserror", + "thiserror 1.0.69", ] [[package]] -name = "android-tzdata" -version = "0.1.1" +name = "anchor-syn" +version = "0.32.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e999941b234f3131b00bc13c22d06e8c5ff726d1b6318ac7eb276997bbb4fef0" +checksum = "b93b69aa7d099b59378433f6d7e20e1008fc10c69e48b220270e5b3f2ec4c8be" +dependencies = [ + "anyhow", + "bs58", + "heck 0.3.3", + "proc-macro2", + "quote", + "serde", + "serde_json", + "sha2 0.10.9", + "syn 1.0.109", + "thiserror 1.0.69", +] [[package]] name = "android_system_properties" @@ -298,118 +610,285 @@ dependencies = [ ] [[package]] -name = "ansi_term" -version = "0.12.1" +name = "anstream" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" dependencies = [ - "winapi", + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", ] [[package]] -name = "anyhow" -version = "1.0.79" +name = "anstyle" +version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "080e9890a082662b09c1ad45f567faeeb47f22b5fb23895fbe1e651e718e25ca" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" [[package]] -name = "ark-bn254" -version = "0.4.0" +name = "anstyle-parse" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" dependencies = [ - "ark-ec", - "ark-ff", - "ark-std", + "utf8parse", ] [[package]] -name = "ark-ec" -version = "0.4.2" +name = "anstyle-query" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "ark-ff", - "ark-poly", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", - "itertools", - "num-traits", - "zeroize", + "windows-sys 0.61.2", ] [[package]] -name = "ark-ff" -version = "0.4.2" +name = "anstyle-wincon" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ - "ark-ff-asm", - "ark-ff-macros", - "ark-serialize", - "ark-std", - "derivative", - "digest 0.10.7", - "itertools", - "num-bigint 0.4.4", - "num-traits", - "paste", - "rustc_version", - "zeroize", + "anstyle", + "once_cell_polyfill", + "windows-sys 0.61.2", ] [[package]] -name = "ark-ff-asm" -version = "0.4.2" +name = "anyhow" +version = "1.0.102" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "aquamarine" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f50776554130342de4836ba542aa85a4ddb361690d7e8df13774d7284c3d5c2" dependencies = [ + "include_dir", + "itertools 0.10.5", + "proc-macro-error2", + "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.117", ] [[package]] -name = "ark-ff-macros" -version = "0.4.2" +name = "arc-swap" +version = "1.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +checksum = "6a3a1fd6f75306b68087b831f025c712524bcb19aad54e557b1129cfa0a2b207" dependencies = [ - "num-bigint 0.4.4", - "num-traits", - "proc-macro2", - "quote", - "syn 1.0.109", + "rustversion", ] [[package]] -name = "ark-poly" -version = "0.4.2" +name = "ark-bn254" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +checksum = "a22f4561524cd949590d78d7d4c5df8f592430d221f7f3c9497bbafd8972120f" dependencies = [ - "ark-ff", - "ark-serialize", - "ark-std", - "derivative", - "hashbrown 0.13.2", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-std 0.4.0", ] [[package]] -name = "ark-serialize" -version = "0.4.2" +name = "ark-bn254" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb7b85a02b83d2f22f89bd5cac66c9c89474240cb6207cb1efc16d098e822a5" +checksum = "d69eab57e8d2663efa5c63135b2af4f396d66424f88954c21104125ab6b3e6bc" dependencies = [ - "ark-serialize-derive", - "ark-std", - "digest 0.10.7", - "num-bigint 0.4.4", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-std 0.5.0", ] [[package]] -name = "ark-serialize-derive" +name = "ark-ec" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "defd9a439d56ac24968cca0571f598a61bc8c55f71d50a89cda591cb750670ba" +dependencies = [ + "ark-ff 0.4.2", + "ark-poly 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", + "itertools 0.10.5", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ec" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43d68f2d516162846c1238e755a7c4d131b892b70cc70c471a8e3ca3ed818fce" +dependencies = [ + "ahash 0.8.12", + "ark-ff 0.5.0", + "ark-poly 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe 0.6.0", + "fnv", + "hashbrown 0.15.2", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-integer", + "num-traits", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec847af850f44ad29048935519032c33da8aa03340876d351dfab5660d2966ba" +dependencies = [ + "ark-ff-asm 0.4.2", + "ark-ff-macros 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "digest 0.10.7", + "itertools 0.10.5", + "num-bigint 0.4.6", + "num-traits", + "paste", + "rustc_version", + "zeroize", +] + +[[package]] +name = "ark-ff" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a177aba0ed1e0fbb62aa9f6d0502e9b46dad8c2eab04c14258a1212d2557ea70" +dependencies = [ + "ark-ff-asm 0.5.0", + "ark-ff-macros 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "educe 0.6.0", + "itertools 0.13.0", + "num-bigint 0.4.6", + "num-traits", + "paste", + "zeroize", +] + +[[package]] +name = "ark-ff-asm" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ed4aa4fe255d0bc6d79373f7e31d2ea147bcf486cba1be5ba7ea85abdb92348" +dependencies = [ + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-asm" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62945a2f7e6de02a31fe400aa489f0e0f5b2502e69f95f853adb82a96c7a6b60" +dependencies = [ + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ark-ff-macros" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abe79b0e4288889c4574159ab790824d0033b9fdcb2a112a3182fac2e514565" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 1.0.109", +] + +[[package]] +name = "ark-ff-macros" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09be120733ee33f7693ceaa202ca41accd5653b779563608f1234f78ae07c4b3" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "ark-poly" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d320bfc44ee185d899ccbadfa8bc31aab923ce1558716e1997a1e74057fe86bf" +dependencies = [ + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "ark-std 0.4.0", + "derivative", + "hashbrown 0.13.2", +] + +[[package]] +name = "ark-poly" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "579305839da207f02b89cd1679e50e67b4331e2f9294a57693e5051b7703fe27" +dependencies = [ + "ahash 0.8.12", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "ark-std 0.5.0", + "educe 0.6.0", + "fnv", + "hashbrown 0.15.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 0.4.2", + "ark-std 0.4.0", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f4d068aaf107ebcd7dfb52bc748f8030e0fc930ac8e360146ca54c1203088f7" +dependencies = [ + "ark-serialize-derive 0.5.0", + "ark-std 0.5.0", + "arrayvec", + "digest 0.10.7", + "num-bigint 0.4.6", +] + +[[package]] +name = "ark-serialize-derive" version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ae3281bc6d0fd7e549af32b52511e1302185bd688fd3359fa36423346ff682ea" @@ -419,6 +898,17 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "ark-serialize-derive" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "213888f660fddcca0d257e88e54ac05bca01885f258ccdf695bafd77031bb69d" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "ark-std" version = "0.4.0" @@ -429,17 +919,27 @@ dependencies = [ "rand 0.8.5", ] +[[package]] +name = "ark-std" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "246a225cc6131e9ee4f24619af0f19d67761fff15d7ccc22e42b80846e69449a" +dependencies = [ + "num-traits", + "rand 0.8.5", +] + [[package]] name = "arrayref" -version = "0.3.7" +version = "0.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" [[package]] name = "arrayvec" -version = "0.7.4" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96d30a06541fbafbc7f82ed10c06164cfbd2c401138f6addd8404629c4b16711" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" [[package]] name = "ascii" @@ -459,7 +959,7 @@ dependencies = [ "nom", "num-traits", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] @@ -472,7 +972,7 @@ dependencies = [ "proc-macro2", "quote", "syn 1.0.109", - "synstructure", + "synstructure 0.12.6", ] [[package]] @@ -499,44 +999,50 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "81953c529336010edd6d8e358f886d9581267795c61b19475b71314bffa46d35" dependencies = [ "concurrent-queue", - "event-listener", + "event-listener 2.5.3", "futures-core", ] [[package]] name = "async-compression" -version = "0.4.6" +version = "0.4.41" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a116f46a969224200a0a97f29cfd4c50e7534e4b4826bd23ea2c3c533039c82c" +checksum = "d0f9ee0f6e02ffd7ad5816e9464499fba7b3effd01123b515c41d1697c43dad1" dependencies = [ - "brotli", - "flate2", - "futures-core", - "memchr", + "compression-codecs", + "compression-core", "pin-project-lite", "tokio", ] [[package]] -name = "async-mutex" -version = "1.4.0" +name = "async-lock" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "479db852db25d9dbf6204e6cb6253698f175c15726470f78af0d918e99d6156e" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" dependencies = [ - "event-listener", + "event-listener 5.4.1", + "event-listener-strategy", + "pin-project-lite", ] [[package]] name = "async-trait" -version = "0.1.77" +version = "0.1.89" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c980ee35e870bd1a4d2c8294d4c04d0499e67bca1e4b5cefcc693c2fa00caea9" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "atty" version = "0.2.14" @@ -550,24 +1056,15 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] -name = "backtrace" -version = "0.3.69" +name = "base16ct" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2089b7e3f35b9dd2d0ed921ead4f6d318c27680d4a5bd167b3ee120edb105837" -dependencies = [ - "addr2line", - "cc", - "cfg-if", - "libc", - "miniz_oxide", - "object", - "rustc-demangle", -] +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" [[package]] name = "base64" @@ -589,15 +1086,15 @@ checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567" [[package]] name = "base64" -version = "0.22.0" +version = "0.22.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9475866fec1451be56a3c2400fd081ff546538961565ccb5b7142cbd22bc7a51" +checksum = "72b3254f16251a8381aa12e40e3c4d2f0199f8c6508fbecb9d91f575e0fbb8c6" [[package]] name = "base64ct" -version = "1.6.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bincode" @@ -610,17 +1107,11 @@ dependencies = [ [[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" +version = "2.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1" +checksum = "c4512299f36f043ab09a583e57bceb5a5aab7a73db1805848e8fef3c9e8c78b3" dependencies = [ - "serde", + "serde_core", ] [[package]] @@ -634,16 +1125,17 @@ dependencies = [ [[package]] name = "blake3" -version = "1.5.0" +version = "1.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +checksum = "4d2d5991425dfd0785aed03aedcf0b321d61975c9b5b3689c774a2610ae0b51e" dependencies = [ "arrayref", "arrayvec", "cc", "cfg-if", "constant_time_eq", - "digest 0.10.7", + "cpufeatures 0.3.0", + "digest 0.11.2", ] [[package]] @@ -652,7 +1144,6 @@ version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" dependencies = [ - "block-padding", "generic-array", ] @@ -666,84 +1157,66 @@ dependencies = [ ] [[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" +name = "block-buffer" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15bf3650200d8bffa99015595e10f1fbd17de07abbc25bb067da79e769939bfa" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ - "borsh-derive 0.9.3", - "hashbrown 0.11.2", + "hybrid-array", ] [[package]] name = "borsh" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4114279215a005bc675e386011e594e1d9b800918cea18fcadadcce864a2046b" +checksum = "115e54d64eb62cdebad391c19efc9dce4981c690c85a33a12199d99bb9546fee" dependencies = [ - "borsh-derive 0.10.3", + "borsh-derive 0.10.4", "hashbrown 0.13.2", ] [[package]] -name = "borsh-derive" -version = "0.9.3" +name = "borsh" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6441c552f230375d18e3cc377677914d2ca2b0d36e52129fe15450a2dce46775" +checksum = "cfd1e3f8955a5d7de9fab72fc8373fade9fb8a703968cb200ae3dc6cf08e185a" 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", + "borsh-derive 1.6.1", + "bytes", + "cfg_aliases", ] [[package]] name = "borsh-derive" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0754613691538d51f329cce9af41d7b7ca150bc973056f1156611489475f54f7" +checksum = "831213f80d9423998dd696e2c5345aba6be7a0bd8cd19e31c5243e13df1cef89" dependencies = [ - "borsh-derive-internal 0.10.3", - "borsh-schema-derive-internal 0.10.3", + "borsh-derive-internal", + "borsh-schema-derive-internal", "proc-macro-crate 0.1.5", "proc-macro2", "syn 1.0.109", ] [[package]] -name = "borsh-derive-internal" -version = "0.9.3" +name = "borsh-derive" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5449c28a7b352f2d1e592a8a28bf139bc71afb0764a14f3c02500935d8c44065" +checksum = "bfcfdc083699101d5a7965e49925975f2f55060f94f9a05e7187be95d530ca59" dependencies = [ + "once_cell", + "proc-macro-crate 3.5.0", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.117", ] [[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" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cdbd5696d8bfa21d53d9fe39a714a18538bad11492a42d066dbbc395fb1951c0" +checksum = "65d6ba50644c98714aa2a70d13d7df3cd75cd2b523a2b452bf010443800976b3" dependencies = [ "proc-macro2", "quote", @@ -752,9 +1225,9 @@ dependencies = [ [[package]] name = "borsh-schema-derive-internal" -version = "0.10.3" +version = "0.10.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634205cc43f74a1b9046ef87c4540ebda95696ec0f315024860cad7c5b0f5ccd" +checksum = "276691d96f063427be83e6692b86148e488ebba9f48f77788724ca027ba3b6d4" dependencies = [ "proc-macro2", "quote", @@ -763,9 +1236,9 @@ dependencies = [ [[package]] name = "brotli" -version = "3.4.0" +version = "8.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "516074a47ef4bce09577a3b379392300159ce5b1ba2e501ff1c819950066100f" +checksum = "4bd8b9603c7aa97359dbd97ecf258968c95f3adddd6db2f7e7a5bef101c84560" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -774,20 +1247,14 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "2.5.1" +version = "5.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4e2e4afe60d7dd600fdd3de8d0f08c2b7ec039712e3b6137ff98b7004e82de4f" +checksum = "874bb8112abecc98cbd6d81ea4fa7e94fb9449648c93cc89aa40c81c24d7de03" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", ] -[[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" @@ -799,9 +1266,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.14.0" +version = "3.20.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f30e7476521f6f8af1a1c4c0b8cc94f0bee37d91763d0ca2665f299b6cd8aec" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" [[package]] name = "bv" @@ -815,22 +1282,22 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.14.1" +version = "1.25.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" dependencies = [ "bytemuck_derive", ] [[package]] name = "bytemuck_derive" -version = "1.5.0" +version = "1.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "965ab7eb5f8f97d2a083c799f3a1b994fc397b2fe2da5d1da1626ce15a39f2b1" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] @@ -841,9 +1308,12 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "bytes" -version = "1.5.0" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2bd12c1caf447e69cd4528f47f94d203fd2582878ecb9e9465484c4148a8223" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" +dependencies = [ + "serde", +] [[package]] name = "bzip2" @@ -857,54 +1327,74 @@ dependencies = [ [[package]] name = "bzip2-sys" -version = "0.1.11+1.0.8" +version = "0.1.13+1.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "736a955f3fa7875102d57c82b8cac37ec45224a07fd32d58f9f7a186b6cd4cdc" +checksum = "225bff33b2141874fe80d71e07d6eec4f85c5c216453dd96388240f96e1acc14" dependencies = [ "cc", - "libc", "pkg-config", ] [[package]] name = "caps" -version = "0.5.5" +version = "0.5.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190baaad529bcfbde9e1a19022c42781bdb6ff9de25721abdb8fd98c0807730b" +checksum = "fd1ddba47aba30b6a889298ad0109c3b8dcb0e8fc993b459daa7067d46f865e0" dependencies = [ "libc", - "thiserror", ] [[package]] name = "cc" -version = "1.0.83" +version = "1.2.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +checksum = "43c5703da9466b66a946814e1adf53ea2c90f10063b86290cc9eb67ce3478a20" dependencies = [ + "find-msvc-tools", "jobserver", "libc", + "shlex", ] +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfg-if" -version = "1.0.0" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cfg_eval" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +checksum = "45565fc9416b9896014f5732ac776f810ee53a66730c17e4020c3ec064a8f88f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] name = "chrono" -version = "0.4.31" +version = "0.4.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f2c685bad3eb3d45a01354cedb7d5faa66194d1d58ba6e267a8de788f79db38" +checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" dependencies = [ - "android-tzdata", "iana-time-zone", - "js-sys", "num-traits", "serde", - "wasm-bindgen", - "windows-targets 0.48.5", + "windows-link", ] [[package]] @@ -918,52 +1408,25 @@ dependencies = [ [[package]] name = "cipher" -version = "0.3.0" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ee52072ec15386f770805afd189a01c8841be8696bed250fa2f13c4c0d6dfb7" +checksum = "773f3b9af64447d2ce9850330c473515014aa235e6a783b02db81ff39e4a3dad" dependencies = [ - "generic-array", + "crypto-common 0.1.7", + "inout", ] [[package]] -name = "clap" -version = "2.34.0" +name = "cmov" +version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" -dependencies = [ - "ansi_term", - "atty", - "bitflags 1.3.2", - "strsim 0.8.0", - "textwrap 0.11.0", - "unicode-width", - "vec_map", -] +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" [[package]] -name = "clap" -version = "3.2.25" +name = "colorchoice" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4ea181bf566f71cb9a5d17a59e1871af638180a18fb0035c92ae62b705207123" -dependencies = [ - "atty", - "bitflags 1.3.2", - "clap_lex", - "indexmap 1.9.3", - "once_cell", - "strsim 0.10.0", - "termcolor", - "textwrap 0.16.0", -] - -[[package]] -name = "clap_lex" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2850f2f5a82cbf437dd5af4d49848fbdfc27c157c3d010345776f952765261c5" -dependencies = [ - "os_str_bytes", -] +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" [[package]] name = "combine" @@ -978,26 +1441,53 @@ dependencies = [ "unreachable", ] +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "compression-codecs" +version = "0.4.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb7b51a7d9c967fc26773061ba86150f19c50c0d65c887cb1fbe295fd16619b7" +dependencies = [ + "brotli", + "compression-core", + "flate2", + "memchr", +] + +[[package]] +name = "compression-core" +version = "0.4.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75984efb6ed102a0d42db99afb6c1948f0380d1d91808d5529916e6c08b49d8d" + [[package]] name = "concurrent-queue" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d16048cd947b08fa32c24458a22f5dc5e835264f689f4f5653210c69fd107363" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" dependencies = [ "crossbeam-utils", ] [[package]] name = "console" -version = "0.15.8" +version = "0.16.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e1f83fc076bd6dd27517eacdf25fef6c4dfe5f1d7448bafaaf3a26f13b5e4eb" +checksum = "d64e8af5551369d19cf50138de61f1c42074ab970f74e99be916646777f8fc87" dependencies = [ "encode_unicode", - "lazy_static", "libc", "unicode-width", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1022,21 +1512,21 @@ dependencies = [ [[package]] name = "const-oid" -version = "0.7.1" +version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e4c78c047431fee22c1a7bb92e00ad095a02a983affe4d8a72e2a2c62c1b94f3" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" [[package]] name = "constant_time_eq" -version = "0.3.0" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" [[package]] name = "core-foundation" -version = "0.9.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" dependencies = [ "core-foundation-sys", "libc", @@ -1044,42 +1534,51 @@ dependencies = [ [[package]] name = "core-foundation-sys" -version = "0.8.6" +version = "0.8.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06ea2b9bc92be3c2baa9334a323ebca2d6f074ff852cd1d7b11064035cd3868f" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" dependencies = [ "libc", ] [[package]] name = "crc32fast" -version = "1.3.2" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" dependencies = [ "cfg-if", ] [[package]] name = "crossbeam-channel" -version = "0.5.11" +version = "0.5.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" dependencies = [ "crossbeam-utils", ] [[package]] name = "crossbeam-deque" -version = "0.8.5" +version = "0.8.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" dependencies = [ "crossbeam-epoch", "crossbeam-utils", @@ -1096,26 +1595,48 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.19" +version = "0.8.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-bigint" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core 0.6.4", + "subtle", + "zeroize", +] [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" dependencies = [ "generic-array", + "rand_core 0.6.4", "typenum", ] +[[package]] +name = "crypto-common" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77727bb15fa921304124b128af125e7e3b968275d1b108b379190264f4423710" +dependencies = [ + "hybrid-array", +] + [[package]] name = "crypto-mac" version = "0.8.0" @@ -1128,86 +1649,161 @@ dependencies = [ [[package]] name = "ctr" -version = "0.8.0" +version = "0.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "049bb91fb4aaf0e3c7efa6cd5ef877dbbbd15b39dad06d9948de4ec8a75761ea" +checksum = "0369ee1ad671834580515889b80f2ea915f23b8be8d0daa4bbaf2ac5c7590835" dependencies = [ "cipher", ] +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", +] + [[package]] name = "curve25519-dalek" -version = "3.2.1" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" dependencies = [ "byteorder", "digest 0.9.0", "rand_core 0.5.1", + "subtle", + "zeroize", +] + +[[package]] +name = "curve25519-dalek" +version = "4.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97fb8b7c4503de7d6ae7b42ab72a5a59857b4c937ec27a3d4539dba95b5ab2be" +dependencies = [ + "cfg-if", + "cpufeatures 0.2.17", + "curve25519-dalek-derive", + "digest 0.10.7", + "fiat-crypto", + "rand_core 0.6.4", + "rustc_version", "serde", "subtle", "zeroize", ] +[[package]] +name = "curve25519-dalek-derive" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f46882e17999c6cc590af592290432be3bce0428cb0d5f8b6715e4dc7b383eb3" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "darling" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdf337090841a411e2a7f3deb9187445851f91b309c0c0a29e05f74a00a48c0" +dependencies = [ + "darling_core 0.21.3", + "darling_macro 0.21.3", +] + [[package]] name = "darling" -version = "0.20.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0209d94da627ab5605dcccf08bb18afa5009cfbef48d8a8b7d7bdbc79be25c5e" +checksum = "25ae13da2f202d56bd7f91c25fba009e7717a1e4a1cc98a76d844b65ae912e9d" dependencies = [ - "darling_core", - "darling_macro", + "darling_core 0.23.0", + "darling_macro 0.23.0", ] [[package]] name = "darling_core" -version = "0.20.3" +version = "0.21.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "177e3443818124b357d8e76f53be906d60937f0d3a90773a664fa63fa253e621" +checksum = "1247195ecd7e3c85f83c8d2a366e4210d588e802133e1e355180a9870b517ea4" dependencies = [ "fnv", "ident_case", "proc-macro2", "quote", - "strsim 0.10.0", - "syn 2.0.48", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_core" +version = "0.23.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9865a50f7c335f53564bb694ef660825eb8610e0a53d3e11bf1b0d3df31e03b0" +dependencies = [ + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.117", +] + +[[package]] +name = "darling_macro" +version = "0.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d38308df82d1080de0afee5d069fa14b0326a88c14f15c5ccda35b4a6c414c81" +dependencies = [ + "darling_core 0.21.3", + "quote", + "syn 2.0.117", ] [[package]] name = "darling_macro" -version = "0.20.3" +version = "0.23.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "836a9bbc7ad63342d6d6e7b815ccab164bc77a2d95d84bc3117a8c0d5c98e2d5" +checksum = "ac3984ec7bd6cfa798e62b4a642426a5be0e68f9401cfc2a01e3fa9ea2fcdb8d" dependencies = [ - "darling_core", + "darling_core 0.23.0", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[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.5", + "lock_api", + "once_cell", + "parking_lot_core", "rayon", ] [[package]] name = "data-encoding" -version = "2.5.0" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e962a19be5cfc3f3bf6dd8f61eb50107f356ad6270fbb3ed41476571db78be5" +checksum = "d7a1e2f27636f116493b8b860f5546edb47c8d8f8ea73e1d2a20be88e28d1fea" [[package]] name = "der" -version = "0.5.1" +version = "0.7.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6919815d73839e7ad218de758883aae3a257ba6759ce7a9992501efbb53d705c" +checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" dependencies = [ "const-oid", + "zeroize", ] [[package]] @@ -1219,19 +1815,19 @@ dependencies = [ "asn1-rs", "displaydoc", "nom", - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "rusticata-macros", ] [[package]] name = "deranged" -version = "0.3.11" +version = "0.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b42b6fa04a440b495c8b04d0e71b707c585f83cb9cb28cf8cd0d976c315e31b4" +checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" dependencies = [ "powerfmt", - "serde", + "serde_core", ] [[package]] @@ -1252,16 +1848,10 @@ dependencies = [ ] [[package]] -name = "dialoguer" -version = "0.10.4" +name = "difflib" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59c6f2989294b9a498d3ad5491a79c6deb604617378e1cdc4bfc1c1361fe2f87" -dependencies = [ - "console", - "shell-words", - "tempfile", - "zeroize", -] +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" [[package]] name = "digest" @@ -1279,10 +1869,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer 0.10.4", - "crypto-common", + "const-oid", + "crypto-common 0.1.7", "subtle", ] +[[package]] +name = "digest" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4850db49bf08e663084f7fb5c87d202ef91a3907271aff24a94eb97ff039153c" +dependencies = [ + "block-buffer 0.12.0", + "crypto-common 0.2.1", + "ctutils", +] + [[package]] name = "dir-diff" version = "0.3.3" @@ -1294,13 +1896,13 @@ dependencies = [ [[package]] name = "displaydoc" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] @@ -1323,22 +1925,58 @@ checksum = "a6cbae11b3de8fce2a456e8ea3dada226b35fe791f0dc1d360c0941f0bb681f3" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] +[[package]] +name = "downcast" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1435fa1053d8b2fbbe9be7e97eca7f33d37b28409959813daefc1446a14247f1" + +[[package]] +name = "dyn-clone" +version = "1.0.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555" + [[package]] name = "eager" version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abe71d579d1812060163dff96056261deb5bf6729b100fa2e36a68b9649ba3d3" +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest 0.10.7", + "elliptic-curve", + "rfc6979", + "signature 2.2.0", + "spki", +] + [[package]] name = "ed25519" version = "1.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "91cff35c70bba8a626e3185d8cd48cc11b5437e1a5bcd15b9b5fa3c64b6dfee7" dependencies = [ - "signature", + "signature 1.6.4", +] + +[[package]] +name = "ed25519" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115531babc129696a58c64a4fef0a8bf9e9698629fb97e9e40767d235cfbcd53" +dependencies = [ + "pkcs8", + "signature 2.2.0", ] [[package]] @@ -1347,14 +1985,29 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c762bae6dcaf24c4c84667b8579785430908723d5c889f469d76a41d59cc7a9d" dependencies = [ - "curve25519-dalek", - "ed25519", + "curve25519-dalek 3.2.0", + "ed25519 1.5.3", "rand 0.7.3", "serde", "sha2 0.9.9", "zeroize", ] +[[package]] +name = "ed25519-dalek" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e796c081cee67dc755e1a36a0a172b897fab85fc3f6bc48307991f64e4eca9" +dependencies = [ + "curve25519-dalek 4.1.3", + "ed25519 2.2.3", + "rand_core 0.6.4", + "serde", + "sha2 0.10.9", + "subtle", + "zeroize", +] + [[package]] name = "ed25519-dalek-bip32" version = "0.2.0" @@ -1362,9 +2015,21 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9d2be62a4061b872c8c0873ee4fc6f101ce7b889d039f019c5fa2af471a59908" dependencies = [ "derivation-path", - "ed25519-dalek", + "ed25519-dalek 1.0.1", + "hmac 0.12.1", + "sha2 0.10.9", +] + +[[package]] +name = "ed25519-dalek-bip32" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b49a684b133c4980d7ee783936af771516011c8cd15f429dbda77245e282f03" +dependencies = [ + "derivation-path", + "ed25519-dalek 2.2.0", "hmac 0.12.1", - "sha2 0.10.8", + "sha2 0.10.9", ] [[package]] @@ -1373,33 +2038,55 @@ version = "0.4.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0f0042ff8246a363dbe77d2ceedb073339e85a804b9a47636c6e016a9a32c05f" dependencies = [ - "enum-ordinalize", + "enum-ordinalize 3.1.15", "proc-macro2", "quote", "syn 1.0.109", ] [[package]] -name = "either" -version = "1.9.0" +name = "educe" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize 4.3.2", + "proc-macro2", + "quote", + "syn 2.0.117", +] [[package]] -name = "encode_unicode" -version = "0.3.6" +name = "either" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a357d28ed41a50f9c765dbfe56cbc04a64e53e5fc58ba79fbc34c10ef3df831f" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] -name = "encoding_rs" -version = "0.8.33" +name = "elliptic-curve" +version = "0.13.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7268b386296a025e474d5140678f75d6de9493ae55a5d709eeb9dd08149945e1" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" dependencies = [ - "cfg-if", + "base16ct", + "crypto-bigint", + "digest 0.10.7", + "ff", + "generic-array", + "group", + "pkcs8", + "rand_core 0.6.4", + "sec1", + "subtle", + "zeroize", ] +[[package]] +name = "encode_unicode" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34aa73646ffb006b8f5147f3dc182bd4bcb190227ce861fc4a4844bf8e3cb2c0" + [[package]] name = "enum-iterator" version = "1.5.0" @@ -1411,13 +2098,13 @@ dependencies = [ [[package]] name = "enum-iterator-derive" -version = "1.3.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03cdc46ec28bd728e67540c528013c6a10eb69a02eb31078a1bda695438cbfb8" +checksum = "685adfa4d6f3d765a26bc5dbc936577de9abf756c1feeb3089b01dd395034842" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] @@ -1426,11 +2113,41 @@ version = "3.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1bf1fa3f06bbff1ea5b1a9c7b14aa992a39657db60a2759457328d7e058f49ee" dependencies = [ - "num-bigint 0.4.4", + "num-bigint 0.4.6", "num-traits", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", +] + +[[package]] +name = "enum-ordinalize" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a1091a7bb1f8f2c4b28f1fe2cef4980ca2d410a3d727d67ecc3178c9b0800f0" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ca9601fb2d62598ee17836250842873a413586e5d7ed88b356e38ddbb0ec631" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "env_filter" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32e90c2accc4b07a8456ea0debdc2e7587bdd890680d71173a15d4ae604f6eef" +dependencies = [ + "log", + "regex", ] [[package]] @@ -1446,20 +2163,33 @@ dependencies = [ "termcolor", ] +[[package]] +name = "env_logger" +version = "0.11.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0621c04f2196ac3f488dd583365b9c09be011a4ab8b9f37248ffcc8f6198b56a" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + [[package]] name = "equivalent" -version = "1.0.1" +version = "1.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" [[package]] name = "errno" -version = "0.3.8" +version = "0.3.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" dependencies = [ "libc", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -1469,68 +2199,200 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0206175f82b8d6bf6652ff7d71a1e27fd2e4efde587fd368662814d6ec1d9ce0" [[package]] -name = "fastrand" -version = "2.0.1" +name = "event-listener" +version = "5.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25cbce373ec4653f1a01a31e8a5e5ec0c622dc27ff9c4e6606eefef5cbbed4a5" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] [[package]] -name = "feature-probe" -version = "0.1.1" +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener 5.4.1", + "pin-project-lite", +] + +[[package]] +name = "fastbloom" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e7f34442dbe69c60fe8eaf58a8cafff81a1f278816d8ab4db255b3bef4ac3c4" +dependencies = [ + "getrandom 0.3.4", + "libm", + "rand 0.9.4", + "siphasher 1.0.2", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + +[[package]] +name = "feature-probe" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "835a3dc7d1ec9e75e2b5fb4ba75396837112d2060b03f7d43bc1897c7f7211da" +[[package]] +name = "ff" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +dependencies = [ + "rand_core 0.6.4", + "subtle", +] + +[[package]] +name = "fiat-crypto" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28dea519a9695b9977216879a3ebfddf92f1c08c05d984f8996aecd6ecdc811d" + [[package]] name = "filetime" -version = "0.2.23" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1ee447700ac8aa0b2f2bd7bc4462ad686ba06baa6727ac149a2d6277f0d240fd" +checksum = "f98844151eee8917efc50bd9e8318cb963ae8b297431495d3f758616ea5c57db" dependencies = [ "cfg-if", "libc", - "redox_syscall", - "windows-sys 0.52.0", + "libredox", ] +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "five8" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75b8549488b4715defcb0d8a8a1c1c76a80661b5fa106b4ca0e7fce59d7d875" +dependencies = [ + "five8_core 0.1.2", +] + +[[package]] +name = "five8" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23f76610e969fa1784327ded240f1e28a3fd9520c9cec93b636fcf62dd37f772" +dependencies = [ + "five8_core 1.0.0", +] + +[[package]] +name = "five8_const" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26dec3da8bc3ef08f2c04f61eab298c3ab334523e55f076354d6d6f613799a7b" +dependencies = [ + "five8_core 0.1.2", +] + +[[package]] +name = "five8_const" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a0f1728185f277989ca573a402716ae0beaaea3f76a8ff87ef9dd8fb19436c5" +dependencies = [ + "five8_core 1.0.0", +] + +[[package]] +name = "five8_core" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2551bf44bc5f776c15044b9b94153a00198be06743e262afaaa61f11ac7523a5" + +[[package]] +name = "five8_core" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "059c31d7d36c43fe39d89e55711858b4da8be7eb6dabac23c7289b1a19489406" + [[package]] name = "flate2" -version = "1.0.28" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46303f565772937ffe1d394a4fac6f411c6013172fadde9dcdb1e147a086940e" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" dependencies = [ "crc32fast", "miniz_oxide", ] +[[package]] +name = "float-cmp" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98de4bbd547a563b716d8dfa9aad1cb19bfab00f4fa09a6a4ed21dbcf44ce9c4" +dependencies = [ + "num-traits", +] + [[package]] name = "fnv" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + [[package]] name = "form_urlencoded" -version = "1.2.1" +version = "1.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e13624c2627564efccf4934284bdd98cbaa14e79b0b5a141218e507b3a823456" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" dependencies = [ "percent-encoding", ] [[package]] -name = "fs-err" -version = "2.11.0" +name = "fragile" +version = "2.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88a41f105fe1d5b6b34b2055e3dc59bb79b46b48b2040b9e6c7b4b5de097aa41" +checksum = "8878864ba14bb86e818a412bfd6f18f9eabd4ec0f008a28e8f7eb61db532fcf9" dependencies = [ - "autocfg", + "futures-core", ] [[package]] name = "futures" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "645c6916888f6cb6350d2550b80fb63e734897a8498abe35cfb732b6487804b0" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" dependencies = [ "futures-channel", "futures-core", @@ -1543,9 +2405,9 @@ dependencies = [ [[package]] name = "futures-channel" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eac8f7d7865dcb88bd4373ab671c8cf4508703796caa2b1985a9ca867b3fcb78" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" dependencies = [ "futures-core", "futures-sink", @@ -1553,15 +2415,15 @@ dependencies = [ [[package]] name = "futures-core" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" [[package]] name = "futures-executor" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a576fc72ae164fca6b9db127eaa9a9dda0d61316034f33a0a0d4eda41f02b01d" +checksum = "baf29c38818342a3b26b5b923639e7b1f4a61fc5e76102d4b1981c6dc7a7579d" dependencies = [ "futures-core", "futures-task", @@ -1570,38 +2432,44 @@ dependencies = [ [[package]] name = "futures-io" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" [[package]] name = "futures-macro" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87750cf4b7a4c0625b1529e4c543c2182106e4dedc60a2a6455e00d212c489ac" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "futures-sink" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9fb8e00e87438d937621c1c6269e53f536c14d3fbd6a042bb24879e57d474fb5" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" [[package]] name = "futures-task" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-timer" +version = "3.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" [[package]] name = "futures-util" -version = "0.3.30" +version = "0.3.32" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6401deb83407ab3da39eba7e33987a73c3df0c82b4bb5813ee871c19c41d48" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" dependencies = [ "futures-channel", "futures-core", @@ -1611,7 +2479,6 @@ dependencies = [ "futures-task", "memchr", "pin-project-lite", - "pin-utils", "slab", ] @@ -1621,9 +2488,9 @@ version = "0.14.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ - "serde", "typenum", "version_check", + "zeroize", ] [[package]] @@ -1651,94 +2518,111 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.12" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" dependencies = [ "cfg-if", "js-sys", "libc", - "wasi 0.11.0+wasi-snapshot-preview1", + "wasi 0.11.1+wasi-snapshot-preview1", "wasm-bindgen", ] [[package]] -name = "gimli" -version = "0.28.1" +name = "getrandom" +version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4271d37baee1b8c7e4b708028c57d816cf9d2434acb33a549475f78c181f6253" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "js-sys", + "libc", + "r-efi", + "wasip2", + "wasm-bindgen", +] [[package]] -name = "goblin" -version = "0.5.4" +name = "governor" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a7666983ed0dd8d21a6f6576ee00053ca0926fb281a5522577a4dbd0f1b54143" +checksum = "68a7f542ee6b35af73b06abc0dad1c1bae89964e4e253bc4b587b91c9637867b" dependencies = [ - "log", - "plain", - "scroll", + "cfg-if", + "dashmap", + "futures", + "futures-timer", + "no-std-compat", + "nonzero_ext", + "parking_lot", + "portable-atomic", + "quanta", + "rand 0.8.5", + "smallvec", + "spinning_top", ] [[package]] -name = "h2" -version = "0.3.24" +name = "group" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bb2c4422095b67ee78da96fbb51a4cc413b3b25883c7717ff7ca1ab31022c9c9" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" dependencies = [ - "bytes", - "fnv", - "futures-core", - "futures-sink", - "futures-util", - "http", - "indexmap 2.1.0", - "slab", - "tokio", - "tokio-util 0.7.10", - "tracing", + "ff", + "rand_core 0.6.4", + "subtle", ] [[package]] name = "hash32" -version = "0.2.1" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" dependencies = [ "byteorder", ] [[package]] name = "hashbrown" -version = "0.11.2" +version = "0.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5ef0d4909ef3724cc8cce6ccc8572c5c817592e9285f5464f8e86f8bd3726e" +checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" dependencies = [ - "ahash 0.7.7", + "ahash 0.7.8", ] [[package]] name = "hashbrown" -version = "0.12.3" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888" +checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" dependencies = [ - "ahash 0.7.7", + "ahash 0.8.12", ] [[package]] name = "hashbrown" -version = "0.13.2" +version = "0.14.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e" +checksum = "e5274423e17b7c9fc20b6e7e208532f9b19825d82dfd615708b70edd83df41f1" + +[[package]] +name = "hashbrown" +version = "0.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf151400ff0baff5465007dd2f3e717f3fe502074ca563069ce3a6629d07b289" dependencies = [ - "ahash 0.8.6", + "allocator-api2", + "equivalent", + "foldhash", ] [[package]] name = "hashbrown" -version = "0.14.3" +version = "0.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" [[package]] name = "heck" @@ -1755,6 +2639,12 @@ version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8" +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + [[package]] name = "hermit-abi" version = "0.1.19" @@ -1766,9 +2656,9 @@ dependencies = [ [[package]] name = "hermit-abi" -version = "0.3.4" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" [[package]] name = "hex" @@ -1814,92 +2704,139 @@ dependencies = [ [[package]] name = "http" -version = "0.2.11" +version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8947b1a6fad4393052c7ba1f4cd97bed3e953a95c79c92ad9b051a04611d9fbb" +checksum = "601cbb57e577e2f5ef5be8e7b83f0f63994f25aa94d673e54a92d5c516d101f1" dependencies = [ "bytes", "fnv", "itoa", ] +[[package]] +name = "http" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3ba2a386d7f85a81f119ad7498ebe444d2e22c2af0b86b069416ace48b3311a" +dependencies = [ + "bytes", + "itoa", +] + [[package]] name = "http-body" -version = "0.4.6" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1efedce1fb8e6913f23e0c92de8e62cd5b772a67e7b3946df930a62566c93184" +dependencies = [ + "bytes", + "http 1.4.0", +] + +[[package]] +name = "http-body-util" +version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ceab25649e9960c0311ea418d17bee82c0dcec1bd053b5f9a66e265a693bed2" +checksum = "b021d93e26becf5dc7e1b75b1bed1fd93124b374ceb73f43d4d4eafec896a64a" dependencies = [ "bytes", - "http", + "futures-core", + "http 1.4.0", + "http-body", "pin-project-lite", ] [[package]] name = "httparse" -version = "1.8.0" +version = "1.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d897f394bad6a705d5f4104762e116a75639e470d80901eed05a860a95cb1904" +checksum = "6dbf3de79e51f3d586ab4cb9d5c3e2c14aa28ed23d180cf89b4df0454a69cc87" [[package]] -name = "httpdate" -version = "1.0.3" +name = "humantime" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "df3b46402a9d5adb4c86a0cf463f42e19994e3ee891101b1841f30a545cb49a9" +checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424" [[package]] -name = "humantime" -version = "2.1.0" +name = "hybrid-array" +version = "0.4.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" +checksum = "3944cf8cf766b40e2a1a333ee5e9b563f854d5fa49d6a8ca2764e97c6eddb214" +dependencies = [ + "typenum", +] [[package]] name = "hyper" -version = "0.14.28" +version = "1.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bf96e135eb83a2a8ddf766e426a841d8ddd7449d5f00d34ea02b41d2f19eef80" +checksum = "6299f016b246a94207e63da54dbe807655bf9e00044f73ded42c3ac5305fbcca" dependencies = [ + "atomic-waker", "bytes", "futures-channel", "futures-core", - "futures-util", - "h2", - "http", + "http 1.4.0", "http-body", "httparse", - "httpdate", "itoa", "pin-project-lite", - "socket2", + "smallvec", "tokio", - "tower-service", - "tracing", "want", ] [[package]] name = "hyper-rustls" -version = "0.24.2" +version = "0.27.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33ca68d021ef39cf6463ab54c1d0f5daf03377b70561305bb89a8f83aab66e0f" +dependencies = [ + "http 1.4.0", + "hyper", + "hyper-util", + "rustls 0.23.38", + "tokio", + "tokio-rustls 0.26.4", + "tower-service", + "webpki-roots 1.0.7", +] + +[[package]] +name = "hyper-util" +version = "0.1.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec3efd23720e2049821a693cbc7e65ea87c72f1c58ff2f9522ff332b1491e590" +checksum = "96547c2556ec9d12fb1578c4eaf448b04993e7fb79cbaad930a656880a6bdfa0" dependencies = [ + "base64 0.22.1", + "bytes", + "futures-channel", "futures-util", - "http", + "http 1.4.0", + "http-body", "hyper", - "rustls", + "ipnet", + "libc", + "percent-encoding", + "pin-project-lite", + "socket2", "tokio", - "tokio-rustls", + "tower-service", + "tracing", ] [[package]] name = "iana-time-zone" -version = "0.1.59" +version = "0.1.65" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6a67363e2aa4443928ce15e57ebae94fd8949958fd1223c4cfc0cd473ad7539" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" dependencies = [ "android_system_properties", "core-foundation-sys", "iana-time-zone-haiku", "js-sys", + "log", "wasm-bindgen", "windows-core", ] @@ -1914,92 +2851,226 @@ dependencies = [ ] [[package]] -name = "ident_case" -version = "1.0.1" +name = "icu_collections" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] [[package]] -name = "idna" -version = "0.5.0" +name = "icu_locale_core" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "634d9b1461af396cad843f47fdba5597a4f9e6ddd4bfb6ff5d85028c25cb12f6" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" dependencies = [ - "unicode-bidi", - "unicode-normalization", + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", ] [[package]] -name = "im" -version = "15.1.0" +name = "icu_normalizer" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d0acd33ff0285af998aaf9b57342af478078f53492322fafc47450e09397e0e9" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" dependencies = [ - "bitmaps", - "rand_core 0.6.4", - "rand_xoshiro", - "rayon", - "serde", - "sized-chunks", - "typenum", - "version_check", + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", ] [[package]] -name = "index_list" -version = "0.2.11" +name = "icu_normalizer_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70891286cb8e844fdfcf1178b47569699f9e20b5ecc4b45a6240a64771444638" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" [[package]] -name = "indexmap" -version = "1.9.3" +name = "icu_properties" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" dependencies = [ - "autocfg", - "hashbrown 0.12.3", - "serde", + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", ] [[package]] -name = "indexmap" -version = "2.1.0" +name = "icu_properties_data" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d530e1a18b1cb4c484e6e34556a0d948706958449fca0cab753d649f2bce3d1f" -dependencies = [ - "equivalent", - "hashbrown 0.14.3", - "serde", -] +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" [[package]] -name = "indicatif" -version = "0.17.7" +name = "icu_provider" +version = "2.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb28741c9db9a713d93deb3bb9515c20788cef5815265bee4980e87bde7e0f25" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" dependencies = [ - "console", - "instant", - "number_prefix", - "portable-atomic", - "unicode-width", + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", ] [[package]] -name = "instant" -version = "0.1.12" +name = "ident_case" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a5bbe824c507c5da5956355e86a746d82e0e1464f65d862cc5e71da70e94b2c" -dependencies = [ - "cfg-if", -] +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[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 = "include_dir" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd" +dependencies = [ + "include_dir_macros", +] + +[[package]] +name = "include_dir_macros" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "indexmap" +version = "1.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99" +dependencies = [ + "autocfg", + "hashbrown 0.12.3", + "serde", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + +[[package]] +name = "indicatif" +version = "0.18.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25470f23803092da7d239834776d653104d551bc4d7eacaf31e6837854b8e9eb" +dependencies = [ + "console", + "portable-atomic", + "unicode-width", + "unit-prefix", + "web-time", +] + +[[package]] +name = "inout" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "879f10e63c20629ecabbb64a8010319738c66a5cd0c29b02d63d272b03751d01" +dependencies = [ + "generic-array", +] + +[[package]] +name = "io-uring" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdd7bddefd0a8833b88a4b68f90dae22c7450d11b354198baee3874fd811b344" +dependencies = [ + "bitflags", + "cfg-if", + "libc", +] [[package]] name = "ipnet" -version = "2.9.0" +version = "2.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d98f6fed1fde3f8c21bc40a1abb88dd75e67924f9cffc3ef95607bad8017f8e2" + +[[package]] +name = "iri-string" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f518f335dce6725a761382244631d86cf0ccb2863413590b31338feb467f9c3" +checksum = "25e659a4bb38e810ebc252e53b5814ff908a8c58c2a9ce2fae1bbec24cbf4e20" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" @@ -2010,27 +3081,117 @@ dependencies = [ "either", ] +[[package]] +name = "itertools" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +dependencies = [ + "either", +] + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + [[package]] name = "itoa" -version = "1.0.10" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" +dependencies = [ + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine 4.6.7", + "jni-sys 0.3.1", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41a652e1f9b6e0275df1f15b32661cf0d4b78d4d87ddec5e0c3c20f097433258" +dependencies = [ + "jni-sys 0.4.1", +] + +[[package]] +name = "jni-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6377a88cb3910bee9b0fa88d4f42e1d2da8e79915598f65fb0c7ee14c878af2" +dependencies = [ + "jni-sys-macros", +] + +[[package]] +name = "jni-sys-macros" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c" +checksum = "38c0b942f458fe50cdac086d2f946512305e5631e720728f2a61aabcd47a6264" +dependencies = [ + "quote", + "syn 2.0.117", +] [[package]] name = "jobserver" -version = "0.1.27" +version = "0.1.34" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8c37f63953c4c63420ed5fd3d6d398c719489b9f872b9fa683262f8edd363c7d" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" dependencies = [ + "getrandom 0.3.4", "libc", ] [[package]] name = "js-sys" -version = "0.3.67" +version = "0.3.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a1d36f1235bc969acba30b7f5990b864423a6068a10f7c90ae8f0112e3a59d1" +checksum = "2964e92d1d9dc3364cae4d718d93f227e3abb088e747d92e0395bfdedf1c12ca" dependencies = [ + "cfg-if", + "futures-util", + "once_cell", "wasm-bindgen", ] @@ -2049,37 +3210,70 @@ dependencies = [ "serde_json", ] +[[package]] +name = "k256" +version = "0.13.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e3919bbaa2945715f0bb6d3934a173d1e9a59ac23767fbaaef277265a7411b" +dependencies = [ + "cfg-if", + "ecdsa", + "elliptic-curve", + "once_cell", + "sha2 0.10.9", + "signature 2.2.0", +] + [[package]] name = "kaigan" -version = "0.2.6" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2ba15de5aeb137f0f65aa3bf82187647f1285abfe5b20c80c2c37f7007ad519a" +checksum = "358444e00cb7d2efdbe986f90c05466f222e0554c38834d03d994b0705621ab0" dependencies = [ - "anchor-lang", - "borsh 0.10.3", + "anchor-lang 0.32.1", + "borsh 0.10.4", + "borsh 1.6.1", "serde", ] [[package]] name = "keccak" -version = "0.1.5" +version = "0.1.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "cb26cec98cce3a3d96cbb7bced3c4b16e3d13f27ec56dbd62cbc8f39cfb9d653" dependencies = [ - "cpufeatures", + "cpufeatures 0.2.17", ] [[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.152" +version = "0.2.185" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ff2c0fe9bc6cb6b14a0592c2ff4fa9ceb83eea9db979b0487cd054946a2b8f" + +[[package]] +name = "libm" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981" + +[[package]] +name = "libredox" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "13e3bf6590cbc649f4d1a3eefc9d5d6eb746f5200ffb04e5e142700b8faa56e7" +checksum = "e02f3bb43d335493c96bf3fd3a321600bf6bd07ed34bc64118e9293bdffea46c" +dependencies = [ + "bitflags", + "libc", + "plain", + "redox_syscall 0.7.4", +] [[package]] name = "libsecp256k1" @@ -2135,33 +3329,38 @@ version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3c9a85a9752c549ceb7578064b4ed891179d20acd85f27318573b64d2d7ee7ee" dependencies = [ - "ark-bn254", - "ark-ff", - "num-bigint 0.4.4", - "thiserror", + "ark-bn254 0.4.0", + "ark-ff 0.4.2", + "num-bigint 0.4.6", + "thiserror 1.0.69", ] [[package]] name = "linux-raw-sys" -version = "0.4.13" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" [[package]] name = "lock_api" -version = "0.4.11" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3c168f8615b12bc01f9c17e2eb0cc07dcae1940121185446edc3744920e8ef45" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" dependencies = [ - "autocfg", "scopeguard", ] [[package]] name = "log" -version = "0.4.20" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "lru" @@ -2172,21 +3371,26 @@ dependencies = [ "hashbrown 0.12.3", ] +[[package]] +name = "lru-slab" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "112b39cec0b298b6c1999fee3e31427f74f676e4cb9879ed1a121b43661a4154" + [[package]] name = "lz4" -version = "1.24.0" +version = "1.28.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e9e2dd86df36ce760a60f6ff6ad526f7ba1f14ba0356f8254fb6905e6494df1" +checksum = "a20b523e860d03443e98350ceaac5e71c6ba89aea7d960769ec3ce37f4de5af4" dependencies = [ - "libc", "lz4-sys", ] [[package]] name = "lz4-sys" -version = "1.9.4" +version = "1.11.1+lz4-1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57d27b317e207b10f69f5e75494119e391a96f48861ae870d1da6edac98ca900" +checksum = "6bd8c0d6c6ed0cd30b3652886bb8711dc4bb01d637a68105a3d5158039b418e6" dependencies = [ "cc", "libc", @@ -2194,9 +3398,9 @@ dependencies = [ [[package]] name = "memchr" -version = "2.7.1" +version = "2.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" [[package]] name = "memmap2" @@ -2208,19 +3412,19 @@ dependencies = [ ] [[package]] -name = "memoffset" -version = "0.7.1" +name = "memmap2" +version = "0.9.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5de893c32cde5f383baa4c04c5d6dbdd735cfd4a794b0debdb2bb1b421da5ff4" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" dependencies = [ - "autocfg", + "libc", ] [[package]] name = "memoffset" -version = "0.9.0" +version = "0.9.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a634b1c61a95585bd15607c6ab0c4e5b226e695ff2800ba0cdccddf208c406c" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" dependencies = [ "autocfg", ] @@ -2237,12 +3441,6 @@ dependencies = [ "zeroize", ] -[[package]] -name = "mime" -version = "0.3.17" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a" - [[package]] name = "minimal-lexical" version = "0.2.1" @@ -2251,22 +3449,50 @@ checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "miniz_oxide" -version = "0.7.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7810e0be55b428ada41041c41f32c9f1a42817901b4ccf45fa3d4b6561e74c7" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" dependencies = [ - "adler", + "adler2", + "simd-adler32", ] [[package]] name = "mio" -version = "0.8.10" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f3d0b296e374a4e6f3c7b0a1f5a51d748a0d34c85e7dc48fc3fa9a87657fe09" +checksum = "50b7e5b27aa02a74bac8c3f23f448f8d87ff11f92d3aac1a6ed369ee08cc56c1" dependencies = [ "libc", - "wasi 0.11.0+wasi-snapshot-preview1", - "windows-sys 0.48.0", + "wasi 0.11.1+wasi-snapshot-preview1", + "windows-sys 0.61.2", +] + +[[package]] +name = "mockall" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c84490118f2ee2d74570d114f3d0493cbf02790df303d2707606c3e14e07c96" +dependencies = [ + "cfg-if", + "downcast", + "fragile", + "lazy_static", + "mockall_derive", + "predicates", + "predicates-tree", +] + +[[package]] +name = "mockall_derive" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22ce75669015c4f47b289fd4d4f56e894e4c96003ffdf3ac51313126f94c6cbb" +dependencies = [ + "cfg-if", + "proc-macro2", + "quote", + "syn 1.0.109", ] [[package]] @@ -2291,69 +3517,201 @@ dependencies = [ ] [[package]] -name = "mpl-core" -version = "0.8.1-beta.1" +name = "mollusk-svm" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c01cfd03829e0c7c5a0decb92cdc2963501268fb48851eea03f9017bd0eae83" dependencies = [ - "anchor-lang", - "assert_matches", - "base64 0.22.0", - "borsh 0.10.3", - "kaigan", - "modular-bitfield", - "num-derive 0.3.3", - "num-traits", - "rmp-serde", - "serde", - "serde_json", - "serde_with 3.4.0", - "solana-program", - "solana-program-test", - "solana-sdk", - "thiserror", + "agave-feature-set 2.3.13", + "agave-precompiles 2.3.13", + "bincode", + "mollusk-svm-error", + "mollusk-svm-keys", + "mollusk-svm-result", + "solana-account 2.2.1", + "solana-bpf-loader-program 2.3.13", + "solana-clock 2.2.3", + "solana-compute-budget 2.3.13", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-loader-v3-interface 3.0.0", + "solana-loader-v4-interface 2.2.1", + "solana-log-collector", + "solana-logger 2.3.1", + "solana-precompile-error 2.2.2", + "solana-program-error 2.2.2", + "solana-program-runtime 2.3.13", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-stake-interface 1.2.1", + "solana-svm-callback 2.3.13", + "solana-system-program 2.3.13", + "solana-sysvar 2.3.0", + "solana-sysvar-id 2.2.1", + "solana-timings", + "solana-transaction-context 2.3.13", +] + +[[package]] +name = "mollusk-svm-error" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a9aeed06a7181fa7b5dc4437ccf39cba9cf2062938aa44bc5373bffebacd1" +dependencies = [ + "solana-pubkey 2.4.0", + "thiserror 1.0.69", ] [[package]] -name = "mpl-core-program" -version = "0.1.0" +name = "mollusk-svm-keys" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf086261ca149a8b03c75ef17b3ac83ca985ff46598c3a298f6e85bdc69d7420" dependencies = [ - "borsh 0.10.3", - "bytemuck", - "modular-bitfield", - "mpl-utils", - "num-derive 0.3.3", - "num-traits", - "podded", - "shank", - "solana-program", - "spl-noop", - "strum 0.26.1", - "thiserror", + "mollusk-svm-error", + "solana-account 2.2.1", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-transaction-context 2.3.13", ] [[package]] -name = "mpl-utils" -version = "0.3.5" +name = "mollusk-svm-result" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ee1b830bfd014504a11b2234e2e7d6af535adda601f224cd519b923f593c91b" +checksum = "46d33c72e491320ce1a884c60e0e23768c44c0990accb0ecbd20e698b21a2c25" dependencies = [ - "arrayref", - "solana-program", - "spl-token-2022 0.8.0", + "solana-account 2.2.1", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", +] + +[[package]] +name = "mpl-agent-identity" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b64cc13e4bc690ee535b5c10cb2c759d5e997e33044f8a2c7b70557bfc0dd23" +dependencies = [ + "borsh 0.10.4", + "num-derive 0.4.2", + "num-traits", + "solana-program 2.3.0", + "solana-program-error 3.0.0", + "thiserror 1.0.69", +] + +[[package]] +name = "mpl-agent-tools" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda6369852c60946a33454b9e114af52f19c70bcbb77af08f8120e60fffcfebd" +dependencies = [ + "borsh 0.10.4", + "num-derive 0.4.2", + "num-traits", + "solana-program 2.3.0", + "solana-program-error 3.0.0", + "thiserror 1.0.69", +] + +[[package]] +name = "mpl-bubblegum" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9160048f67dd7541bc5d04cfcf62a8431e882f13e6df90ac42185b53a250f52d" +dependencies = [ + "borsh 0.10.4", + "kaigan", + "modular-bitfield", + "num-derive 0.3.3", + "num-traits", + "solana-program 2.3.0", + "thiserror 1.0.69", +] + +[[package]] +name = "mpl-core" +version = "0.11.1" +dependencies = [ + "anchor-lang 0.31.1", + "assert_matches", + "base64 0.22.1", + "borsh 1.6.1", + "kaigan", + "modular-bitfield", + "num-derive 0.4.2", + "num-traits", + "rmp-serde", + "serde", + "serde_json", + "serde_with", + "solana-program 3.0.0", + "solana-program-error 3.0.0", + "solana-program-test", + "solana-sdk 3.0.0", + "solana-system-interface 2.0.0", + "thiserror 1.0.69", +] + +[[package]] +name = "mpl-core-program" +version = "0.2.0" +dependencies = [ + "borsh 0.10.4", + "bytemuck", + "modular-bitfield", + "mollusk-svm", + "mpl-agent-identity", + "mpl-agent-tools", + "mpl-bubblegum", + "mpl-utils", + "num-derive 0.3.3", + "num-traits", + "podded", + "shank", + "solana-program 2.3.0", + "solana-sdk 2.3.1", + "spl-noop", + "strum 0.26.3", + "thiserror 1.0.69", +] + +[[package]] +name = "mpl-utils" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d592e87845ee88bf1a6923426740686bb82c5a44c4432020582107220a566c3" +dependencies = [ + "arrayref", + "solana-program 2.3.0", + "spl-token-2022", ] [[package]] name = "nix" -version = "0.26.4" +version = "0.30.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "598beaf3cc6fdd9a5dfb1630c2800c7acd31df7aaf0f565796fba2b53ca1af1b" +checksum = "74523f3a35e05aba87a1d978330aef40f67b0304ac79c1c00b294c9830543db6" dependencies = [ - "bitflags 1.3.2", + "bitflags", "cfg-if", + "cfg_aliases", "libc", - "memoffset 0.7.1", - "pin-utils", + "memoffset", ] +[[package]] +name = "no-std-compat" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b93853da6d84c2e3c7d730d6473e8817692dd89be387eb01b94d7f108ecb5b8c" + [[package]] name = "nom" version = "7.1.3" @@ -2364,6 +3722,18 @@ dependencies = [ "minimal-lexical", ] +[[package]] +name = "nonzero_ext" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38bf9645c8b145698bb0b18a4637dcacbc421ea49bef2317e4fd8065a387cf21" + +[[package]] +name = "normalize-line-endings" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61807f77802ff30975e01f4f071c8ba10c022052f98b3294119f3e615d13e5be" + [[package]] name = "num" version = "0.2.1" @@ -2391,11 +3761,10 @@ dependencies = [ [[package]] name = "num-bigint" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "608e7659b5c3d7cba262d894801b9ec9d00de989e8a82bd4bef91d08da45cdc0" +checksum = "a5e44f723f1133c9deac646763579fdb3ac745e418f2a7af9cd0c431da1f20b9" dependencies = [ - "autocfg", "num-integer", "num-traits", ] @@ -2410,6 +3779,12 @@ dependencies = [ "num-traits", ] +[[package]] +name = "num-conv" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" + [[package]] name = "num-derive" version = "0.3.3" @@ -2423,30 +3798,29 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" dependencies = [ "autocfg", "num-integer", @@ -2467,106 +3841,125 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", ] [[package]] name = "num_cpus" -version = "1.16.0" +version = "1.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +checksum = "91df4bbde75afed763b708b7eee1e8e7651e02d97f6d5dd763e89367e957b23b" dependencies = [ - "hermit-abi 0.3.4", + "hermit-abi 0.5.2", "libc", ] [[package]] name = "num_enum" -version = "0.6.1" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a015b430d3c108a207fd776d2e2196aaf8b1cf8cf93253e3a097ff3085076a1" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" dependencies = [ - "num_enum_derive 0.6.1", + "num_enum_derive", + "rustversion", ] [[package]] -name = "num_enum" -version = "0.7.2" +name = "num_enum_derive" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02339744ee7253741199f897151b38e72257d13802d4ee837285cc2990a90845" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" dependencies = [ - "num_enum_derive 0.7.2", + "proc-macro-crate 3.5.0", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "num_enum_derive" +name = "oid-registry" version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96667db765a921f7b295ffee8b60472b686a51d4f21c2ee4ffdb94c7013b65a6" +checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" dependencies = [ - "proc-macro-crate 1.3.1", - "proc-macro2", - "quote", - "syn 2.0.48", + "asn1-rs", ] [[package]] -name = "num_enum_derive" -version = "0.7.2" +name = "once_cell" +version = "1.21.4" 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.48", -] +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] -name = "number_prefix" -version = "0.4.0" +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "opaque-debug" +version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b246a0e5f20af87141b25c173cd1b609bd7779a4617d6ec582abaf90870f3" +checksum = "c08d65885ee38876c4f86fa503fb49d7b507c2b62552df7c70b2fce627e06381" [[package]] -name = "object" -version = "0.32.2" +name = "openssl" +version = "0.10.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a6a622008b6e321afc04970976f62ee297fdbaa6f95318ca343e3eebb9648441" +checksum = "bfe4646e360ec77dff7dde40ed3d6c5fee52d156ef4a62f53973d38294dad87f" dependencies = [ - "memchr", + "bitflags", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", ] [[package]] -name = "oid-registry" -version = "0.6.1" +name = "openssl-macros" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9bedf36ffb6ba96c2eb7144ef6270557b52e54b20c0a8e1eb2ff99a6c6959bff" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" dependencies = [ - "asn1-rs", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] -name = "once_cell" -version = "1.19.0" +name = "openssl-probe" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92" +checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" [[package]] -name = "opaque-debug" -version = "0.3.0" +name = "openssl-src" +version = "300.6.0+3.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" +checksum = "a8e8cbfd3a4a8c8f089147fd7aaa33cf8c7450c4d09f8f80698a0cf093abeff4" +dependencies = [ + "cc", +] [[package]] -name = "openssl-probe" -version = "0.1.5" +name = "openssl-sys" +version = "0.9.113" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ff011a302c396a5197692431fc1948019154afc178baf7d8e37367442a4601cf" +checksum = "ad2f2c0eba47118757e4c6d2bff2838f3e0523380021356e7875e858372ce644" +dependencies = [ + "cc", + "libc", + "openssl-src", + "pkg-config", + "vcpkg", +] [[package]] name = "opentelemetry" @@ -2584,43 +3977,20 @@ dependencies = [ "percent-encoding", "pin-project", "rand 0.8.5", - "thiserror", -] - -[[package]] -name = "os_str_bytes" -version = "6.6.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2355d85b9a3786f481747ced0e0ff2ba35213a1f9bd406ed906554d7af805a1" - -[[package]] -name = "ouroboros" -version = "0.15.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e1358bd1558bd2a083fed428ffeda486fbfb323e698cdda7794259d592ca72db" -dependencies = [ - "aliasable", - "ouroboros_macro", + "thiserror 1.0.69", ] [[package]] -name = "ouroboros_macro" -version = "0.15.6" +name = "parking" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f7d21ccd03305a674437ee1248f3ab5d4b1db095cf1caf49f1713ddf61956b7" -dependencies = [ - "Inflector", - "proc-macro-error", - "proc-macro2", - "quote", - "syn 1.0.109", -] +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" [[package]] name = "parking_lot" -version = "0.12.1" +version = "0.12.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" dependencies = [ "lock_api", "parking_lot_core", @@ -2628,31 +3998,28 @@ dependencies = [ [[package]] name = "parking_lot_core" -version = "0.9.9" +version = "0.9.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c42a9226546d68acdd9c0a280d17ce19bfe27a46bf68784e4066115788d008e" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" dependencies = [ "cfg-if", "libc", - "redox_syscall", + "redox_syscall 0.5.18", "smallvec", - "windows-targets 0.48.5", + "windows-link", ] [[package]] name = "paste" -version = "1.0.14" +version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "de3145af08024dea9fa9914f381a17b8fc6034dfb00f3a84013f7ff43f29ed4c" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] -name = "pbkdf2" -version = "0.4.0" +name = "pastey" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "216eaa586a190f0a738f2f918511eecfa90f13295abec0e457cdebcceda80cbd" -dependencies = [ - "crypto-mac", -] +checksum = "b867cad97c0791bbd3aaa6472142568c6c9e8f71937e98379f584cfb0cf35bec" [[package]] name = "pbkdf2" @@ -2674,9 +4041,9 @@ dependencies = [ [[package]] name = "percent-encoding" -version = "2.3.1" +version = "2.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3148f5046208a5d56bcfc03053e3ca6334e51da8dfb19b6cdc8b306fae3283e" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" [[package]] name = "percentage" @@ -2689,52 +4056,45 @@ dependencies = [ [[package]] name = "pin-project" -version = "1.1.3" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fda4ed1c6c173e3fc7a83629421152e01d7b1f9b7f65fb301e490e8cfc656422" +checksum = "f1749c7ed4bcaf4c3d0a3efc28538844fb29bcdd7d2b67b2be7e20ba861ff517" dependencies = [ "pin-project-internal", ] [[package]] name = "pin-project-internal" -version = "1.1.3" +version = "1.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4359fd9c9171ec6e8c62926d6faaf553a8dc3f64e1507e76da7911b4f6a04405" +checksum = "d9b20ed30f105399776b9c883e68e536ef602a16ae6f596d2c473591d6ad64c6" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "pin-project-lite" -version = "0.2.13" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" - -[[package]] -name = "pin-utils" -version = "0.1.0" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" [[package]] name = "pkcs8" -version = "0.8.0" +version = "0.10.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7cabda3fb821068a9a4fab19a683eac3af12edf0f34b94a8be53c4972b8149d0" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" dependencies = [ "der", "spki", - "zeroize", ] [[package]] name = "pkg-config" -version = "0.3.29" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2900ede94e305130c13ddd391e0ab7cbaeb783945ae07a279c268cb05109c6cb" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "plain" @@ -2744,30 +4104,50 @@ checksum = "b4596b6d070b27117e987119b4dac604f3c58cfb0b191112e24771b2faeac1a6" [[package]] name = "podded" -version = "0.5.1" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ef03855395ea7838e038410cf2be5dd419fa65560c3c82dfcf1ee5b32cfb4e" +checksum = "48eebb4e1abcc028ffcec32bc52ea0166e0b0d424fedc30147f7e93bbaa8bee5" dependencies = [ "bytemuck", + "paste", + "solana-program 2.3.0", ] [[package]] name = "polyval" -version = "0.5.3" +version = "0.6.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8419d2b623c7c0896ff2d5d96e2cb4ede590fed28fcc34934f4c33c036e620a1" +checksum = "9d1fe60d06143b2430aa532c94cfe9e29783047f06c0d7fd359a9a51b729fa25" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "opaque-debug", "universal-hash", ] [[package]] name = "portable-atomic" -version = "1.6.0" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7170ef9988bc169ba16dd36a7fa041e5c4cbeb6a35b76d4c03daded371eae7c0" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] [[package]] name = "powerfmt" @@ -2777,67 +4157,87 @@ checksum = "439ee305def115ba05938db6eb1644ff94165c5ab5e9420d1c1bcedbba909391" [[package]] name = "ppv-lite86" -version = "0.2.17" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "predicates" +version = "2.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +checksum = "59230a63c37f3e18569bdb90e4a89cbf5bf8b06fea0b84e65ea10cc4df47addd" +dependencies = [ + "difflib", + "float-cmp", + "itertools 0.10.5", + "normalize-line-endings", + "predicates-core", + "regex", +] [[package]] -name = "proc-macro-crate" -version = "0.1.5" +name = "predicates-core" +version = "1.0.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" + +[[package]] +name = "predicates-tree" +version = "1.0.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" dependencies = [ - "toml", + "predicates-core", + "termtree", ] [[package]] name = "proc-macro-crate" -version = "1.3.1" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7f4c021e1093a56626774e81216a4ce732a735e5bad4868a03f3ed65ca0c3919" +checksum = "1d6ea3c4595b96363c13943497db34af4460fb474a95c43f4446ad341b8c9785" dependencies = [ - "once_cell", - "toml_edit 0.19.15", + "toml", ] [[package]] name = "proc-macro-crate" -version = "3.1.0" +version = "3.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6d37c51ca738a55da99dc0c4a34860fd675453b8b36209178c2249bb13651284" +checksum = "e67ba7e9b2b56446f1d419b1d807906278ffa1a658a8a5d8a39dcb1f5a78614f" dependencies = [ - "toml_edit 0.21.0", + "toml_edit", ] [[package]] -name = "proc-macro-error" -version = "1.0.4" +name = "proc-macro-error-attr2" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" dependencies = [ - "proc-macro-error-attr", "proc-macro2", "quote", - "syn 1.0.109", - "version_check", ] [[package]] -name = "proc-macro-error-attr" -version = "1.0.4" +name = "proc-macro-error2" +version = "2.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" dependencies = [ + "proc-macro-error-attr2", "proc-macro2", "quote", - "version_check", ] [[package]] name = "proc-macro2" -version = "1.0.76" +version = "1.0.106" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95fc56cda0b5c3325f5fbbd7ff9fda9e02bb00bb3dac51252d2f1bfa1cb8cc8c" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" dependencies = [ "unicode-ident", ] @@ -2859,66 +4259,96 @@ checksum = "9e2e25ee72f5b24d773cae88422baddefff7714f97aab68d96fe2b6fc4a28fb2" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", +] + +[[package]] +name = "quanta" +version = "0.12.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3ab5a9d756f0d97bdc89019bd2e4ea098cf9cde50ee7564dde6b81ccc8f06c7" +dependencies = [ + "crossbeam-utils", + "libc", + "once_cell", + "raw-cpuid", + "wasi 0.11.1+wasi-snapshot-preview1", + "web-sys", + "winapi", ] [[package]] name = "quinn" -version = "0.10.2" +version = "0.11.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8cc2c5017e4b43d5995dcea317bc46c1e09404c0a9664d2908f7f02dfe943d75" +checksum = "b9e20a958963c291dc322d98411f541009df2ced7b5a4f2bd52337638cfccf20" dependencies = [ "bytes", + "cfg_aliases", "pin-project-lite", "quinn-proto", "quinn-udp", "rustc-hash", - "rustls", - "thiserror", + "rustls 0.23.38", + "socket2", + "thiserror 2.0.18", "tokio", "tracing", + "web-time", ] [[package]] name = "quinn-proto" -version = "0.10.6" +version = "0.11.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "141bf7dfde2fbc246bfd3fe12f2455aa24b0fbd9af535d8c86c7bd1381ff2b1a" +checksum = "434b42fec591c96ef50e21e886936e66d3cc3f737104fdb9b737c40ffb94c098" dependencies = [ "bytes", - "rand 0.8.5", - "ring 0.16.20", + "fastbloom", + "getrandom 0.3.4", + "lru-slab", + "rand 0.9.4", + "ring", "rustc-hash", - "rustls", - "rustls-native-certs", + "rustls 0.23.38", + "rustls-pki-types", + "rustls-platform-verifier", "slab", - "thiserror", + "thiserror 2.0.18", "tinyvec", "tracing", + "web-time", ] [[package]] name = "quinn-udp" -version = "0.4.1" +version = "0.5.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "055b4e778e8feb9f93c4e439f71dc2156ef13360b432b799e179a8c4cdf0b1d7" +checksum = "addec6a0dcad8a8d96a771f815f0eaf55f9d1805756410b39f5fa81332574cbd" dependencies = [ - "bytes", + "cfg_aliases", "libc", + "once_cell", "socket2", "tracing", - "windows-sys 0.48.0", + "windows-sys 0.60.2", ] [[package]] name = "quote" -version = "1.0.35" +version = "1.0.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef" +checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924" dependencies = [ "proc-macro2", ] +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + [[package]] name = "rand" version = "0.7.3" @@ -2943,6 +4373,16 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "rand" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c5af06bb1b7d3216d91932aed5265164bf384dc89cd6ba05cf59a35f5f76ea" +dependencies = [ + "rand_chacha 0.9.0", + "rand_core 0.9.5", +] + [[package]] name = "rand_chacha" version = "0.2.2" @@ -2964,12 +4404,22 @@ dependencies = [ ] [[package]] -name = "rand_core" -version = "0.5.1" +name = "rand_chacha" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +checksum = "d3022b5f1df60f26e1ffddd6c66e8aa15de382ae63b3a0c1bfc0e4d3e3f325cb" dependencies = [ - "getrandom 0.1.16", + "ppv-lite86", + "rand_core 0.9.5", +] + +[[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]] @@ -2978,7 +4428,16 @@ version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ - "getrandom 0.2.12", + "getrandom 0.2.17", +] + +[[package]] +name = "rand_core" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76afc826de14238e6e8c374ddcc1fa19e374fd8dd986b0d2af0d02377261d83c" +dependencies = [ + "getrandom 0.3.4", ] [[package]] @@ -2999,11 +4458,20 @@ dependencies = [ "rand_core 0.6.4", ] +[[package]] +name = "raw-cpuid" +version = "11.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "498cd0dc59d73224351ee52a95fee0f1a617a2eae0e7d9d720cc622c73a54186" +dependencies = [ + "bitflags", +] + [[package]] name = "rayon" -version = "1.8.1" +version = "1.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa7237101a77a10773db45d62004a272517633fbcc3df19d96455ede1122e051" +checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d" dependencies = [ "either", "rayon-core", @@ -3011,40 +4479,57 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" +checksum = "22e18b0f0062d30d4230b2e85ff77fdfe4326feb054b9783a3460d8435c8ab91" dependencies = [ "crossbeam-deque", "crossbeam-utils", ] [[package]] -name = "rcgen" -version = "0.10.0" +name = "redox_syscall" +version = "0.5.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffbe84efe2f38dea12e9bfc1f65377fdf03e53a18cb3b995faedf7934c7e785b" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" dependencies = [ - "pem", - "ring 0.16.20", - "time", - "yasna", + "bitflags", ] [[package]] name = "redox_syscall" -version = "0.4.1" +version = "0.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f450ad9c3b1da563fb6948a8e0fb0fb9269711c9c73d9ea1de5058c79c8d643a" +dependencies = [ + "bitflags", +] + +[[package]] +name = "ref-cast" +version = "1.0.25" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f354300ae66f76f1c85c5f84693f0ce81d747e2c3f21a45fef496d89c960bf7d" +dependencies = [ + "ref-cast-impl", +] + +[[package]] +name = "ref-cast-impl" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +checksum = "b7186006dcb21920990093f30e3dea63b7d6e977bf1256be20c3563a5db070da" dependencies = [ - "bitflags 1.3.2", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "regex" -version = "1.10.2" +version = "1.12.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "380b951a9c5e80ddfd6136919eef32310721aa4aacd4889a8d39124b026ab343" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" dependencies = [ "aho-corasick", "memchr", @@ -3054,9 +4539,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.3" +version = "0.4.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f804c7828047e88b2d32e2d7fe5a105da8ee3264f01902f796c8e067dc2483f" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" dependencies = [ "aho-corasick", "memchr", @@ -3065,141 +4550,125 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" [[package]] name = "reqwest" -version = "0.11.23" +version = "0.12.28" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "37b1ae8d9ac08420c66222fb9096fc5de435c3c48542bc5336c51892cffafb41" +checksum = "eddd3ca559203180a307f12d114c268abf583f59b03cb906fd0b3ff8646c1147" dependencies = [ - "async-compression", - "base64 0.21.7", + "base64 0.22.1", "bytes", - "encoding_rs", + "futures-channel", "futures-core", "futures-util", - "h2", - "http", + "http 1.4.0", "http-body", + "http-body-util", "hyper", "hyper-rustls", - "ipnet", + "hyper-util", "js-sys", "log", - "mime", - "once_cell", "percent-encoding", "pin-project-lite", - "rustls", - "rustls-pemfile", + "quinn", + "rustls 0.23.38", + "rustls-pki-types", "serde", "serde_json", "serde_urlencoded", - "system-configuration", + "sync_wrapper", "tokio", - "tokio-rustls", - "tokio-util 0.7.10", + "tokio-rustls 0.26.4", + "tower", + "tower-http", "tower-service", "url", "wasm-bindgen", "wasm-bindgen-futures", "web-sys", - "webpki-roots 0.25.3", - "winreg", + "webpki-roots 1.0.7", ] [[package]] -name = "ring" -version = "0.16.20" +name = "reqwest-middleware" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3053cf52e236a3ed746dfc745aa9cacf1b791d846bdaf412f60a8d7d6e17c8fc" +checksum = "57f17d28a6e6acfe1733fe24bcd30774d13bffa4b8a22535b4c8c98423088d4e" dependencies = [ - "cc", - "libc", - "once_cell", - "spin 0.5.2", - "untrusted 0.7.1", - "web-sys", - "winapi", + "anyhow", + "async-trait", + "http 1.4.0", + "reqwest", + "serde", + "thiserror 1.0.69", + "tower-service", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac 0.12.1", + "subtle", ] [[package]] name = "ring" -version = "0.17.7" +version = "0.17.14" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "688c63d65483050968b2a8937f7995f443e27041a0f7700aa59b0822aedebb74" +checksum = "a4689e6c2294d81e88dc6261c768b63bc4fcdb852be6d1352498b114f61383b7" dependencies = [ "cc", - "getrandom 0.2.12", + "cfg-if", + "getrandom 0.2.17", "libc", - "spin 0.9.8", - "untrusted 0.9.0", - "windows-sys 0.48.0", + "untrusted", + "windows-sys 0.52.0", ] [[package]] name = "rmp" -version = "0.8.14" +version = "0.8.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +checksum = "4ba8be72d372b2c9b35542551678538b562e7cf86c3315773cae48dfbfe7790c" dependencies = [ - "byteorder", "num-traits", - "paste", ] [[package]] name = "rmp-serde" -version = "1.3.0" +version = "1.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +checksum = "72f81bee8c8ef9b577d1681a70ebbc962c232461e397b22c208c43c04b67a155" dependencies = [ - "byteorder", "rmp", "serde", ] -[[package]] -name = "rpassword" -version = "7.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "80472be3c897911d0137b2d2b9055faf6eeac5b14e324073d83bc17b191d7e3f" -dependencies = [ - "libc", - "rtoolbox", - "windows-sys 0.48.0", -] - -[[package]] -name = "rtoolbox" -version = "0.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c247d24e63230cdb56463ae328478bd5eac8b8faa8c69461a77e8e323afac90e" -dependencies = [ - "libc", - "windows-sys 0.48.0", -] - [[package]] name = "rustc-demangle" -version = "0.1.23" +version = "0.1.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" +checksum = "b50b8869d9fc858ce7266cce0194bd74df58b9d0e3f6df3a9fc8eb470d95c09d" [[package]] name = "rustc-hash" -version = "1.1.0" +version = "2.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" [[package]] name = "rustc_version" -version = "0.4.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa0f585226d2e68097d4f95d113b15b83a82e819ab25717ec0590d9584ef366" +checksum = "cfcb3a22ef46e85b45de6ee7e79d063319ebb6594faafcf1c225ea92ab6e9b92" dependencies = [ "semver", ] @@ -3215,71 +4684,124 @@ dependencies = [ [[package]] name = "rustix" -version = "0.38.30" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "322394588aaf33c24007e8bb3238ee3e4c5c09c084ab32bc73890b99ff326bca" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" dependencies = [ - "bitflags 2.5.0", + "bitflags", "errno", "libc", "linux-raw-sys", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] name = "rustls" -version = "0.21.10" +version = "0.21.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9d5a6813c0759e4609cd494e8e725babae6a2ca7b62a5536a13daaec6fcb7ba" +checksum = "3f56a14d1f48b391359b22f731fd4bd7e43c97f3c50eee276f3aa09c94784d3e" dependencies = [ "log", - "ring 0.17.7", - "rustls-webpki", + "ring", + "rustls-webpki 0.101.7", "sct", ] +[[package]] +name = "rustls" +version = "0.23.38" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69f9466fb2c14ea04357e91413efb882e2a6d4a406e625449bc0a5d360d53a21" +dependencies = [ + "once_cell", + "ring", + "rustls-pki-types", + "rustls-webpki 0.103.12", + "subtle", + "zeroize", +] + [[package]] name = "rustls-native-certs" -version = "0.6.3" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9aace74cb666635c918e9c12bc0d348266037aa8eb599b5cba565709a8dff00" +checksum = "612460d5f7bea540c490b2b6395d8e34a953e52b491accd6c86c8164c5932a63" dependencies = [ "openssl-probe", - "rustls-pemfile", + "rustls-pki-types", "schannel", "security-framework", ] [[package]] -name = "rustls-pemfile" -version = "1.0.4" +name = "rustls-pki-types" +version = "1.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c74cae0a4cf6ccbbf5f359f08efdf8ee7e1dc532573bf0db71968cb56b1448c" +checksum = "be040f8b0a225e40375822a563fa9524378b9d63112f53e19ffff34df5d33fdd" dependencies = [ - "base64 0.21.7", + "web-time", + "zeroize", +] + +[[package]] +name = "rustls-platform-verifier" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d99feebc72bae7ab76ba994bb5e121b8d83d910ca40b36e0921f53becc41784" +dependencies = [ + "core-foundation", + "core-foundation-sys", + "jni", + "log", + "once_cell", + "rustls 0.23.38", + "rustls-native-certs", + "rustls-platform-verifier-android", + "rustls-webpki 0.103.12", + "security-framework", + "security-framework-sys", + "webpki-root-certs", + "windows-sys 0.61.2", ] +[[package]] +name = "rustls-platform-verifier-android" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f87165f0995f63a9fbeea62b64d10b4d9d8e78ec6d7d51fb2125fda7bb36788f" + [[package]] name = "rustls-webpki" version = "0.101.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8b6275d1ee7a1cd780b64aca7726599a1dbc893b1e64144529e55c3c2f745765" dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", + "ring", + "untrusted", +] + +[[package]] +name = "rustls-webpki" +version = "0.103.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8279bb85272c9f10811ae6a6c547ff594d6a7f3c6c6b02ee9726d1d0dcfcdd06" +dependencies = [ + "ring", + "rustls-pki-types", + "untrusted", ] [[package]] name = "rustversion" -version = "1.0.14" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "ryu" -version = "1.0.16" +version = "1.0.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" [[package]] name = "same-file" @@ -3292,38 +4814,42 @@ dependencies = [ [[package]] name = "schannel" -version = "0.1.23" +version = "0.1.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fbc91545643bcf3a0bbb6569265615222618bdf33ce4ffbbd13c4bbd4c093534" +checksum = "91c1b7e4904c873ef0710c1f407dde2e6287de2bebc1bbbf7d430bb7cbffd939" dependencies = [ - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] -name = "scopeguard" -version = "1.2.0" +name = "schemars" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" +checksum = "4cd191f9397d57d581cddd31014772520aa448f65ef991055d7f61582c65165f" +dependencies = [ + "dyn-clone", + "ref-cast", + "serde", + "serde_json", +] [[package]] -name = "scroll" -version = "0.11.0" +name = "schemars" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04c565b551bafbef4157586fa379538366e4385d42082f255bfd96e4fe8519da" +checksum = "a2b42f36aa1cd011945615b92222f6bf73c599a102a300334cd7f8dbeec726cc" dependencies = [ - "scroll_derive", + "dyn-clone", + "ref-cast", + "serde", + "serde_json", ] [[package]] -name = "scroll_derive" -version = "0.11.1" +name = "scopeguard" +version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1db149f81d46d2deba7cd3c50772474707729550221e69588478ebf9ada425ae" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" [[package]] name = "sct" @@ -3331,17 +4857,31 @@ version = "0.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "da046153aa2352493d6cb7da4b6e5c0c057d8a1d0a9aa8560baffdd945acd414" dependencies = [ - "ring 0.17.7", - "untrusted 0.9.0", + "ring", + "untrusted", +] + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", ] [[package]] name = "security-framework" -version = "2.9.2" +version = "3.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "05b64fb303737d99b81884b2c63433e9ae28abebe5eb5045dcdd175dc2ecf4de" +checksum = "b7f4bc775c73d9a02cde8bf7b2ec4c9d12743edf609006c7facc23998404cd1d" dependencies = [ - "bitflags 1.3.2", + "bitflags", "core-foundation", "core-foundation-sys", "libc", @@ -3350,9 +4890,9 @@ dependencies = [ [[package]] name = "security-framework-sys" -version = "2.9.1" +version = "2.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e932934257d3b408ed8f30db49d85ea163bfe74961f017f405b025af298f0c7a" +checksum = "6ce2691df843ecc5d231c0b14ece2acc3efb62c0a398c7e1d875f3983ce020e3" dependencies = [ "core-foundation-sys", "libc", @@ -3360,48 +4900,79 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.21" +version = "1.0.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd" + +[[package]] +name = "seqlock" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b97ed7a9823b74f99c7742f5336af7be5ecd3eeafcb1507d1fa93347b1d589b0" +checksum = "b5c67b6f14ecc5b86c66fa63d76b5092352678545a8a3cdae80aef5128371910" +dependencies = [ + "parking_lot", +] [[package]] name = "serde" -version = "1.0.202" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "226b61a0d411b2ba5ff6d7f73a476ac4f8bb900373459cd00fab8512828ba395" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" dependencies = [ + "serde_core", "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_bytes" -version = "0.11.14" +version = "0.11.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b8497c313fd43ab992087548117643f6fcd935cbf36f176ffda0aacf9591734" +checksum = "a5d440709e79d88e51ac01c4b72fc6cb7314017bb7da9eeff678aa94c10e3ea8" dependencies = [ "serde", + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.202" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6048858004bcff69094cd972ed40a32500f153bd3be9f716b2eed2e8217c4838" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "serde_json" -version = "1.0.111" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "176e46fa42316f18edd598015a5166857fc835ec732f5215eac6b7bdbf0a84f4" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", - "ryu", + "memchr", "serde", + "serde_core", + "zmij", ] [[package]] @@ -3418,53 +4989,33 @@ dependencies = [ [[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 2.3.3", -] - -[[package]] -name = "serde_with" -version = "3.4.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "64cd236ccc1b7a29e7e2739f27c0b2dd199804abc4290e32f59f3b68d6405c23" +checksum = "dd5414fad8e6907dbdd5bc441a50ae8d6e26151a03b1de04d89a5576de61d01f" dependencies = [ - "base64 0.21.7", + "base64 0.22.1", "chrono", "hex", "indexmap 1.9.3", - "indexmap 2.1.0", - "serde", + "indexmap 2.14.0", + "schemars 0.9.0", + "schemars 1.2.1", + "serde_core", "serde_json", - "serde_with_macros 3.4.0", + "serde_with_macros", "time", ] [[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.48", -] - -[[package]] -name = "serde_with_macros" -version = "3.4.0" +version = "3.18.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93634eb5f75a2323b16de4748022ac4297f9e76b6dced2be287a099f41b5e788" +checksum = "d3db8978e608f1fe7357e211969fd9abdcae80bac1ba7a3369bb7eb6b404eb65" dependencies = [ - "darling", + "darling 0.23.0", "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] @@ -3474,7 +5025,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] @@ -3486,33 +5037,27 @@ checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" dependencies = [ "block-buffer 0.9.0", "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.9.0", "opaque-debug", ] [[package]] name = "sha2" -version = "0.10.8" +version = "0.10.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "a7507d819769d01a365ab707794a4084392c824f54a7a6a7862f8c3d0892b283" dependencies = [ "cfg-if", - "cpufeatures", + "cpufeatures 0.2.17", "digest 0.10.7", ] [[package]] -name = "sha3" -version = "0.9.1" +name = "sha2-const-stable" +version = "0.1.0" 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", -] +checksum = "5f179d4e11094a893b82fff208f74d448a7512f99f5a0acbd5c679b705f83ed9" [[package]] name = "sha3" @@ -3526,18 +5071,18 @@ dependencies = [ [[package]] name = "shank" -version = "0.4.2" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "23d894855493d4ce613b25550fe1ed1c62d0af5486b984579ba55e3f8c9631d5" +checksum = "2a1dc1d3af4ba5f02190110598b2abac0d13ce9dc58408aba4549e1c0f91a24c" dependencies = [ "shank_macro", ] [[package]] name = "shank_macro" -version = "0.4.2" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a9bf2645f8eebde043da69200195058e7b59806705104f908a31d05ca82844ce" +checksum = "63dbf105335507ad339dccacf3b1ea20e4c0b70d992b4de7cc11d5c0b91b0747" dependencies = [ "proc-macro2", "quote", @@ -3548,9 +5093,9 @@ dependencies = [ [[package]] name = "shank_macro_impl" -version = "0.4.2" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "93d0593f48acb0a722906416b1f6b8926f6571eb9af16d566a7c65427f269f50" +checksum = "346563412da6d1a53bc53c81f9d8b102f177952b95fd8de00e5d2203a4685635" dependencies = [ "anyhow", "proc-macro2", @@ -3561,9 +5106,9 @@ dependencies = [ [[package]] name = "shank_render" -version = "0.4.2" +version = "0.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "121175ba61809189f888dc5822ebfd30fa0d91e1e1f61d25a4d40b0847b3075e" +checksum = "8358067ec1787814d2577e76d9ddcc980559ad821e6bd04584f4847f4d1d955c" dependencies = [ "proc-macro2", "quote", @@ -3580,17 +5125,28 @@ dependencies = [ ] [[package]] -name = "shell-words" -version = "1.1.0" +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook" +version = "0.3.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24188a676b6ae68c3b2cb3a01be17fbf7240ce009799bb56d5b1409051e78fde" +checksum = "d881a16cf4426aa584979d30bd82cb33429027e42122b169753d6ef1085ed6e2" +dependencies = [ + "libc", + "signal-hook-registry", +] [[package]] name = "signal-hook-registry" -version = "1.4.1" +version = "1.4.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8229b473baa5980ac72ef434c4415e70c4b5e71b423043adb4ba059f89c99a1" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" dependencies = [ + "errno", "libc", ] @@ -3600,12 +5156,34 @@ version = "1.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "74233d3b3b2f6d4b006dc19dee745e73e2a6bfb6f93607cd3b02bd5b00797d7c" +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest 0.10.7", + "rand_core 0.6.4", +] + +[[package]] +name = "simd-adler32" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703d5c7ef118737c72f1af64ad2f6f8c5e1921f818cdcb97b8fe6fc69bf66214" + [[package]] name = "siphasher" version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "siphasher" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2aa850e253778c88a04c3d7323b043aeda9d3e30d5971937c1855769763678e" + [[package]] name = "sized-chunks" version = "0.6.5" @@ -3618,1467 +5196,5003 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.9" +version = "0.4.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" -dependencies = [ - "autocfg", -] +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" [[package]] name = "smallvec" -version = "1.13.1" +version = "1.15.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ecd384b10a64542d77071bd64bd7b231f4ed5940fba55e98c3de13824cf3d7" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" [[package]] name = "socket2" -version = "0.5.5" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5fac59a5cb5dd637972e5fca70daf0523c9067fcdc4842f053dae04a18f8e9" +checksum = "3a766e1110788c36f4fa1c2b71b387a7815aa65f88ce0229841826633d93723e" dependencies = [ "libc", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] -name = "solana-account-decoder" -version = "1.17.14" +name = "solana-account" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "21ed570fba6f909f69c888b48b39c7e61b454e3594e448d0dad9d973f27f5668" +checksum = "0f949fe4edaeaea78c844023bfc1c898e0b1f5a100f8a8d2d0f85d0a7b090258" dependencies = [ - "Inflector", - "base64 0.21.7", "bincode", - "bs58 0.4.0", - "bv", - "lazy_static", + "qualifier_attr", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 2.3.0", + "solana-clock 2.2.3", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-sysvar 2.3.0", +] + +[[package]] +name = "solana-account" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efc0ed36decb689413b9da5d57f2be49eea5bebb3cf7897015167b0c4336e731" +dependencies = [ + "bincode", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 3.1.1", + "solana-clock 3.0.1", + "solana-instruction-error", + "solana-pubkey 4.2.0", + "solana-sdk-ids 3.1.0", + "solana-sysvar 3.1.1", +] + +[[package]] +name = "solana-account-decoder-client-types" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76625f95bdb0c5c080b7ac34fab55a5b8f226164e0d4326d6132f4deba1bff1d" +dependencies = [ + "base64 0.22.1", + "bs58", "serde", "serde_derive", "serde_json", - "solana-config-program", - "solana-sdk", - "spl-token", - "spl-token-2022 1.0.0", - "spl-token-group-interface", - "spl-token-metadata-interface", - "thiserror", + "solana-account 3.4.0", + "solana-pubkey 3.0.0", "zstd", ] +[[package]] +name = "solana-account-info" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8f5152a288ef1912300fc6efa6c2d1f9bb55d9398eb6c72326360b8063987da" +dependencies = [ + "bincode", + "serde", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-account-info" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9cf16495d9eb53e3d04e72366a33bb1c20c24e78c171d8b8f5978357b63ae95" +dependencies = [ + "bincode", + "serde_core", + "solana-address 2.6.0", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", +] + [[package]] name = "solana-accounts-db" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31c457b335c3b13b0df99ffee59cf8b3d92e861abbddd0de93993367f449a76c" +checksum = "a3fa1f26526fabe870a990b7fd2ca51849a23f594ff18761503e89c034a36736" dependencies = [ - "arrayref", + "agave-io-uring", + "ahash 0.8.12", "bincode", "blake3", "bv", "bytemuck", - "byteorder", + "bytemuck_derive", "bzip2", "crossbeam-channel", "dashmap", - "flate2", - "fnv", - "fs-err", - "im", - "index_list", - "itertools", - "lazy_static", + "indexmap 2.14.0", + "io-uring", + "itertools 0.12.1", + "libc", "log", "lz4", - "memmap2", + "memmap2 0.9.10", "modular-bitfield", - "num-derive 0.3.3", - "num-traits", "num_cpus", - "num_enum 0.6.1", - "ouroboros", - "percentage", - "qualifier_attr", + "num_enum", "rand 0.8.5", "rayon", - "regex", - "rustc_version", + "seqlock", "serde", "serde_derive", + "slab", + "smallvec", + "solana-account 3.4.0", + "solana-address-lookup-table-interface 3.1.0", "solana-bucket-map", - "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-measure", - "solana-metrics", - "solana-program-runtime", + "solana-clock 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", + "solana-genesis-config 3.0.0", + "solana-hash 3.1.0", + "solana-lattice-hash", + "solana-measure 3.0.0", + "solana-message 3.1.0", + "solana-metrics 3.0.0", + "solana-nohash-hasher", + "solana-pubkey 3.0.0", "solana-rayon-threadlimit", - "solana-sdk", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", + "solana-reward-info 3.0.0", + "solana-sha256-hasher 3.1.0", + "solana-slot-hashes 3.0.1", + "solana-svm-transaction", + "solana-system-interface 2.0.0", + "solana-sysvar 3.1.1", + "solana-time-utils 3.0.0", + "solana-transaction 3.1.0", + "solana-transaction-context 3.0.0", + "solana-transaction-error 3.2.0", + "spl-generic-token", "static_assertions", - "strum 0.24.1", - "strum_macros 0.24.3", "tar", "tempfile", - "thiserror", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-address" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2ecac8e1b7f74c2baa9e774c42817e3e75b20787134b76cc4d45e8a604488f5" +dependencies = [ + "solana-address 2.6.0", +] + +[[package]] +name = "solana-address" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1384b52c435a750cc9c538760fc7bb472fd78e65a9900a2d07312c5bb335b72" +dependencies = [ + "borsh 1.6.1", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8 1.0.0", + "five8_const 1.0.0", + "rand 0.9.4", + "serde", + "serde_derive", + "sha2-const-stable", + "solana-atomic-u64 3.0.1", + "solana-define-syscall 5.1.0", + "solana-program-error 3.0.0", + "solana-sanitize 3.0.1", + "solana-sha256-hasher 3.1.0", + "wincode", ] [[package]] -name = "solana-address-lookup-table-program" -version = "1.17.14" +name = "solana-address-lookup-table-interface" +version = "2.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dba35ca5c434b2479a2a55b831461bd8cfdf2c389ee3ae4a0fc51918fbe17d88" +checksum = "d1673f67efe870b64a65cb39e6194be5b26527691ce5922909939961a6e6b395" +dependencies = [ + "bincode", + "bytemuck", + "serde", + "serde_derive", + "solana-clock 2.2.3", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-slot-hashes 2.2.1", +] + +[[package]] +name = "solana-address-lookup-table-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "115b4f773acc4f3f3cb986b0d335e9845c0368c82b0940410935bc11ae065578" dependencies = [ "bincode", "bytemuck", - "log", - "num-derive 0.3.3", - "num-traits", - "rustc_version", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-program", - "solana-program-runtime", - "solana-sdk", - "thiserror", + "serde_derive", + "solana-clock 3.0.1", + "solana-instruction 3.4.0", + "solana-instruction-error", + "solana-pubkey 4.2.0", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.1", +] + +[[package]] +name = "solana-atomic-u64" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52e52720efe60465b052b9e7445a01c17550666beec855cce66f44766697bc2" +dependencies = [ + "parking_lot", +] + +[[package]] +name = "solana-atomic-u64" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "085db4906d89324cef2a30840d59eaecf3d4231c560ec7c9f6614a93c652f501" +dependencies = [ + "parking_lot", ] [[package]] name = "solana-banks-client" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f22c7a0b5d1a81193875dded16ed189666fab0b753d46faec311c2798e0af34" +checksum = "c3e259bc2e06799e6aaf2665fa664e5301a28119f89793d6623e97ee7b36be3c" dependencies = [ - "borsh 0.10.3", + "borsh 1.6.1", "futures", + "solana-account 3.4.0", "solana-banks-interface", - "solana-program", - "solana-sdk", + "solana-clock 3.0.1", + "solana-commitment-config 3.1.1", + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-program-pack 3.1.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-signature 3.4.0", + "solana-sysvar 3.1.1", + "solana-transaction 3.1.0", + "solana-transaction-context 3.0.0", + "solana-transaction-error 3.2.0", "tarpc", - "thiserror", + "thiserror 2.0.18", "tokio", "tokio-serde", ] [[package]] name = "solana-banks-interface" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7c2652008dcd55d163e08e4d94c2b7592cb8562b33e168ac86462ddac4dca143" +checksum = "d1d4ee09683a05f1e5fe4a94a0d43ecb3a4abd9e00ca82728e73493edc0d5a21" dependencies = [ "serde", - "solana-sdk", + "serde_derive", + "solana-account 3.4.0", + "solana-clock 3.0.1", + "solana-commitment-config 3.1.1", + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", + "solana-signature 3.4.0", + "solana-transaction 3.1.0", + "solana-transaction-context 3.0.0", + "solana-transaction-error 3.2.0", "tarpc", ] [[package]] name = "solana-banks-server" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5a01440c39a08f90f8016013918491f8ffe16d066efe0508f9cb12e2863f6eaf" +checksum = "839fcc4bf090d8653b1cda01050ccb2748f4a1b27d0512eaffa5035532742a58" dependencies = [ + "agave-feature-set 3.0.0", "bincode", "crossbeam-channel", "futures", - "solana-accounts-db", + "solana-account 3.4.0", "solana-banks-interface", "solana-client", + "solana-clock 3.0.1", + "solana-commitment-config 3.1.1", + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", "solana-runtime", - "solana-sdk", + "solana-runtime-transaction", "solana-send-transaction-service", + "solana-signature 3.4.0", + "solana-svm", + "solana-transaction 3.1.0", + "solana-transaction-error 3.2.0", "tarpc", "tokio", "tokio-serde", ] +[[package]] +name = "solana-big-mod-exp" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75db7f2bbac3e62cfd139065d15bcda9e2428883ba61fc8d27ccb251081e7567" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 2.3.0", +] + +[[package]] +name = "solana-big-mod-exp" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "30c80fb6d791b3925d5ec4bf23a7c169ef5090c013059ec3ed7d0b2c04efa085" +dependencies = [ + "num-bigint 0.4.6", + "num-traits", + "solana-define-syscall 3.0.0", +] + +[[package]] +name = "solana-bincode" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19a3787b8cf9c9fe3dd360800e8b70982b9e5a8af9e11c354b6665dd4a003adc" +dependencies = [ + "bincode", + "serde", + "solana-instruction 2.3.3", +] + +[[package]] +name = "solana-bincode" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "278a1a5bad62cd9da89ac8d4b7ec444e83caa8ae96aa656dfc27684b28d49a5d" +dependencies = [ + "bincode", + "serde_core", + "solana-instruction-error", +] + +[[package]] +name = "solana-blake3-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a0801e25a1b31a14494fc80882a036be0ffd290efc4c2d640bfcca120a4672" +dependencies = [ + "blake3", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-blake3-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7116e1d942a2432ca3f514625104757ab8a56233787e95144c93950029e31176" +dependencies = [ + "blake3", + "solana-define-syscall 4.0.1", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-bn254" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4420f125118732833f36facf96a27e7b78314b2d642ba07fa9ffdacd8d79e243" +dependencies = [ + "ark-bn254 0.4.0", + "ark-ec 0.4.2", + "ark-ff 0.4.2", + "ark-serialize 0.4.2", + "bytemuck", + "solana-define-syscall 2.3.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-bn254" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62ff13a8867fcc7b0f1114764e1bf6191b4551dcaf93729ddc676cd4ec6abc9f" +dependencies = [ + "ark-bn254 0.5.0", + "ark-ec 0.5.0", + "ark-ff 0.5.0", + "ark-serialize 0.5.0", + "bytemuck", + "solana-define-syscall 5.1.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-borsh" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "718333bcd0a1a7aed6655aa66bef8d7fb047944922b2d3a18f49cbc13e73d004" +dependencies = [ + "borsh 0.10.4", + "borsh 1.6.1", +] + +[[package]] +name = "solana-borsh" +version = "3.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c04abbae16f57178a163125805637b8a076175bb5c0002fb04f4792bea901cf7" +dependencies = [ + "borsh 1.6.1", +] + [[package]] name = "solana-bpf-loader-program" -version = "1.17.14" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "571e8ef9d82bec9d32dd2d54b00e1572a85c967ed996cf737f3a52946d760623" +checksum = "b5aec57dcd80d0f6879956cad28854a6eebaed6b346ce56908ea01a9f36ab259" dependencies = [ "bincode", - "byteorder", "libsecp256k1", - "log", + "num-traits", + "qualifier_attr", "scopeguard", - "solana-measure", - "solana-program-runtime", - "solana-sdk", - "solana-zk-token-sdk", - "solana_rbpf", - "thiserror", + "solana-account 2.2.1", + "solana-account-info 2.3.0", + "solana-big-mod-exp 2.2.1", + "solana-bincode 2.2.1", + "solana-blake3-hasher 2.2.1", + "solana-bn254 2.2.2", + "solana-clock 2.2.3", + "solana-cpi 2.2.1", + "solana-curve25519 2.3.13", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-keccak-hasher 2.2.1", + "solana-loader-v3-interface 5.0.0", + "solana-loader-v4-interface 2.2.1", + "solana-log-collector", + "solana-measure 2.3.13", + "solana-packet 2.2.1", + "solana-poseidon 2.3.13", + "solana-program-entrypoint 2.3.0", + "solana-program-runtime 2.3.13", + "solana-pubkey 2.4.0", + "solana-sbpf 0.11.1", + "solana-sdk-ids 2.2.1", + "solana-secp256k1-recover 2.2.1", + "solana-sha256-hasher 2.3.0", + "solana-stable-layout 2.2.1", + "solana-svm-feature-set 2.3.13", + "solana-system-interface 1.0.0", + "solana-sysvar 2.3.0", + "solana-sysvar-id 2.2.1", + "solana-timings", + "solana-transaction-context 2.3.13", + "solana-type-overrides", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-bpf-loader-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4528133cc0e540525f9eb9013ffcaa3708615f5e4aa4926d93b16ac059cbe299" +dependencies = [ + "agave-syscalls", + "bincode", + "qualifier_attr", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-clock 3.0.1", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", + "solana-packet 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-sbpf 0.12.2", + "solana-sdk-ids 3.1.0", + "solana-svm-feature-set 3.0.0", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-type-overrides", + "solana-system-interface 2.0.0", + "solana-transaction-context 3.0.0", ] [[package]] name = "solana-bucket-map" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "109fdb52669846283bc6ef2ed87c832295af6f7e3c4e7888127b3d506054d651" +checksum = "ecb6479bd5c8e31c9ce8a060e27b70a27717247350eda52607b708d58efd7679" dependencies = [ "bv", "bytemuck", - "log", - "memmap2", + "bytemuck_derive", + "memmap2 0.9.10", "modular-bitfield", - "num_enum 0.6.1", + "num_enum", "rand 0.8.5", - "solana-measure", - "solana-sdk", + "solana-clock 3.0.1", + "solana-measure 3.0.0", + "solana-pubkey 3.0.0", "tempfile", ] [[package]] -name = "solana-clap-utils" -version = "1.17.14" +name = "solana-builtins" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4729fec3c2ac37b7daaf24c1ef879bbedbff3495b1ac728d9b627282d878753" +checksum = "d3de64f99fed955c6c5ab7fa9c90bd6d5897fcfcdd63317a4f331d4465c7ed2d" dependencies = [ - "chrono", - "clap 2.34.0", - "rpassword", - "solana-remote-wallet", - "solana-sdk", - "thiserror", - "tiny-bip39", - "uriparse", - "url", + "agave-feature-set 3.0.0", + "solana-bpf-loader-program 3.0.0", + "solana-compute-budget-program", + "solana-hash 3.1.0", + "solana-loader-v4-program", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-stake-program", + "solana-system-program 3.0.0", + "solana-vote-program", + "solana-zk-elgamal-proof-program", + "solana-zk-token-proof-program", +] + +[[package]] +name = "solana-builtins-default-costs" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "caa1b8b35fb23f4ee555eb91a5cdc9a4dabfdd40f001211b5a211808e07bff59" +dependencies = [ + "agave-feature-set 3.0.0", + "ahash 0.8.12", + "log", + "solana-bpf-loader-program 3.0.0", + "solana-compute-budget-program", + "solana-loader-v4-program", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-stake-program", + "solana-system-program 3.0.0", + "solana-vote-program", ] [[package]] name = "solana-client" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2da13019a833940af2edebda969db4337ab11c6fb220eb0d4c02d79c83ae8034" +checksum = "9851e1273c0503fb204fb0e5b7a42f05dd48cca910be02b9a8702af65f40a243" dependencies = [ "async-trait", "bincode", "dashmap", "futures", "futures-util", - "indexmap 2.1.0", + "indexmap 2.14.0", "indicatif", "log", "quinn", "rayon", + "solana-account 3.4.0", + "solana-client-traits 3.0.0", + "solana-commitment-config 3.1.1", "solana-connection-cache", - "solana-measure", - "solana-metrics", + "solana-epoch-info 3.1.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-keypair 3.0.0", + "solana-measure 3.0.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", "solana-pubsub-client", "solana-quic-client", + "solana-quic-definitions 3.0.0", "solana-rpc-client", "solana-rpc-client-api", "solana-rpc-client-nonce-utils", - "solana-sdk", + "solana-signature 3.4.0", + "solana-signer 3.0.0", "solana-streamer", - "solana-thin-client", + "solana-time-utils 3.0.0", "solana-tpu-client", + "solana-transaction 3.1.0", + "solana-transaction-error 3.2.0", + "solana-transaction-status-client-types", "solana-udp-client", - "thiserror", + "thiserror 2.0.18", "tokio", ] [[package]] -name = "solana-compute-budget-program" -version = "1.17.14" +name = "solana-client-traits" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0ba64641b22efb6332088dc5892369a2f2049f83e66459ea300a4fc74a7a9f84" +checksum = "83f0071874e629f29e0eb3dab8a863e98502ac7aba55b7e0df1803fc5cac72a7" dependencies = [ - "solana-program-runtime", - "solana-sdk", + "solana-account 2.2.1", + "solana-commitment-config 2.2.1", + "solana-epoch-info 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-keypair 2.2.3", + "solana-message 2.4.0", + "solana-pubkey 2.4.0", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction 2.2.3", + "solana-transaction-error 2.2.1", ] [[package]] -name = "solana-config-program" -version = "1.17.14" +name = "solana-client-traits" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04b91ca968a63946e7513a1de20188e6e917f09136339ee3bec247aa0e985d36" +checksum = "08618ed587e128105510c54ae3e456b9a06d674d8640db75afe66dad65cb4e02" dependencies = [ - "bincode", - "chrono", - "serde", - "serde_derive", - "solana-program-runtime", - "solana-sdk", + "solana-account 3.4.0", + "solana-commitment-config 3.1.1", + "solana-epoch-info 3.1.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-keypair 3.0.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "solana-system-interface 2.0.0", + "solana-transaction 3.1.0", + "solana-transaction-error 3.2.0", ] [[package]] -name = "solana-connection-cache" -version = "1.17.14" +name = "solana-clock" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a850c0122f094efb83df00ab080ab6ace0dcd8dbf91240f91832157ee6d460" +checksum = "f8584296123df8fe229b95e2ebfd37ae637fe9db9b7d4dd677ac5a78e80dbfce" dependencies = [ - "async-trait", - "bincode", - "crossbeam-channel", - "futures-util", - "indexmap 2.1.0", - "log", - "rand 0.8.5", - "rayon", - "rcgen", - "solana-measure", - "solana-metrics", - "solana-sdk", - "thiserror", - "tokio", + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", ] [[package]] -name = "solana-cost-model" -version = "1.17.14" +name = "solana-clock" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0c6e08e5be41ab19c7906a6b6adf58172fd49ee042f8511a6c4e0155daa1b7c" +checksum = "95cf11109c3b6115cc510f1e31f06fdd52f504271bc24ef5f1249fbbcae5f9f3" dependencies = [ - "lazy_static", - "log", - "rustc_version", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-compute-budget-program", - "solana-config-program", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-loader-v4-program", - "solana-metrics", - "solana-program-runtime", - "solana-sdk", - "solana-stake-program", - "solana-system-program", - "solana-vote-program", + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", ] [[package]] -name = "solana-frozen-abi" -version = "1.17.14" +name = "solana-cluster-type" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e2c5e5dde22cac045d29675b3fefa84817e1f63b0b911d094c599e80c0c07d9" +checksum = "7ace9fea2daa28354d107ea879cff107181d85cd4e0f78a2bedb10e1a428c97e" dependencies = [ - "ahash 0.8.6", - "blake3", - "block-buffer 0.10.4", - "bs58 0.4.0", - "bv", - "byteorder", - "cc", - "either", - "generic-array", - "im", - "lazy_static", - "log", - "memmap2", - "rustc_version", "serde", - "serde_bytes", "serde_derive", - "serde_json", - "sha2 0.10.8", - "solana-frozen-abi-macro", - "subtle", - "thiserror", + "solana-hash 2.3.0", ] [[package]] -name = "solana-frozen-abi-macro" -version = "1.17.14" +name = "solana-cluster-type" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "296e4cf0e2479e4c21afe4d17e32526f71f1bcd93b1c7c660900bc3e4233447a" +checksum = "3a494cf8eda7d98d9f0144b288bb409c88308d2e86f15cc1045aa77b83304718" dependencies = [ - "proc-macro2", - "quote", - "rustc_version", - "syn 2.0.48", + "serde", + "serde_derive", + "solana-hash 4.3.0", ] [[package]] -name = "solana-loader-v4-program" -version = "1.17.14" +name = "solana-commitment-config" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a902445f0bdf610e7eec94dab7f4a8e756d001c17651647730f1efcb9d7af6fe" +checksum = "ac49c4dde3edfa832de1697e9bcdb7c3b3f7cb7a1981b7c62526c8bb6700fb73" dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-commitment-config" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1517aa49dcfa9cb793ef90e7aac81346d62ca4a546bb1a754030a033e3972e1c" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-compute-budget" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f4fc63bc2276a1618ca0bfc609da7448534ecb43a1cb387cdf9eaa2dc7bc272" +dependencies = [ + "solana-fee-structure 2.3.0", + "solana-program-runtime 2.3.13", +] + +[[package]] +name = "solana-compute-budget" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c1f2216bb68fb61ba79c91709ded40271e5aac1bf3ca20f3f84a13ec4ae8e8b" +dependencies = [ + "solana-fee-structure 3.0.0", + "solana-program-runtime 3.0.0", +] + +[[package]] +name = "solana-compute-budget-instruction" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe37e1bca2920323eb1c2650f64d51962eee136583e3a3e35d831342ea15cc7c" +dependencies = [ + "agave-feature-set 3.0.0", + "log", + "solana-borsh 3.0.2", + "solana-builtins-default-costs", + "solana-compute-budget 3.0.0", + "solana-compute-budget-interface 3.0.0", + "solana-instruction 3.4.0", + "solana-packet 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-svm-transaction", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8432d2c4c22d0499aa06d62e4f7e333f81777b3d7c96050ae9e5cb71a8c3aee4" +dependencies = [ + "borsh 1.6.1", + "serde", + "serde_derive", + "solana-instruction 2.3.3", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-compute-budget-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8292c436b269ad23cecc8b24f7da3ab07ca111661e25e00ce0e1d22771951ab9" +dependencies = [ + "borsh 1.6.1", + "solana-instruction 3.4.0", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-compute-budget-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fe3d5b27630f6cf158e673108859fd55391f2fd2c4078c8b2422603306b5036" +dependencies = [ + "solana-program-runtime 3.0.0", +] + +[[package]] +name = "solana-config-interface" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e401ae56aed512821cc7a0adaa412ff97fecd2dff4602be7b1330d2daec0c4" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account 3.4.0", + "solana-instruction 3.4.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", + "solana-system-interface 2.0.0", +] + +[[package]] +name = "solana-connection-cache" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3cbf407fe1502d7c92dd7ae8645e2080bd8d273ddfb1f772666f9e51064b162f" +dependencies = [ + "async-trait", + "bincode", + "crossbeam-channel", + "futures-util", + "indexmap 2.14.0", + "log", + "rand 0.8.5", + "rayon", + "solana-keypair 3.0.0", + "solana-measure 3.0.0", + "solana-metrics 3.0.0", + "solana-time-utils 3.0.0", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-cost-model" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a97e1cca3bbbdc4506e7ce99fe99205859c548eaa88ff0b228a4601d05e82ab5" +dependencies = [ + "agave-feature-set 3.0.0", + "ahash 0.8.12", + "log", + "solana-bincode 3.1.0", + "solana-borsh 3.0.2", + "solana-builtins-default-costs", + "solana-clock 3.0.1", + "solana-compute-budget 3.0.0", + "solana-compute-budget-instruction", + "solana-compute-budget-interface 3.0.0", + "solana-fee-structure 3.0.0", + "solana-metrics 3.0.0", + "solana-packet 3.0.0", + "solana-pubkey 3.0.0", + "solana-runtime-transaction", + "solana-sdk-ids 3.1.0", + "solana-svm-transaction", + "solana-system-interface 2.0.0", + "solana-transaction-error 3.2.0", + "solana-vote-program", +] + +[[package]] +name = "solana-cpi" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dc71126edddc2ba014622fc32d0f5e2e78ec6c5a1e0eb511b85618c09e9ea11" +dependencies = [ + "solana-account-info 2.3.0", + "solana-define-syscall 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-stable-layout 2.2.1", +] + +[[package]] +name = "solana-cpi" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dea26709d867aada85d0d3617db0944215c8bb28d3745b912de7db13a23280c" +dependencies = [ + "solana-account-info 3.1.1", + "solana-define-syscall 4.0.1", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", + "solana-pubkey 4.2.0", + "solana-stable-layout 3.0.1", +] + +[[package]] +name = "solana-curve25519" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eae4261b9a8613d10e77ac831a8fa60b6fa52b9b103df46d641deff9f9812a23" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-define-syscall 2.3.0", + "subtle", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-curve25519" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2dab05c4022aaf34512f8237b868758d638839ce55e3e30bf26e14a8f7a81250" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "solana-define-syscall 3.0.0", + "subtle", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-decode-error" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c781686a18db2f942e70913f7ca15dc120ec38dcab42ff7557db2c70c625a35" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-define-syscall" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2ae3e2abcf541c8122eafe9a625d4d194b4023c20adde1e251f94e056bb1aee2" + +[[package]] +name = "solana-define-syscall" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9697086a4e102d28a156b8d6b521730335d6951bd39a5e766512bbe09007cee" + +[[package]] +name = "solana-define-syscall" +version = "4.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e5b1c0bc1d4a4d10c88a4100499d954c09d3fecfae4912c1a074dff68b1738" + +[[package]] +name = "solana-define-syscall" +version = "5.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21e14a4f604117f379840956a8fc8695e4c84f5b0ebed192f31f60d9b85d581d" + +[[package]] +name = "solana-derivation-path" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "939756d798b25c5ec3cca10e06212bdca3b1443cb9bb740a38124f58b258737b" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-derivation-path" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff71743072690fdbdfcdc37700ae1cb77485aaad49019473a81aee099b1e0b8c" +dependencies = [ + "derivation-path", + "qstring", + "uriparse", +] + +[[package]] +name = "solana-ed25519-program" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1feafa1691ea3ae588f99056f4bdd1293212c7ece28243d7da257c443e84753" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "ed25519-dalek 1.0.1", + "solana-feature-set", + "solana-instruction 2.3.3", + "solana-precompile-error 2.2.2", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-ed25519-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1419197f1c06abf760043f6d64ba9d79a03ad5a43f18c7586471937122094da" +dependencies = [ + "bytemuck", + "bytemuck_derive", + "solana-instruction 3.4.0", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-epoch-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ef6f0b449290b0b9f32973eefd95af35b01c5c0c34c569f936c34c5b20d77b" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-info" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e093c84f6ece620a6b10cd036574b0cd51944231ab32d81f80f76d54aba833e6" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-epoch-rewards" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b575d3dd323b9ea10bb6fe89bf6bf93e249b215ba8ed7f68f1a3633f384db7" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-epoch-rewards" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e7b0ba210593ba8ddd39d6d234d81795d1671cebf3026baa10d5dc23ac42f0" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 4.3.0", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-epoch-rewards-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c5fd2662ae7574810904585fd443545ed2b568dbd304b25a31e79ccc76e81b" +dependencies = [ + "siphasher 0.3.11", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-epoch-rewards-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ee8beac9bff4db9225e57d532d169b0be5e447f1e6601a2f50f27a01bf5518f" +dependencies = [ + "siphasher 0.3.11", + "solana-address 2.6.0", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-epoch-schedule" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3fce071fbddecc55d727b1d7ed16a629afe4f6e4c217bc8d00af3b785f6f67ed" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-epoch-schedule" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ce264b7b42322325947c4136a09460bf5c73d9aa8262c9b0a2064be63ba8639" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-epoch-stake" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "027e6d0b9e7daac5b2ac7c3f9ca1b727861121d9ef05084cf435ff736051e7c2" +dependencies = [ + "solana-define-syscall 5.1.0", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-example-mocks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84461d56cbb8bb8d539347151e0525b53910102e4bced875d49d5139708e39d3" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface 2.2.2", + "solana-clock 2.2.3", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-keccak-hasher 2.2.1", + "solana-message 2.4.0", + "solana-nonce 2.2.1", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-example-mocks" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978855d164845c1b0235d4b4d101cadc55373fffaf0b5b6cfa2194d25b2ed658" +dependencies = [ + "serde", + "serde_derive", + "solana-address-lookup-table-interface 3.1.0", + "solana-clock 3.0.1", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-keccak-hasher 3.1.0", + "solana-message 3.1.0", + "solana-nonce 3.2.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-system-interface 2.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43f5c5382b449e8e4e3016fb05e418c53d57782d8b5c30aa372fc265654b956d" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account 2.2.1", + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "solana-feature-gate-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75ca9b5cbb6f500f7fd73db5bd95640f71a83f04d6121a0e59a43b202dca2731" +dependencies = [ + "bincode", + "serde", + "serde_derive", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", + "solana-pubkey 4.2.0", + "solana-rent 4.2.0", + "solana-sdk-ids 3.1.0", + "solana-system-interface 3.2.0", +] + +[[package]] +name = "solana-feature-set" +version = "2.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93b93971e289d6425f88e6e3cb6668c4b05df78b3c518c249be55ced8efd6b6d" +dependencies = [ + "ahash 0.8.12", + "lazy_static", + "solana-epoch-schedule 2.2.1", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", + "solana-sha256-hasher 2.3.0", +] + +[[package]] +name = "solana-fee" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c986086198e93974b008ad9c4bd0533aec33fed2549fb9016b0848be324b8422" +dependencies = [ + "agave-feature-set 3.0.0", + "solana-fee-structure 3.0.0", + "solana-svm-transaction", +] + +[[package]] +name = "solana-fee-calculator" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d89bc408da0fb3812bc3008189d148b4d3e08252c79ad810b245482a3f70cd8d" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-calculator" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57e8add96b5741573e9f7529c4bb7719cfcfa999c3847a68cdfaef0cb6adf567" +dependencies = [ + "log", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-fee-structure" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "33adf673581c38e810bf618f745bf31b683a0a4a4377682e6aaac5d9a058dd4e" +dependencies = [ + "serde", + "serde_derive", + "solana-message 2.4.0", + "solana-native-token 2.3.0", +] + +[[package]] +name = "solana-fee-structure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e2abdb1223eea8ec64136f39cb1ffcf257e00f915c957c35c0dd9e3f4e700b0" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-genesis-config" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3725085d47b96d37fef07a29d78d2787fc89a0b9004c66eed7753d1e554989f" +dependencies = [ + "bincode", + "chrono", + "memmap2 0.5.10", + "serde", + "serde_derive", + "solana-account 2.2.1", + "solana-clock 2.2.3", + "solana-cluster-type 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-inflation 2.2.1", + "solana-keypair 2.2.3", + "solana-logger 2.3.1", + "solana-poh-config 2.2.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sha256-hasher 2.3.0", + "solana-shred-version 2.2.1", + "solana-signer 2.2.1", + "solana-time-utils 2.2.1", +] + +[[package]] +name = "solana-genesis-config" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "749eccc960e85c9b33608450093d256006253e1cb436b8380e71777840a3f675" +dependencies = [ + "bincode", + "chrono", + "memmap2 0.5.10", + "serde", + "serde_derive", + "solana-account 3.4.0", + "solana-clock 3.0.1", + "solana-cluster-type 3.1.0", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", + "solana-hash 3.1.0", + "solana-inflation 3.1.0", + "solana-keypair 3.0.0", + "solana-poh-config 3.0.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sdk-ids 3.1.0", + "solana-sha256-hasher 3.1.0", + "solana-shred-version 3.0.1", + "solana-signer 3.0.0", + "solana-time-utils 3.0.0", +] + +[[package]] +name = "solana-hard-forks" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c28371f878e2ead55611d8ba1b5fb879847156d04edea13693700ad1a28baf" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hard-forks" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52fd9cc610fd0782f09482527cb7b4f41ec22071303742718b7b57fc43bb236b" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-hash" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5b96e9f0300fa287b545613f007dfe20043d7812bee255f418c1eb649c93b63" +dependencies = [ + "borsh 1.6.1", + "bytemuck", + "bytemuck_derive", + "five8 0.2.1", + "js-sys", + "serde", + "serde_derive", + "solana-atomic-u64 2.2.1", + "solana-sanitize 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-hash" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "337c246447142f660f778cf6cb582beba8e28deb05b3b24bfb9ffd7c562e5f41" +dependencies = [ + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-hash" +version = "4.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1b113239362cee7093bfb250467138f079a2a03673181dc15bff6ccd677912d" +dependencies = [ + "borsh 1.6.1", + "bytemuck", + "bytemuck_derive", + "five8 1.0.0", + "serde", + "serde_derive", + "solana-atomic-u64 3.0.1", + "solana-sanitize 3.0.1", + "wincode", +] + +[[package]] +name = "solana-inflation" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23eef6a09eb8e568ce6839573e4966850e85e9ce71e6ae1a6c930c1c43947de3" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-inflation" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f762559c5f962727efdcb03c61f5cf6c5364645695978fb145d25c88bbacdada" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-instruction" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bab5682934bd1f65f8d2c16f21cb532526fcc1a09f796e2cacdb091eee5774ad" +dependencies = [ + "bincode", + "borsh 1.6.1", + "getrandom 0.2.17", + "js-sys", + "num-traits", + "serde", + "serde_derive", + "serde_json", + "solana-define-syscall 2.3.0", + "solana-pubkey 2.4.0", + "wasm-bindgen", +] + +[[package]] +name = "solana-instruction" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37ebb0ffd19263051bc3f683fcc086134b8ff23af894dcb63f7563c7137b42f1" +dependencies = [ + "bincode", + "borsh 1.6.1", + "serde", + "serde_derive", + "solana-define-syscall 5.1.0", + "solana-instruction-error", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-instruction-error" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0b188842592fdf6cb96f55263ae1bf11713ab5114401d1d5a881ed7cc41bef6" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-program-error 3.0.0", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0e85a6fad5c2d0c4f5b91d34b8ca47118fc593af706e523cdbedf846a954f57" +dependencies = [ + "bitflags", + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serialize-utils 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-instructions-sysvar" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ddf67876c541aa1e21ee1acae35c95c6fbc61119814bfef70579317a5e26955" +dependencies = [ + "bitflags", + "solana-account-info 3.1.1", + "solana-instruction 3.4.0", + "solana-instruction-error", + "solana-program-error 3.0.0", + "solana-pubkey 3.0.0", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-serialize-utils 3.1.1", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-invoke" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58f5693c6de226b3626658377168b0184e94e8292ff16e3d31d4766e65627565" +dependencies = [ + "solana-account-info 2.3.0", + "solana-define-syscall 2.3.0", + "solana-instruction 2.3.3", + "solana-program-entrypoint 2.3.0", + "solana-stable-layout 2.2.1", +] + +[[package]] +name = "solana-keccak-hasher" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c7aeb957fbd42a451b99235df4942d96db7ef678e8d5061ef34c9b34cae12f79" +dependencies = [ + "sha3", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-keccak-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed1c0d16d6fdeba12291a1f068cdf0d479d9bff1141bf44afd7aa9d485f65ef8" +dependencies = [ + "sha3", + "solana-define-syscall 4.0.1", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-keypair" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd3f04aa1a05c535e93e121a95f66e7dcccf57e007282e8255535d24bf1e98bb" +dependencies = [ + "ed25519-dalek 1.0.1", + "ed25519-dalek-bip32 0.2.0", + "five8 0.2.1", + "rand 0.7.3", + "solana-derivation-path 2.2.1", + "solana-pubkey 2.4.0", + "solana-seed-derivable 2.2.1", + "solana-seed-phrase 2.2.1", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-keypair" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "80eaf45d386c94e59c0c2d3db4a76c05f90365394aa848edce5826d3f7e77fb3" +dependencies = [ + "ed25519-dalek 2.2.0", + "ed25519-dalek-bip32 0.3.0", + "five8 0.2.1", + "rand 0.8.5", + "solana-derivation-path 3.0.0", + "solana-pubkey 3.0.0", + "solana-seed-derivable 3.0.0", + "solana-seed-phrase 3.0.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", +] + +[[package]] +name = "solana-last-restart-slot" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a6360ac2fdc72e7463565cd256eedcf10d7ef0c28a1249d261ec168c1b55cdd" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-last-restart-slot" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcda154ec827f5fc1e4da0af3417951b7e9b8157540f81f936c4a8b1156134d0" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-lattice-hash" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "16bfb7c5b8f005fed6d87fde9e4544a4875344a656f799c211a8650e6eec867f" +dependencies = [ + "base64 0.22.1", + "blake3", + "bs58", + "bytemuck", +] + +[[package]] +name = "solana-loader-v2-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8ab08006dad78ae7cd30df8eea0539e207d08d91eaefb3e1d49a446e1c49654" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa4be76cfa9afd84ca2f35ebc09f0da0f0092935ccdac0595d98447f259538c2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "5.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6f7162a05b8b0773156b443bccd674ea78bb9aa406325b467ea78c06c99a63a2" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "solana-loader-v3-interface" +version = "6.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2e0538d4dbc9022e01616f1c58f2db98ece739c5d5ed4a2ef8737a953e76a2d4" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 3.4.0", + "solana-pubkey 4.2.0", + "solana-sdk-ids 3.1.0", + "solana-system-interface 3.2.0", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "706a777242f1f39a83e2a96a2a6cb034cb41169c6ecbee2cf09cb873d9659e7e" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", +] + +[[package]] +name = "solana-loader-v4-interface" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4c948b33ff81fa89699911b207059e493defdba9647eaf18f23abdf3674e0fb" +dependencies = [ + "serde", + "serde_bytes", + "serde_derive", + "solana-instruction 3.4.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-system-interface 2.0.0", +] + +[[package]] +name = "solana-loader-v4-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "293c1a6fb01621bbe24926440766ad1810f922c34b7512884602cbc1330c2aee" +dependencies = [ + "log", + "qualifier_attr", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-bpf-loader-program 3.0.0", + "solana-instruction 3.4.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", + "solana-packet 3.0.0", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-sbpf 0.12.2", + "solana-sdk-ids 3.1.0", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-type-overrides", + "solana-transaction-context 3.0.0", +] + +[[package]] +name = "solana-log-collector" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d945b1cf5bf7cbd6f5b78795beda7376370c827640df43bb2a1c17b492dc106" +dependencies = [ + "log", +] + +[[package]] +name = "solana-logger" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db8e777ec1afd733939b532a42492d888ec7c88d8b4127a5d867eb45c6eb5cd5" +dependencies = [ + "env_logger 0.9.3", + "lazy_static", + "libc", + "log", + "signal-hook", +] + +[[package]] +name = "solana-logger" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef7421d1092680d72065edbf5c7605856719b021bf5f173656c71febcdd5d003" +dependencies = [ + "env_logger 0.11.10", + "lazy_static", + "libc", + "log", + "signal-hook", +] + +[[package]] +name = "solana-measure" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11dcd67cd2ae6065e494b64e861e0498d046d95a61cbbf1ae3d58be1ea0f42ed" + +[[package]] +name = "solana-measure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86b9557f15c46d3f4aa2f836e37e5c904c643c602a7f31c9f2dc64dd5d81ff24" + +[[package]] +name = "solana-message" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1796aabce376ff74bf89b78d268fa5e683d7d7a96a0a4e4813ec34de49d5314b" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-bincode 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction-error 2.2.1", + "wasm-bindgen", +] + +[[package]] +name = "solana-message" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0448b1fd891c5f46491e5dc7d9986385ba3c852c340db2911dd29faa01d2b08d" +dependencies = [ + "bincode", + "blake3", + "lazy_static", + "serde", + "serde_derive", + "solana-address 2.6.0", + "solana-hash 4.3.0", + "solana-instruction 3.4.0", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", + "solana-transaction-error 3.2.0", +] + +[[package]] +name = "solana-metrics" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0375159d8460f423d39e5103dcff6e07796a5ec1850ee1fcfacfd2482a8f34b5" +dependencies = [ + "crossbeam-channel", + "gethostname", + "log", + "reqwest", + "solana-cluster-type 2.2.1", + "solana-sha256-hasher 2.3.0", + "solana-time-utils 2.2.1", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-metrics" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d54bd8fa33466ba0354300f160170ef90aa474620ab1853d5e632043eff90b57" +dependencies = [ + "crossbeam-channel", + "gethostname", + "log", + "reqwest", + "solana-cluster-type 3.1.0", + "solana-sha256-hasher 3.1.0", + "solana-time-utils 3.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-msg" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f36a1a14399afaabc2781a1db09cb14ee4cc4ee5c7a5a3cfcc601811379a8092" +dependencies = [ + "solana-define-syscall 2.3.0", +] + +[[package]] +name = "solana-msg" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "726b7cbbc6be6f1c6f29146ac824343b9415133eee8cce156452ad1db93f8008" +dependencies = [ + "solana-define-syscall 5.1.0", +] + +[[package]] +name = "solana-native-token" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61515b880c36974053dd499c0510066783f0cc6ac17def0c7ef2a244874cf4a9" + +[[package]] +name = "solana-native-token" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae8dd4c280dca9d046139eb5b7a5ac9ad10403fbd64964c7d7571214950d758f" + +[[package]] +name = "solana-net-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2340c9463ce28e44718108bf717da285959ed3dff41d6bfd4ea1471b485fb4f" +dependencies = [ + "anyhow", + "bincode", + "bytes", + "itertools 0.12.1", + "log", + "nix", + "rand 0.8.5", + "serde", + "serde_derive", + "socket2", + "solana-serde 3.0.0", + "tokio", + "url", +] + +[[package]] +name = "solana-nohash-hasher" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b8a731ed60e89177c8a7ab05fe0f1511cedd3e70e773f288f9de33a9cfdc21e" + +[[package]] +name = "solana-nonce" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703e22eb185537e06204a5bd9d509b948f0066f2d1d814a6f475dafb3ddf1325" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-pubkey 2.4.0", + "solana-sha256-hasher 2.3.0", +] + +[[package]] +name = "solana-nonce" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d95dbc9f2e33b6c10e231df15cb2a3bff9ea7eab6347f9e316fe75c97fd67bbb" +dependencies = [ + "serde", + "serde_derive", + "solana-fee-calculator 3.2.0", + "solana-hash 4.3.0", + "solana-pubkey 4.2.0", + "solana-sha256-hasher 3.1.0", +] + +[[package]] +name = "solana-nonce-account" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cde971a20b8dbf60144d6a84439dda86b5466e00e2843091fe731083cda614da" +dependencies = [ + "solana-account 2.2.1", + "solana-hash 2.3.0", + "solana-nonce 2.2.1", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-nonce-account" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "805fd25b29e5a1a0e6c3dd6320c9da80f275fbe4ff6e392617c303a2085c435e" +dependencies = [ + "solana-account 3.4.0", + "solana-hash 3.1.0", + "solana-nonce 3.2.0", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-offchain-message" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b526398ade5dea37f1f147ce55dae49aa017a5d7326606359b0445ca8d946581" +dependencies = [ + "num_enum", + "solana-hash 2.3.0", + "solana-packet 2.2.1", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sha256-hasher 2.3.0", + "solana-signature 2.3.0", + "solana-signer 2.2.1", +] + +[[package]] +name = "solana-offchain-message" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6e2a1141a673f72a05cf406b99e4b2b8a457792b7c01afa07b3f00d4e2de393" +dependencies = [ + "num_enum", + "solana-hash 3.1.0", + "solana-packet 3.0.0", + "solana-pubkey 3.0.0", + "solana-sanitize 3.0.1", + "solana-sha256-hasher 3.1.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", +] + +[[package]] +name = "solana-packet" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "004f2d2daf407b3ec1a1ca5ec34b3ccdfd6866dd2d3c7d0715004a96e4b6d127" +dependencies = [ + "bincode", + "bitflags", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-packet" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6edf2f25743c95229ac0fdc32f8f5893ef738dbf332c669e9861d33ddb0f469d" +dependencies = [ + "bincode", + "bitflags", + "cfg_eval", + "serde", + "serde_derive", + "serde_with", +] + +[[package]] +name = "solana-perf" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95cd5639552166f92a884218f68c12576026b6502f0de2bb61c3abaedcdb0f65" +dependencies = [ + "ahash 0.8.12", + "bincode", + "bv", + "bytes", + "caps", + "curve25519-dalek 4.1.3", + "dlopen2", + "fnv", + "libc", + "log", + "nix", + "rand 0.8.5", + "rayon", + "serde", + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-metrics 3.0.0", + "solana-packet 3.0.0", + "solana-pubkey 3.0.0", + "solana-rayon-threadlimit", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", + "solana-signature 3.4.0", + "solana-time-utils 3.0.0", +] + +[[package]] +name = "solana-poh-config" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d650c3b4b9060082ac6b0efbbb66865089c58405bfb45de449f3f2b91eccee75" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-poh-config" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2f1fef1f2ff2480fdbcc64bef5e3c47bec6e1647270db88b43f23e3a55f8d9cf" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-poseidon" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbac4eb90016eeb1d37fa36e592d3a64421510c49666f81020736611c319faff" +dependencies = [ + "ark-bn254 0.4.0", + "light-poseidon", + "solana-define-syscall 2.3.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-poseidon" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ff32717f251f272e52d0c668befe78ec1e060544dd763671e75d88fda04063c" +dependencies = [ + "ark-bn254 0.4.0", + "light-poseidon", + "solana-define-syscall 3.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-precompile-error" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d87b2c1f5de77dfe2b175ee8dd318d196aaca4d0f66f02842f80c852811f9f8" +dependencies = [ + "num-traits", + "solana-decode-error", +] + +[[package]] +name = "solana-precompile-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cafcd950de74c6c39d55dc8ca108bbb007799842ab370ef26cf45a34453c31e1" +dependencies = [ + "num-traits", +] + +[[package]] +name = "solana-precompiles" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36e92768a57c652edb0f5d1b30a7d0bc64192139c517967c18600debe9ae3832" +dependencies = [ + "lazy_static", + "solana-ed25519-program 2.2.3", + "solana-feature-set", + "solana-message 2.4.0", + "solana-precompile-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-secp256k1-program 2.2.3", + "solana-secp256r1-program 2.2.4", +] + +[[package]] +name = "solana-presigner" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81a57a24e6a4125fc69510b6774cd93402b943191b6cddad05de7281491c90fe" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-signature 2.3.0", + "solana-signer 2.2.1", +] + +[[package]] +name = "solana-presigner" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f704eaf825be3180832445b9e4983b875340696e8e7239bf2d535b0f86c14a2" +dependencies = [ + "solana-pubkey 3.0.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", +] + +[[package]] +name = "solana-program" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98eca145bd3545e2fbb07166e895370576e47a00a7d824e325390d33bf467210" +dependencies = [ + "bincode", + "blake3", + "borsh 0.10.4", + "borsh 1.6.1", + "bs58", + "bytemuck", + "console_error_panic_hook", + "console_log", + "getrandom 0.2.17", + "lazy_static", + "log", + "memoffset", + "num-bigint 0.4.6", + "num-derive 0.4.2", + "num-traits", + "rand 0.8.5", + "serde", + "serde_bytes", + "serde_derive", + "solana-account-info 2.3.0", + "solana-address-lookup-table-interface 2.2.2", + "solana-atomic-u64 2.2.1", + "solana-big-mod-exp 2.2.1", + "solana-bincode 2.2.1", + "solana-blake3-hasher 2.2.1", + "solana-borsh 2.2.1", + "solana-clock 2.2.3", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-example-mocks 2.2.1", + "solana-feature-gate-interface 2.2.2", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-keccak-hasher 2.2.1", + "solana-last-restart-slot 2.2.1", + "solana-loader-v2-interface", + "solana-loader-v3-interface 5.0.0", + "solana-loader-v4-interface 2.2.1", + "solana-message 2.4.0", + "solana-msg 2.2.1", + "solana-native-token 2.3.0", + "solana-nonce 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-program-option 2.2.1", + "solana-program-pack 2.2.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-secp256k1-recover 2.2.1", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-sha256-hasher 2.3.0", + "solana-short-vec 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stable-layout 2.2.1", + "solana-stake-interface 1.2.1", + "solana-system-interface 1.0.0", + "solana-sysvar 2.3.0", + "solana-sysvar-id 2.2.1", + "solana-vote-interface 2.2.6", + "thiserror 2.0.18", + "wasm-bindgen", +] + +[[package]] +name = "solana-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91b12305dd81045d705f427acd0435a2e46444b65367d7179d7bdcfc3bc5f5eb" +dependencies = [ + "memoffset", + "solana-account-info 3.1.1", + "solana-big-mod-exp 3.0.0", + "solana-blake3-hasher 3.1.0", + "solana-borsh 3.0.2", + "solana-clock 3.0.1", + "solana-cpi 3.1.0", + "solana-define-syscall 3.0.0", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-epoch-stake", + "solana-example-mocks 3.0.0", + "solana-fee-calculator 3.2.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-instruction-error", + "solana-instructions-sysvar 3.0.0", + "solana-keccak-hasher 3.1.0", + "solana-last-restart-slot 3.0.0", + "solana-msg 3.1.0", + "solana-native-token 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", + "solana-program-option 3.1.0", + "solana-program-pack 3.1.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sdk-ids 3.1.0", + "solana-secp256k1-recover 3.1.1", + "solana-serde-varint 3.0.1", + "solana-serialize-utils 3.1.1", + "solana-sha256-hasher 3.1.0", + "solana-short-vec 3.2.0", + "solana-slot-hashes 3.0.1", + "solana-slot-history 3.0.0", + "solana-stable-layout 3.0.1", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-program-entrypoint" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32ce041b1a0ed275290a5008ee1a4a6c48f5054c8a3d78d313c08958a06aedbd" +dependencies = [ + "solana-account-info 2.3.0", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-program-entrypoint" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c9b0a1ff494e05f503a08b3d51150b73aa639544631e510279d6375f290997" +dependencies = [ + "solana-account-info 3.1.1", + "solana-define-syscall 4.0.1", + "solana-program-error 3.0.0", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-program-error" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ee2e0217d642e2ea4bee237f37bd61bb02aec60da3647c48ff88f6556ade775" +dependencies = [ + "borsh 1.6.1", + "num-traits", + "serde", + "serde_derive", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-program-error" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1af32c995a7b692a915bb7414d5f8e838450cf7c70414e763d8abcae7b51f28" +dependencies = [ + "borsh 1.6.1", + "serde", + "serde_derive", +] + +[[package]] +name = "solana-program-memory" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a5426090c6f3fd6cfdc10685322fede9ca8e5af43cd6a59e98bfe4e91671712" +dependencies = [ + "solana-define-syscall 2.3.0", +] + +[[package]] +name = "solana-program-memory" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4068648649653c2c50546e9a7fb761791b5ab0cda054c771bb5808d3a4b9eb52" +dependencies = [ + "solana-define-syscall 4.0.1", +] + +[[package]] +name = "solana-program-option" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc677a2e9bc616eda6dbdab834d463372b92848b2bfe4a1ed4e4b4adba3397d0" + +[[package]] +name = "solana-program-option" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a88006a9b8594088cec9027ab77caaaa258a2aaa2083d3f086c44b42e50aeab" + +[[package]] +name = "solana-program-pack" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "319f0ef15e6e12dc37c597faccb7d62525a509fec5f6975ecb9419efddeb277b" +dependencies = [ + "solana-program-error 2.2.2", +] + +[[package]] +name = "solana-program-pack" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7701cb15b90667ae1c89ef4ac35a59c61e66ce58ddee13d729472af7f41d59" +dependencies = [ + "solana-program-error 3.0.0", +] + +[[package]] +name = "solana-program-runtime" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5653001e07b657c9de6f0417cf9add1cf4325903732c480d415655e10cc86704" +dependencies = [ + "base64 0.22.1", + "bincode", + "enum-iterator", + "itertools 0.12.1", + "log", + "percentage", + "rand 0.8.5", + "serde", + "solana-account 2.2.1", + "solana-clock 2.2.3", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-fee-structure 2.3.0", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-last-restart-slot 2.2.1", + "solana-log-collector", + "solana-measure 2.3.13", + "solana-metrics 2.3.13", + "solana-program-entrypoint 2.3.0", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sbpf 0.11.1", + "solana-sdk-ids 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-stable-layout 2.2.1", + "solana-svm-callback 2.3.13", + "solana-svm-feature-set 2.3.13", + "solana-system-interface 1.0.0", + "solana-sysvar 2.3.0", + "solana-sysvar-id 2.2.1", + "solana-timings", + "solana-transaction-context 2.3.13", + "solana-type-overrides", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-program-runtime" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de830498586c69acc46747e241c1e60d9c7aba572d014be3a2c7b1b1306c0304" +dependencies = [ + "base64 0.22.1", + "bincode", + "itertools 0.12.1", + "log", + "percentage", + "rand 0.8.5", + "serde", + "solana-account 3.4.0", + "solana-clock 3.0.1", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-fee-structure 3.0.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-last-restart-slot 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sbpf 0.12.2", + "solana-sdk-ids 3.1.0", + "solana-slot-hashes 3.0.1", + "solana-stake-interface 2.0.2", + "solana-svm-callback 3.0.0", + "solana-svm-feature-set 3.0.0", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-metrics", + "solana-svm-timings", + "solana-svm-transaction", + "solana-svm-type-overrides", + "solana-system-interface 2.0.0", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", + "solana-transaction-context 3.0.0", +] + +[[package]] +name = "solana-program-test" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "473f0f51104f7e41ff81e20017ec427d82bd227a1ddd09d0a45ea1230e156b71" +dependencies = [ + "agave-feature-set 3.0.0", + "assert_matches", + "async-trait", + "base64 0.22.1", + "bincode", + "chrono-humanize", + "crossbeam-channel", + "log", + "serde", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-accounts-db", + "solana-banks-client", + "solana-banks-interface", + "solana-banks-server", + "solana-clock 3.0.1", + "solana-cluster-type 3.1.0", + "solana-commitment-config 3.1.1", + "solana-compute-budget 3.0.0", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", + "solana-genesis-config 3.0.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-keypair 3.0.0", + "solana-loader-v3-interface 6.1.1", + "solana-logger 3.0.0", + "solana-message 3.1.0", + "solana-msg 3.1.0", + "solana-native-token 3.0.0", + "solana-poh-config 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-runtime", + "solana-sbpf 0.12.2", + "solana-sdk-ids 3.1.0", + "solana-signer 3.0.0", + "solana-stable-layout 3.0.1", + "solana-stake-interface 2.0.2", + "solana-svm", + "solana-svm-log-collector", + "solana-svm-timings", + "solana-system-interface 2.0.0", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", + "solana-transaction 3.1.0", + "solana-transaction-context 3.0.0", + "solana-transaction-error 3.2.0", + "solana-vote-program", + "spl-generic-token", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-pubkey" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b62adb9c3261a052ca1f999398c388f1daf558a1b492f60a6d9e64857db4ff1" +dependencies = [ + "borsh 0.10.4", + "borsh 1.6.1", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "five8 0.2.1", + "five8_const 0.1.4", + "getrandom 0.2.17", + "js-sys", + "num-traits", + "rand 0.8.5", + "serde", + "serde_derive", + "solana-atomic-u64 2.2.1", + "solana-decode-error", + "solana-define-syscall 2.3.0", + "solana-sanitize 2.2.1", + "solana-sha256-hasher 2.3.0", + "wasm-bindgen", +] + +[[package]] +name = "solana-pubkey" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8909d399deb0851aa524420beeb5646b115fd253ef446e35fe4504c904da3941" +dependencies = [ + "rand 0.8.5", + "solana-address 1.1.0", +] + +[[package]] +name = "solana-pubkey" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7db719574990de7e8b0f55a8593ac92a5ccb42c8ce67b3e4bf05b139d5d9ee71" +dependencies = [ + "solana-address 2.6.0", +] + +[[package]] +name = "solana-pubsub-client" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf675756739fce7d5352aa87d2d2907ab700397cf7b250672f401e43a18959e" +dependencies = [ + "crossbeam-channel", + "futures-util", + "http 0.2.12", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock 3.0.1", + "solana-pubkey 3.0.0", + "solana-rpc-client-types", + "solana-signature 3.4.0", + "thiserror 2.0.18", + "tokio", + "tokio-stream", + "tokio-tungstenite", + "tungstenite", + "url", +] + +[[package]] +name = "solana-quic-client" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e071c7923f760d969ebc4f53bee815eadadb0edb54c5d188f8eeb31fc6daa09d" +dependencies = [ + "async-lock", + "async-trait", + "futures", + "itertools 0.12.1", + "log", + "quinn", + "quinn-proto", + "rustls 0.23.38", + "solana-connection-cache", + "solana-keypair 3.0.0", + "solana-measure 3.0.0", + "solana-metrics 3.0.0", + "solana-net-utils", + "solana-pubkey 3.0.0", + "solana-quic-definitions 3.0.0", + "solana-rpc-client-api", + "solana-signer 3.0.0", + "solana-streamer", + "solana-tls-utils", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-quic-definitions" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbf0d4d5b049eb1d0c35f7b18f305a27c8986fc5c0c9b383e97adaa35334379e" +dependencies = [ + "solana-keypair 2.2.3", +] + +[[package]] +name = "solana-quic-definitions" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15319accf7d3afd845817aeffa6edd8cc185f135cefbc6b985df29cfd8c09609" +dependencies = [ + "solana-keypair 3.0.0", +] + +[[package]] +name = "solana-rayon-threadlimit" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bc8990bf4b27b043302edbd27a9567c791931550c35bb7aa931459944ff61b7" +dependencies = [ + "log", + "num_cpus", +] + +[[package]] +name = "solana-rent" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1aea8fdea9de98ca6e8c2da5827707fb3842833521b528a713810ca685d2480" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-rent" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e860d5499a705369778647e97d760f7670adfb6fc8419dd3d568deccd46d5487" +dependencies = [ + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-rent" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9809b081e99bc142ce803bcd7ee18306759ce3b30a96a9da3f6f41c45e50ef0" +dependencies = [ + "solana-sdk-macro 3.0.1", +] + +[[package]] +name = "solana-rent-collector" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "127e6dfa51e8c8ae3aa646d8b2672bc4ac901972a338a9e1cd249e030564fb9d" +dependencies = [ + "serde", + "serde_derive", + "solana-account 2.2.1", + "solana-clock 2.2.3", + "solana-epoch-schedule 2.2.1", + "solana-genesis-config 2.3.0", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-rent-debits" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f6f9113c6003492e74438d1288e30cffa8ccfdc2ef7b49b9e816d8034da18cd" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-reward-info 2.2.1", +] + +[[package]] +name = "solana-reserved-account-keys" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4b22ea19ca2a3f28af7cd047c914abf833486bf7a7c4a10fc652fff09b385b1" +dependencies = [ + "lazy_static", + "solana-feature-set", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-reward-info" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18205b69139b1ae0ab8f6e11cdcb627328c0814422ad2482000fa2ca54ae4a2f" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-reward-info" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82be7946105c2ee6be9f9ee7bd18a068b558389221d29efa92b906476102bfcc" +dependencies = [ + "serde", + "serde_derive", +] + +[[package]] +name = "solana-rpc-client" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "133f94f08c31fedb64d0ba717d93d7911c4609f2cd641d73c165684e69cf8b4d" +dependencies = [ + "async-trait", + "base64 0.22.1", + "bincode", + "bs58", + "futures", + "indicatif", + "log", + "reqwest", + "reqwest-middleware", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account 3.4.0", + "solana-account-decoder-client-types", + "solana-clock 3.0.1", + "solana-commitment-config 3.1.1", + "solana-epoch-info 3.1.0", + "solana-epoch-schedule 3.1.0", + "solana-feature-gate-interface 3.1.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", + "solana-rpc-client-api", + "solana-signature 3.4.0", + "solana-transaction 3.1.0", + "solana-transaction-error 3.2.0", + "solana-transaction-status-client-types", + "solana-version", + "solana-vote-interface 3.0.0", + "tokio", +] + +[[package]] +name = "solana-rpc-client-api" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3dcab8bf22cdac34d26794d19909b056d9b1272d5e1ea92b4f83c49866d31142" +dependencies = [ + "anyhow", + "jsonrpc-core", + "reqwest", + "reqwest-middleware", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-clock 3.0.1", + "solana-rpc-client-types", + "solana-signer 3.0.0", + "solana-transaction-error 3.2.0", + "solana-transaction-status-client-types", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-rpc-client-nonce-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "839c807645b0a459d0d678a1aaf2bac93d2e7b29d56f13f53e4ebd6f570d72da" +dependencies = [ + "solana-account 3.4.0", + "solana-commitment-config 3.1.1", + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-nonce 3.2.0", + "solana-pubkey 3.0.0", + "solana-rpc-client", + "solana-sdk-ids 3.1.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-rpc-client-types" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68cd26ea7669573179babcf9117ab16c449718b52c8c405ac19631b564c048ea" +dependencies = [ + "base64 0.22.1", + "bs58", + "semver", + "serde", + "serde_derive", + "serde_json", + "solana-account 3.4.0", + "solana-account-decoder-client-types", + "solana-clock 3.0.1", + "solana-commitment-config 3.1.1", + "solana-fee-calculator 3.2.0", + "solana-inflation 3.1.0", + "solana-pubkey 3.0.0", + "solana-transaction-error 3.2.0", + "solana-transaction-status-client-types", + "solana-version", + "spl-generic-token", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-runtime" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c6d1d17a99abac0cfc3c3864a6ca37b56d15877de2a48286e3231b0ce8a2a92" +dependencies = [ + "agave-feature-set 3.0.0", + "agave-precompiles 3.0.0", + "agave-reserved-account-keys", + "agave-syscalls", + "ahash 0.8.12", + "aquamarine", + "arc-swap", + "arrayref", + "assert_matches", + "base64 0.22.1", + "bincode", + "blake3", + "bv", + "bytemuck", + "crossbeam-channel", + "dashmap", + "dir-diff", + "fnv", + "im", + "itertools 0.12.1", + "libc", + "log", + "lz4", + "memmap2 0.9.10", + "mockall", + "modular-bitfield", + "num-derive 0.4.2", + "num-traits", + "num_cpus", + "num_enum", + "percentage", + "qualifier_attr", + "rand 0.8.5", + "rayon", + "regex", + "serde", + "serde_derive", + "serde_json", + "serde_with", + "solana-account 3.4.0", + "solana-account-info 3.1.1", + "solana-accounts-db", + "solana-address-lookup-table-interface 3.1.0", + "solana-bpf-loader-program 3.0.0", + "solana-bucket-map", + "solana-builtins", + "solana-client-traits 3.0.0", + "solana-clock 3.0.1", + "solana-cluster-type 3.1.0", + "solana-commitment-config 3.1.1", + "solana-compute-budget 3.0.0", + "solana-compute-budget-instruction", + "solana-compute-budget-interface 3.0.0", + "solana-cost-model", + "solana-cpi 3.1.0", + "solana-ed25519-program 3.0.0", + "solana-epoch-info 3.1.0", + "solana-epoch-rewards-hasher 3.1.0", + "solana-epoch-schedule 3.1.0", + "solana-feature-gate-interface 3.1.0", + "solana-fee", + "solana-fee-calculator 3.2.0", + "solana-fee-structure 3.0.0", + "solana-genesis-config 3.0.0", + "solana-hard-forks 3.1.0", + "solana-hash 3.1.0", + "solana-inflation 3.1.0", + "solana-instruction 3.4.0", + "solana-keypair 3.0.0", + "solana-lattice-hash", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", + "solana-measure 3.0.0", + "solana-message 3.1.0", + "solana-metrics 3.0.0", + "solana-native-token 3.0.0", + "solana-nohash-hasher", + "solana-nonce 3.2.0", + "solana-nonce-account 3.0.0", + "solana-packet 3.0.0", + "solana-perf", + "solana-poh-config 3.0.0", + "solana-precompile-error 3.0.0", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-rayon-threadlimit", + "solana-rent 3.1.0", + "solana-reward-info 3.0.0", + "solana-runtime-transaction", + "solana-sdk-ids 3.1.0", + "solana-secp256k1-program 3.0.1", + "solana-seed-derivable 3.0.0", + "solana-serde 3.0.0", + "solana-sha256-hasher 3.1.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "solana-slot-hashes 3.0.1", + "solana-slot-history 3.0.0", + "solana-stake-interface 2.0.2", + "solana-stake-program", + "solana-svm", + "solana-svm-callback 3.0.0", + "solana-svm-timings", + "solana-svm-transaction", + "solana-system-interface 2.0.0", + "solana-system-transaction 3.0.0", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", + "solana-time-utils 3.0.0", + "solana-transaction 3.1.0", + "solana-transaction-context 3.0.0", + "solana-transaction-error 3.2.0", + "solana-transaction-status-client-types", + "solana-unified-scheduler-logic", + "solana-version", + "solana-vote", + "solana-vote-interface 3.0.0", + "solana-vote-program", + "spl-generic-token", + "static_assertions", + "strum 0.24.1", + "strum_macros 0.24.3", + "symlink", + "tar", + "tempfile", + "thiserror 2.0.18", + "zstd", +] + +[[package]] +name = "solana-runtime-transaction" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19cc056b9a5b400977c6bed9673a3a2349aa4eb2d0bfff6ce639513855ec4bea" +dependencies = [ + "agave-transaction-view", + "log", + "solana-compute-budget 3.0.0", + "solana-compute-budget-instruction", + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-signature 3.4.0", + "solana-svm-transaction", + "solana-transaction 3.1.0", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-sanitize" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "61f1bc1357b8188d9c4a3af3fc55276e56987265eb7ad073ae6f8180ee54cecf" + +[[package]] +name = "solana-sanitize" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dcf09694a0fc14e5ffb18f9b7b7c0f15ecb6eac5b5610bf76a1853459d19daf9" + +[[package]] +name = "solana-sbpf" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "474a2d95dc819898ded08d24f29642d02189d3e1497bbb442a92a3997b7eb55f" +dependencies = [ + "byteorder", + "combine 3.8.1", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "thiserror 2.0.18", + "winapi", +] + +[[package]] +name = "solana-sbpf" +version = "0.12.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f224d906c14efc7ed7f42bc5fe9588f3f09db8cabe7f6023adda62a69678e1a" +dependencies = [ + "byteorder", + "combine 3.8.1", + "hash32", + "libc", + "log", + "rand 0.8.5", + "rustc-demangle", + "thiserror 2.0.18", + "winapi", +] + +[[package]] +name = "solana-sdk" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8cc0e4a7635b902791c44b6581bfb82f3ada32c5bc0929a64f39fe4bb384c86a" +dependencies = [ + "bincode", + "bs58", + "getrandom 0.1.16", + "js-sys", + "serde", + "serde_json", + "solana-account 2.2.1", + "solana-bn254 2.2.2", + "solana-client-traits 2.2.1", + "solana-cluster-type 2.2.1", + "solana-commitment-config 2.2.1", + "solana-compute-budget-interface 2.2.2", + "solana-decode-error", + "solana-derivation-path 2.2.1", + "solana-ed25519-program 2.2.3", + "solana-epoch-info 2.2.1", + "solana-epoch-rewards-hasher 2.2.1", + "solana-feature-set", + "solana-fee-structure 2.3.0", + "solana-genesis-config 2.3.0", + "solana-hard-forks 2.2.1", + "solana-inflation 2.2.1", + "solana-instruction 2.3.3", + "solana-keypair 2.2.3", + "solana-message 2.4.0", + "solana-native-token 2.3.0", + "solana-nonce-account 2.2.1", + "solana-offchain-message 2.2.1", + "solana-packet 2.2.1", + "solana-poh-config 2.2.1", + "solana-precompile-error 2.2.2", + "solana-precompiles", + "solana-presigner 2.2.1", + "solana-program 2.3.0", + "solana-program-memory 2.3.1", + "solana-pubkey 2.4.0", + "solana-quic-definitions 2.3.1", + "solana-rent-collector", + "solana-rent-debits", + "solana-reserved-account-keys", + "solana-reward-info 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-secp256k1-program 2.2.3", + "solana-secp256k1-recover 2.2.1", + "solana-secp256r1-program 2.2.4", + "solana-seed-derivable 2.2.1", + "solana-seed-phrase 2.2.1", + "solana-serde 2.2.1", + "solana-serde-varint 2.2.2", + "solana-short-vec 2.2.1", + "solana-shred-version 2.2.1", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-system-transaction 2.2.1", + "solana-time-utils 2.2.1", + "solana-transaction 2.2.3", + "solana-transaction-context 2.3.13", + "solana-transaction-error 2.2.1", + "solana-validator-exit", + "thiserror 2.0.18", + "wasm-bindgen", +] + +[[package]] +name = "solana-sdk" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f03df7969f5e723ad31b6c9eadccc209037ac4caa34d8dc259316b05c11e82b" +dependencies = [ + "bincode", + "bs58", + "serde", + "solana-account 3.4.0", + "solana-epoch-info 3.1.0", + "solana-epoch-rewards-hasher 3.1.0", + "solana-fee-structure 3.0.0", + "solana-inflation 3.1.0", + "solana-keypair 3.0.0", + "solana-message 3.1.0", + "solana-offchain-message 3.0.0", + "solana-presigner 3.0.0", + "solana-program 3.0.0", + "solana-program-memory 3.1.0", + "solana-pubkey 3.0.0", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-seed-derivable 3.0.0", + "solana-seed-phrase 3.0.0", + "solana-serde 3.0.0", + "solana-serde-varint 3.0.1", + "solana-short-vec 3.2.0", + "solana-shred-version 3.0.1", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "solana-time-utils 3.0.0", + "solana-transaction 3.1.0", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-sdk-ids" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c5d8b9cc68d5c88b062a33e23a6466722467dde0035152d8fb1afbcdf350a5f" +dependencies = [ + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-sdk-ids" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "def234c1956ff616d46c9dd953f251fa7096ddbaa6d52b165218de97882b7280" +dependencies = [ + "solana-address 2.6.0", +] + +[[package]] +name = "solana-sdk-macro" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86280da8b99d03560f6ab5aca9de2e38805681df34e0bb8f238e69b29433b9df" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "solana-sdk-macro" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8765316242300c48242d84a41614cb3388229ec353ba464f6fe62a733e41806f" +dependencies = [ + "bs58", + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "solana-secp256k1-program" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f19833e4bc21558fe9ec61f239553abe7d05224347b57d65c2218aeeb82d6149" +dependencies = [ + "bincode", + "digest 0.10.7", + "libsecp256k1", + "serde", + "serde_derive", + "sha3", + "solana-feature-set", + "solana-instruction 2.3.3", + "solana-precompile-error 2.2.2", + "solana-sdk-ids 2.2.1", + "solana-signature 2.3.0", +] + +[[package]] +name = "solana-secp256k1-program" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ad4cf8232f7aef9ff2dd95d701f63e3c11909dec2400def5c361be29d24291e7" +dependencies = [ + "digest 0.10.7", + "k256", + "serde", + "serde_derive", + "sha3", + "solana-signature 3.4.0", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baa3120b6cdaa270f39444f5093a90a7b03d296d362878f7a6991d6de3bbe496" +dependencies = [ + "borsh 1.6.1", + "libsecp256k1", + "solana-define-syscall 2.3.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-secp256k1-recover" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7c5f18893d62e6c73117dcba48f8f5e3266d90e5ec3d0a0a90f9785adac36c1" +dependencies = [ + "k256", + "solana-define-syscall 5.1.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-secp256r1-program" +version = "2.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0ae46da3071a900f02d367d99b2f3058fe2e90c5062ac50c4f20cfedad8f0f" +dependencies = [ + "bytemuck", + "openssl", + "solana-feature-set", + "solana-instruction 2.3.3", + "solana-precompile-error 2.2.2", + "solana-sdk-ids 2.2.1", +] + +[[package]] +name = "solana-secp256r1-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "445d8e12592631d76fc4dc57858bae66c9fd7cc838c306c62a472547fc9d0ce6" +dependencies = [ + "bytemuck", + "openssl", + "solana-instruction 3.4.0", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-security-txt" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "156bb61a96c605fa124e052d630dba2f6fb57e08c7d15b757e1e958b3ed7b3fe" +dependencies = [ + "hashbrown 0.15.2", +] + +[[package]] +name = "solana-seed-derivable" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3beb82b5adb266c6ea90e5cf3967235644848eac476c5a1f2f9283a143b7c97f" +dependencies = [ + "solana-derivation-path 2.2.1", +] + +[[package]] +name = "solana-seed-derivable" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff7bdb72758e3bec33ed0e2658a920f1f35dfb9ed576b951d20d63cb61ecd95c" +dependencies = [ + "solana-derivation-path 3.0.0", +] + +[[package]] +name = "solana-seed-phrase" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36187af2324f079f65a675ec22b31c24919cb4ac22c79472e85d819db9bbbc15" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-seed-phrase" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc905b200a95f2ea9146e43f2a7181e3aeb55de6bc12afb36462d00a3c7310de" +dependencies = [ + "hmac 0.12.1", + "pbkdf2", + "sha2 0.10.9", +] + +[[package]] +name = "solana-send-transaction-service" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7875be65688d51eb973ed8321ee7582bc572505103f357876d1f199a290660c5" +dependencies = [ + "async-trait", + "crossbeam-channel", + "itertools 0.12.1", + "log", + "solana-client", + "solana-clock 3.0.1", + "solana-connection-cache", + "solana-hash 3.1.0", + "solana-keypair 3.0.0", + "solana-measure 3.0.0", + "solana-metrics 3.0.0", + "solana-nonce-account 3.0.0", + "solana-pubkey 3.0.0", + "solana-quic-definitions 3.0.0", + "solana-runtime", + "solana-signature 3.4.0", + "solana-time-utils 3.0.0", + "solana-tpu-client-next", + "tokio", + "tokio-util 0.7.18", +] + +[[package]] +name = "solana-serde" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1931484a408af466e14171556a47adaa215953c7f48b24e5f6b0282763818b04" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709a93cab694c70f40b279d497639788fc2ccbcf9b4aa32273d4b361322c02dd" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "2.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a7e155eba458ecfb0107b98236088c3764a09ddf0201ec29e52a0be40857113" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serde-varint" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "950e5b83e839dc0f92c66afc124bb8f40e89bc90f0579e8ec5499296d27f54e3" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-serialize-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "817a284b63197d2b27afdba829c5ab34231da4a9b4e763466a003c40ca4f535e" +dependencies = [ + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-serialize-utils" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d7cc401931d178472358e6b78dc72d031dc08f752d7410f0e8bd259dd6f02fa" +dependencies = [ + "solana-instruction-error", + "solana-pubkey 4.2.0", + "solana-sanitize 3.0.1", +] + +[[package]] +name = "solana-sha256-hasher" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5aa3feb32c28765f6aa1ce8f3feac30936f16c5c3f7eb73d63a5b8f6f8ecdc44" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall 2.3.0", + "solana-hash 2.3.0", +] + +[[package]] +name = "solana-sha256-hasher" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db7dc3011ea4c0334aaaa7e7128cb390ecf546b28d412e9bf2064680f57f588f" +dependencies = [ + "sha2 0.10.9", + "solana-define-syscall 4.0.1", + "solana-hash 4.3.0", +] + +[[package]] +name = "solana-short-vec" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c54c66f19b9766a56fa0057d060de8378676cb64987533fa088861858fc5a69" +dependencies = [ + "serde", +] + +[[package]] +name = "solana-short-vec" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de3bd991c2cc415291c86bb0b6b4d53e93d13bb40344e4c5a2884e0e4f5fa93f" +dependencies = [ + "serde_core", +] + +[[package]] +name = "solana-shred-version" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "afd3db0461089d1ad1a78d9ba3f15b563899ca2386351d38428faa5350c60a98" +dependencies = [ + "solana-hard-forks 2.2.1", + "solana-hash 2.3.0", + "solana-sha256-hasher 2.3.0", +] + +[[package]] +name = "solana-shred-version" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6c79722e299d957958bf33695f7cd1ef6724ff55563c60fd9e3e24487cccde2" +dependencies = [ + "solana-hard-forks 3.1.0", + "solana-hash 4.3.0", + "solana-sha256-hasher 3.1.0", +] + +[[package]] +name = "solana-signature" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64c8ec8e657aecfc187522fc67495142c12f35e55ddeca8698edbb738b8dbd8c" +dependencies = [ + "ed25519-dalek 1.0.1", + "five8 0.2.1", + "rand 0.8.5", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize 2.2.1", +] + +[[package]] +name = "solana-signature" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e7a73c6e97cc2108be0adf6a6ea326434f8398df9d7eed81da2a4548b69e971c" +dependencies = [ + "ed25519-dalek 2.2.0", + "five8 1.0.0", + "rand 0.9.4", + "serde", + "serde-big-array", + "serde_derive", + "solana-sanitize 3.0.1", + "wincode", +] + +[[package]] +name = "solana-signer" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c41991508a4b02f021c1342ba00bcfa098630b213726ceadc7cb032e051975b" +dependencies = [ + "solana-pubkey 2.4.0", + "solana-signature 2.3.0", + "solana-transaction-error 2.2.1", +] + +[[package]] +name = "solana-signer" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bfea97951fee8bae0d6038f39a5efcb6230ecdfe33425ac75196d1a1e3e3235" +dependencies = [ + "solana-pubkey 3.0.0", + "solana-signature 3.4.0", + "solana-transaction-error 3.2.0", +] + +[[package]] +name = "solana-slot-hashes" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c8691982114513763e88d04094c9caa0376b867a29577939011331134c301ce" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 2.3.0", + "solana-sdk-ids 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-slot-hashes" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2585f70191623887329dfb5078da3a00e15e3980ea67f42c2e10b07028419f43" +dependencies = [ + "serde", + "serde_derive", + "solana-hash 4.3.0", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-slot-history" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97ccc1b2067ca22754d5283afb2b0126d61eae734fc616d23871b0943b0d935e" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids 2.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-slot-history" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f914f6b108f5bba14a280b458d023e3621c9973f27f015a4d755b50e88d89e97" +dependencies = [ + "bv", + "serde", + "serde_derive", + "solana-sdk-ids 3.1.0", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-stable-layout" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f14f7d02af8f2bc1b5efeeae71bc1c2b7f0f65cd75bcc7d8180f2c762a57f54" +dependencies = [ + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-stable-layout" +version = "3.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9f6a291ba063a37780af29e7db14bdd3dc447584d8ba5b3fc4b88e2bbc982fa" +dependencies = [ + "solana-instruction 3.4.0", + "solana-pubkey 4.2.0", +] + +[[package]] +name = "solana-stake-interface" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5269e89fde216b4d7e1d1739cf5303f8398a1ff372a81232abbee80e554a838c" +dependencies = [ + "borsh 0.10.4", + "borsh 1.6.1", + "num-traits", + "serde", + "serde_derive", + "solana-clock 2.2.3", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", + "solana-system-interface 1.0.0", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-stake-interface" +version = "2.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9bc26191b533f9a6e5a14cca05174119819ced680a80febff2f5051a713f0db" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-clock 3.0.1", + "solana-cpi 3.1.0", + "solana-instruction 3.4.0", + "solana-program-error 3.0.0", + "solana-pubkey 3.0.0", + "solana-system-interface 2.0.0", + "solana-sysvar 3.1.1", + "solana-sysvar-id 3.1.0", +] + +[[package]] +name = "solana-stake-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "daf74c671ab8f7bf2c1f4de9d1a1b9f71e3f3cb7acadd3e055c0196ac962b470" +dependencies = [ + "agave-feature-set 3.0.0", + "bincode", + "log", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-clock 3.0.1", + "solana-config-interface", + "solana-genesis-config 3.0.0", + "solana-instruction 3.4.0", + "solana-native-token 3.0.0", + "solana-packet 3.0.0", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sdk-ids 3.1.0", + "solana-stake-interface 2.0.2", + "solana-svm-log-collector", + "solana-svm-type-overrides", + "solana-sysvar 3.1.1", + "solana-transaction-context 3.0.0", + "solana-vote-interface 3.0.0", +] + +[[package]] +name = "solana-streamer" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9289c72c912c0bf09a45ffb7c98c6f1e705c45206de987a78fb38bae2b252902" +dependencies = [ + "arc-swap", + "async-channel", + "bytes", + "crossbeam-channel", + "dashmap", + "futures", + "futures-util", + "governor", + "histogram", + "indexmap 2.14.0", + "itertools 0.12.1", + "libc", "log", - "solana-measure", - "solana-program-runtime", - "solana-sdk", - "solana_rbpf", + "nix", + "num_cpus", + "pem", + "percentage", + "quinn", + "quinn-proto", + "rand 0.8.5", + "rustls 0.23.38", + "smallvec", + "socket2", + "solana-keypair 3.0.0", + "solana-measure 3.0.0", + "solana-metrics 3.0.0", + "solana-net-utils", + "solana-packet 3.0.0", + "solana-perf", + "solana-pubkey 3.0.0", + "solana-quic-definitions 3.0.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "solana-time-utils 3.0.0", + "solana-tls-utils", + "solana-transaction-error 3.2.0", + "solana-transaction-metrics-tracker", + "thiserror 2.0.18", + "tokio", + "tokio-util 0.7.18", + "x509-parser", ] [[package]] -name = "solana-logger" -version = "1.17.14" +name = "solana-svm" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d37a1b1a383a01039afbc6447a1712fb2a1a73a5ba8916762e693e8e492fabf3" +checksum = "1fc08ac749d993423409ddb34b10c4b772fff899cbe618936c3f1ce4bb08510a" dependencies = [ - "env_logger", - "lazy_static", + "ahash 0.8.12", "log", + "percentage", + "serde", + "serde_derive", + "solana-account 3.4.0", + "solana-clock 3.0.1", + "solana-fee-structure 3.0.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-instructions-sysvar 3.0.0", + "solana-loader-v3-interface 6.1.1", + "solana-loader-v4-interface 3.1.0", + "solana-loader-v4-program", + "solana-message 3.1.0", + "solana-nonce 3.2.0", + "solana-nonce-account 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-pack 3.1.0", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sdk-ids 3.1.0", + "solana-svm-callback 3.0.0", + "solana-svm-feature-set 3.0.0", + "solana-svm-log-collector", + "solana-svm-measure", + "solana-svm-timings", + "solana-svm-transaction", + "solana-svm-type-overrides", + "solana-system-interface 2.0.0", + "solana-sysvar-id 3.1.0", + "solana-transaction-context 3.0.0", + "solana-transaction-error 3.2.0", + "spl-generic-token", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-svm-callback" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7cef9f7d5cfb5d375081a6c8ad712a6f0e055a15890081f845acf55d8254a7a2" +dependencies = [ + "solana-account 2.2.1", + "solana-precompile-error 2.2.2", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-svm-callback" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "850b0f7f6397551fbdd0ca55cf1fec6d2943a4e7b1ace7ae2cc4773ccbf4a854" +dependencies = [ + "solana-account 3.4.0", + "solana-clock 3.0.1", + "solana-precompile-error 3.0.0", + "solana-pubkey 3.0.0", ] [[package]] -name = "solana-measure" -version = "1.17.14" +name = "solana-svm-feature-set" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f24b836eb4d74ec255217bdbe0f24f64a07adeac31aca61f334f91cd4a3b1d5" + +[[package]] +name = "solana-svm-feature-set" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddf9eb327b0d8a9ee79d6a2d4fbbabee76473cc6f1c862bb1ec8b1e0cb9c1307" + +[[package]] +name = "solana-svm-log-collector" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19831a93d760205f5c3e20d05a37b0e533caa1889e48041648ad0859e68ec336" +checksum = "653640ff91ff2724219e8ec3c599663307d1ece7ff699ffc0342503d09f4bb9f" dependencies = [ "log", - "solana-sdk", ] [[package]] -name = "solana-metrics" -version = "1.17.14" +name = "solana-svm-measure" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a7602d9a00074a418c8dae0024e4e213b68f44fb7e7aca3cc65bc99cb9145bd8" + +[[package]] +name = "solana-svm-metrics" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f63c23a8db755b2903262ad473e32cbf0093e2d3a0a7b8183d797a182c08326a" +checksum = "43f5361758f7f46a12386741f44a2a36027e5b9e697e503eeeabb5be41ab321c" dependencies = [ "crossbeam-channel", "gethostname", - "lazy_static", "log", "reqwest", - "solana-sdk", - "thiserror", + "solana-cluster-type 3.1.0", + "solana-sha256-hasher 3.1.0", + "solana-time-utils 3.0.0", + "thiserror 2.0.18", ] [[package]] -name = "solana-net-utils" -version = "1.17.14" +name = "solana-svm-timings" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "29ac1afc7feb590b45fd72bee0ca4c4f24b2386184d7e00d9f0d17913655bb4a" +checksum = "a055b583748c41721d1ef87c6da051522da139afa6b5881aa9d04632466adb13" dependencies = [ - "bincode", - "clap 3.2.25", - "crossbeam-channel", - "log", - "nix", - "rand 0.8.5", - "serde", - "serde_derive", - "socket2", - "solana-logger", - "solana-sdk", - "solana-version", - "tokio", - "url", + "eager", + "enum-iterator", + "solana-pubkey 3.0.0", ] [[package]] -name = "solana-perf" -version = "1.17.14" +name = "solana-svm-transaction" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfdf5a429e018e8ba693f4c43f833192db421fe97b88dfaf97041aa258e4b191" +checksum = "c8bb3c2b194607512925e834bce30e060e179634a5c70a5971e868a754c7c31a" +dependencies = [ + "solana-hash 3.1.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-signature 3.4.0", + "solana-transaction 3.1.0", +] + +[[package]] +name = "solana-svm-type-overrides" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe7a6aa721d9596fe33ddf907da38713d10fc2773b17794f3654159e1646b770" dependencies = [ - "ahash 0.8.6", - "bincode", - "bv", - "caps", - "curve25519-dalek", - "dlopen2", - "fnv", - "lazy_static", - "libc", - "log", - "nix", "rand 0.8.5", - "rayon", - "rustc_version", - "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-metrics", - "solana-rayon-threadlimit", - "solana-sdk", - "solana-vote-program", ] [[package]] -name = "solana-program" -version = "1.17.14" +name = "solana-system-interface" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e3a3b9623f09e2c480b4e129c92d7a036f8614fd0fc7519791bd44e64061ce8" +checksum = "94d7c18cb1a91c6be5f5a8ac9276a1d7c737e39a21beba9ea710ab4b9c63bc90" 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", - "bs58 0.4.0", - "bv", - "bytemuck", - "cc", - "console_error_panic_hook", - "console_log", - "curve25519-dalek", - "getrandom 0.2.12", - "itertools", "js-sys", - "lazy_static", - "libc", - "libsecp256k1", - "light-poseidon", - "log", - "memoffset 0.9.0", - "num-bigint 0.4.4", - "num-derive 0.3.3", "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", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", "wasm-bindgen", - "zeroize", ] [[package]] -name = "solana-program-runtime" -version = "1.17.14" +name = "solana-system-interface" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5dbb56d36cc15b4cf5a71c0ce6262a263212f7a312b0dbc41b226654329c37" +checksum = "4e1790547bfc3061f1ee68ea9d8dc6c973c02a163697b24263a8e9f2e6d4afa2" dependencies = [ - "base64 0.21.7", - "bincode", - "eager", - "enum-iterator", - "itertools", - "libc", - "log", - "num-derive 0.3.3", "num-traits", - "percentage", - "rand 0.8.5", - "rustc_version", "serde", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-measure", - "solana-metrics", - "solana-sdk", - "solana_rbpf", - "thiserror", + "serde_derive", + "solana-instruction 3.4.0", + "solana-msg 3.1.0", + "solana-program-error 3.0.0", + "solana-pubkey 3.0.0", ] [[package]] -name = "solana-program-test" -version = "1.17.14" +name = "solana-system-interface" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "61bbf119c35d4393702953e586b72053c3b80a92c781931cd412d53d2036475e" +checksum = "55b54965bf0b76fa8e2b35376583efddd4d916618cfe595bf48c7d7b55a9e628" +dependencies = [ + "num-traits", + "serde", + "serde_derive", + "solana-address 2.6.0", + "solana-instruction 3.4.0", + "solana-msg 3.1.0", + "solana-program-error 3.0.0", +] + +[[package]] +name = "solana-system-program" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23ca36cef39aea7761be58d4108a56a2e27042fb1e913355fdb142a05fc7eab7" dependencies = [ - "assert_matches", - "async-trait", - "base64 0.21.7", "bincode", - "chrono-humanize", - "crossbeam-channel", "log", "serde", - "solana-accounts-db", - "solana-banks-client", - "solana-banks-interface", - "solana-banks-server", - "solana-bpf-loader-program", - "solana-logger", - "solana-program-runtime", - "solana-runtime", - "solana-sdk", - "solana-vote-program", - "solana_rbpf", - "test-case", - "thiserror", - "tokio", + "serde_derive", + "solana-account 2.2.1", + "solana-bincode 2.2.1", + "solana-fee-calculator 2.2.1", + "solana-instruction 2.3.3", + "solana-log-collector", + "solana-nonce 2.2.1", + "solana-nonce-account 2.2.1", + "solana-packet 2.2.1", + "solana-program-runtime 2.3.13", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-system-interface 1.0.0", + "solana-sysvar 2.3.0", + "solana-transaction-context 2.3.13", + "solana-type-overrides", ] [[package]] -name = "solana-pubsub-client" -version = "1.17.14" +name = "solana-system-program" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c22290c0d296a6a250a8d5b680797f12138a81af9c403a6ce62bd3ddad307e6" +checksum = "ed56fee950fd98d7e5187d3d51e4a630c156aafc4fa0527090635bb33d08f9ff" dependencies = [ - "crossbeam-channel", - "futures-util", + "bincode", "log", - "reqwest", - "semver", "serde", "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-rpc-client-api", - "solana-sdk", - "thiserror", - "tokio", - "tokio-stream", - "tokio-tungstenite", - "tungstenite", - "url", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-fee-calculator 3.2.0", + "solana-instruction 3.4.0", + "solana-nonce 3.2.0", + "solana-nonce-account 3.0.0", + "solana-packet 3.0.0", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-svm-log-collector", + "solana-svm-type-overrides", + "solana-system-interface 2.0.0", + "solana-sysvar 3.1.1", + "solana-transaction-context 3.0.0", ] [[package]] -name = "solana-quic-client" -version = "1.17.14" +name = "solana-system-transaction" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f924d8722f9e910d790678a79c2a0bfed786dffe1aefa5d769f8548679794263" +checksum = "5bd98a25e5bcba8b6be8bcbb7b84b24c2a6a8178d7fb0e3077a916855ceba91a" dependencies = [ - "async-mutex", - "async-trait", - "futures", - "itertools", - "lazy_static", - "log", - "quinn", - "quinn-proto", - "rcgen", - "rustls", - "solana-connection-cache", - "solana-measure", - "solana-metrics", - "solana-net-utils", - "solana-rpc-client-api", - "solana-sdk", - "solana-streamer", - "thiserror", - "tokio", + "solana-hash 2.3.0", + "solana-keypair 2.2.3", + "solana-message 2.4.0", + "solana-pubkey 2.4.0", + "solana-signer 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction 2.2.3", ] [[package]] -name = "solana-rayon-threadlimit" -version = "1.17.14" +name = "solana-system-transaction" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a31b5699ec533621515e714f1533ee6b3b0e71c463301d919eb59b8c1e249d30" +dependencies = [ + "solana-hash 3.1.0", + "solana-keypair 3.0.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", + "solana-signer 3.0.0", + "solana-system-interface 2.0.0", + "solana-transaction 3.1.0", +] + +[[package]] +name = "solana-sysvar" +version = "2.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bc0a2e484e5b272690ac1431a6821f2b5180149d67c56934d9e007224ced15d0" +checksum = "b8c3595f95069f3d90f275bb9bd235a1973c4d059028b0a7f81baca2703815db" dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", "lazy_static", - "num_cpus", + "serde", + "serde_derive", + "solana-account-info 2.3.0", + "solana-clock 2.2.3", + "solana-define-syscall 2.3.0", + "solana-epoch-rewards 2.2.1", + "solana-epoch-schedule 2.2.1", + "solana-fee-calculator 2.2.1", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-last-restart-slot 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-program-memory 2.3.1", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-sdk-macro 2.2.1", + "solana-slot-hashes 2.2.1", + "solana-slot-history 2.2.1", + "solana-stake-interface 1.2.1", + "solana-sysvar-id 2.2.1", +] + +[[package]] +name = "solana-sysvar" +version = "3.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6690d3dd88f15c21edff68eb391ef8800df7a1f5cec84ee3e8d1abf05affdf74" +dependencies = [ + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "lazy_static", + "serde", + "serde_derive", + "solana-account-info 3.1.1", + "solana-clock 3.0.1", + "solana-define-syscall 4.0.1", + "solana-epoch-rewards 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-fee-calculator 3.2.0", + "solana-hash 4.3.0", + "solana-instruction 3.4.0", + "solana-last-restart-slot 3.0.0", + "solana-program-entrypoint 3.1.1", + "solana-program-error 3.0.0", + "solana-program-memory 3.1.0", + "solana-pubkey 4.2.0", + "solana-rent 3.1.0", + "solana-sdk-ids 3.1.0", + "solana-sdk-macro 3.0.1", + "solana-slot-hashes 3.0.1", + "solana-slot-history 3.0.0", + "solana-sysvar-id 3.1.0", ] [[package]] -name = "solana-remote-wallet" -version = "1.17.14" +name = "solana-sysvar-id" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fb9a96d1c001d07a0abb08e05b92ff6528b2d9239d03c57f99f738527839eb12" +checksum = "5762b273d3325b047cfda250787f8d796d781746860d5d0a746ee29f3e8812c1" dependencies = [ - "console", - "dialoguer", - "log", - "num-derive 0.3.3", - "num-traits", - "parking_lot", - "qstring", - "semver", - "solana-sdk", - "thiserror", - "uriparse", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", ] [[package]] -name = "solana-rpc-client" -version = "1.17.14" +name = "solana-sysvar-id" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "17358d1e9a13e5b9c2264d301102126cf11a47fd394cdf3dec174fe7bc96e1de" +dependencies = [ + "solana-address 2.6.0", + "solana-sdk-ids 3.1.0", +] + +[[package]] +name = "solana-time-utils" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6af261afb0e8c39252a04d026e3ea9c405342b08c871a2ad8aa5448e068c784c" + +[[package]] +name = "solana-time-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced92c60aa76ec4780a9d93f3bd64dfa916e1b998eacc6f1c110f3f444f02c9" + +[[package]] +name = "solana-timings" +version = "2.3.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c49b842dfc53c1bf9007eaa6730296dea93b4fce73f457ce1080af43375c0d6" +dependencies = [ + "eager", + "enum-iterator", + "solana-pubkey 2.4.0", +] + +[[package]] +name = "solana-tls-utils" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fe9502bc842b5781269a4812c9e8a2967ad90ab14d444f1d98dec81ebef7e6ef" +dependencies = [ + "rustls 0.23.38", + "solana-keypair 3.0.0", + "solana-pubkey 3.0.0", + "solana-signer 3.0.0", + "x509-parser", +] + +[[package]] +name = "solana-tpu-client" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "91503edfdb2ba9c5e0127048e7795f22e050cf2bcee1259361af113d533b4b26" +checksum = "06caabd1fbf5bd23e47f9334b48198529a002846ed85dc873e3ce2dcf2fb7e51" dependencies = [ "async-trait", - "base64 0.21.7", "bincode", - "bs58 0.4.0", + "futures-util", + "indexmap 2.14.0", "indicatif", "log", - "reqwest", - "semver", - "serde", - "serde_derive", - "serde_json", - "solana-account-decoder", + "rayon", + "solana-client-traits 3.0.0", + "solana-clock 3.0.1", + "solana-commitment-config 3.1.1", + "solana-connection-cache", + "solana-epoch-schedule 3.1.0", + "solana-measure 3.0.0", + "solana-message 3.1.0", + "solana-net-utils", + "solana-pubkey 3.0.0", + "solana-pubsub-client", + "solana-quic-definitions 3.0.0", + "solana-rpc-client", "solana-rpc-client-api", - "solana-sdk", - "solana-transaction-status", - "solana-version", - "solana-vote-program", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "solana-transaction 3.1.0", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", + "tokio", +] + +[[package]] +name = "solana-tpu-client-next" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "288307b1388ccb33d3e95695b75f3188b9afd5a6aab390be548e380679d35958" +dependencies = [ + "async-trait", + "log", + "lru", + "quinn", + "rustls 0.23.38", + "solana-clock 3.0.1", + "solana-connection-cache", + "solana-keypair 3.0.0", + "solana-measure 3.0.0", + "solana-metrics 3.0.0", + "solana-quic-definitions 3.0.0", + "solana-rpc-client", + "solana-streamer", + "solana-time-utils 3.0.0", + "solana-tls-utils", + "solana-tpu-client", + "thiserror 2.0.18", "tokio", + "tokio-util 0.7.18", ] [[package]] -name = "solana-rpc-client-api" -version = "1.17.14" +name = "solana-transaction" +version = "2.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "131662e5eea4fa5fc88b01f07d9e430315c0976be848ba3994244249c5fb033a" +checksum = "80657d6088f721148f5d889c828ca60c7daeedac9a8679f9ec215e0c42bcbf41" dependencies = [ - "base64 0.21.7", - "bs58 0.4.0", - "jsonrpc-core", - "reqwest", - "semver", + "bincode", "serde", "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-sdk", - "solana-transaction-status", - "solana-version", - "spl-token-2022 1.0.0", - "thiserror", + "solana-bincode 2.2.1", + "solana-feature-set", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-keypair 2.2.3", + "solana-message 2.4.0", + "solana-precompiles", + "solana-pubkey 2.4.0", + "solana-sanitize 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-short-vec 2.2.1", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "solana-system-interface 1.0.0", + "solana-transaction-error 2.2.1", + "wasm-bindgen", ] [[package]] -name = "solana-rpc-client-nonce-utils" -version = "1.17.14" +name = "solana-transaction" +version = "3.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f67cdff955b9994ae240f6f287420c6727a581120c02ccc4f2fa535886732a1d" +checksum = "96697cff5075a028265324255efed226099f6d761ca67342b230d09f72cc48d2" dependencies = [ - "clap 2.34.0", - "solana-clap-utils", - "solana-rpc-client", - "solana-sdk", - "thiserror", + "bincode", + "serde", + "serde_derive", + "solana-address 2.6.0", + "solana-hash 4.3.0", + "solana-instruction 3.4.0", + "solana-instruction-error", + "solana-message 3.1.0", + "solana-sanitize 3.0.1", + "solana-sdk-ids 3.1.0", + "solana-short-vec 3.2.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "solana-transaction-error 3.2.0", ] [[package]] -name = "solana-runtime" -version = "1.17.14" +name = "solana-transaction-context" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cf63159e669f29065c9ff280c09f5b96139b00258502ee401338150fce78fed7" +checksum = "54a312304361987a85b2ef2293920558e6612876a639dd1309daf6d0d59ef2fe" dependencies = [ - "arrayref", - "base64 0.21.7", "bincode", - "blake3", - "bv", - "bytemuck", - "byteorder", - "bzip2", - "crossbeam-channel", - "dashmap", - "dir-diff", - "flate2", - "fnv", - "fs-err", - "im", - "index_list", - "itertools", - "lazy_static", - "log", - "lru", - "lz4", - "memmap2", - "modular-bitfield", - "num-derive 0.3.3", - "num-traits", - "num_cpus", - "num_enum 0.6.1", - "ouroboros", - "percentage", - "qualifier_attr", - "rand 0.8.5", - "rayon", - "regex", - "rustc_version", "serde", "serde_derive", - "serde_json", - "siphasher", - "solana-accounts-db", - "solana-address-lookup-table-program", - "solana-bpf-loader-program", - "solana-bucket-map", - "solana-compute-budget-program", - "solana-config-program", - "solana-cost-model", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-loader-v4-program", - "solana-measure", - "solana-metrics", - "solana-perf", - "solana-program-runtime", - "solana-rayon-threadlimit", - "solana-sdk", - "solana-stake-program", - "solana-system-program", - "solana-version", - "solana-vote", - "solana-vote-program", - "solana-zk-token-proof-program", - "solana-zk-token-sdk", - "static_assertions", - "strum 0.24.1", - "strum_macros 0.24.3", - "symlink", - "tar", - "tempfile", - "thiserror", - "zstd", + "solana-account 2.2.1", + "solana-instruction 2.3.3", + "solana-instructions-sysvar 2.2.2", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", ] [[package]] -name = "solana-sdk" -version = "1.17.14" +name = "solana-transaction-context" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb34583922c5e79004ad8d8d69f333d274d21b614f0e1a575f325fc29a104ec2" +checksum = "0de80299b069929cfd14aabc606605867810dc4c1a57fb488a8c84a1273e545d" dependencies = [ - "assert_matches", - "base64 0.21.7", "bincode", - "bitflags 2.5.0", - "borsh 0.10.3", - "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 0.3.3", - "num-traits", - "num_enum 0.6.1", - "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 2.3.3", - "sha2 0.10.8", - "sha3 0.10.8", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-logger", - "solana-program", - "solana-sdk-macro", - "thiserror", - "uriparse", - "wasm-bindgen", + "solana-account 3.4.0", + "solana-instruction 3.4.0", + "solana-instructions-sysvar 3.0.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sbpf 0.12.2", + "solana-sdk-ids 3.1.0", ] [[package]] -name = "solana-sdk-macro" -version = "1.17.14" +name = "solana-transaction-error" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "60f58786e949f43b8c9b826fdfa5ad8586634b077ab04f989fb8e30535786712" +checksum = "222a9dc8fdb61c6088baab34fc3a8b8473a03a7a5fd404ed8dd502fa79b67cb1" dependencies = [ - "bs58 0.4.0", - "proc-macro2", - "quote", - "rustversion", - "syn 2.0.48", + "serde", + "serde_derive", + "solana-instruction 2.3.3", + "solana-sanitize 2.2.1", ] [[package]] -name = "solana-security-txt" -version = "1.1.1" +name = "solana-transaction-error" +version = "3.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "468aa43b7edb1f9b7b7b686d5c3aeb6630dc1708e86e31343499dd5c4d775183" +checksum = "4a2165ad25b694c654d5395fc7a049452a192376e4c96a7fad05580f6ba5ba1c" +dependencies = [ + "serde", + "serde_derive", + "solana-instruction-error", + "solana-sanitize 3.0.1", +] [[package]] -name = "solana-send-transaction-service" -version = "1.17.14" +name = "solana-transaction-metrics-tracker" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9987eccfe96b38785d95840277da4238de4f01166d0c32ec9bbfc5a319f4a530" +checksum = "c953121ddde6c2371fcc0c4983ff76ddcb151d0a5fbe9e19358a4c6657568b44" dependencies = [ - "crossbeam-channel", + "base64 0.22.1", + "bincode", "log", - "solana-client", - "solana-measure", - "solana-metrics", - "solana-runtime", - "solana-sdk", - "solana-tpu-client", + "rand 0.8.5", + "solana-packet 3.0.0", + "solana-perf", + "solana-short-vec 3.2.0", + "solana-signature 3.4.0", ] [[package]] -name = "solana-stake-program" -version = "1.17.14" +name = "solana-transaction-status-client-types" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ab247c866dab350bf610df8e1fab97ae0a0519cb81914348d382eac9e80940d" +checksum = "e5d4a438e78dee446765fd9003beb55e6901cd25e5bf9c70ac5648f38ac97f44" dependencies = [ + "base64 0.22.1", "bincode", - "log", - "rustc_version", - "solana-config-program", - "solana-program-runtime", - "solana-sdk", - "solana-vote-program", + "bs58", + "serde", + "serde_derive", + "serde_json", + "solana-account-decoder-client-types", + "solana-commitment-config 3.1.1", + "solana-instruction 3.4.0", + "solana-message 3.1.0", + "solana-pubkey 3.0.0", + "solana-reward-info 3.0.0", + "solana-signature 3.4.0", + "solana-transaction 3.1.0", + "solana-transaction-context 3.0.0", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", ] [[package]] -name = "solana-streamer" -version = "1.17.14" +name = "solana-type-overrides" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efe4c33e0f68ea7a3701650badf6753b85fef2100cac6bc187c8e443e61c53da" +checksum = "41d80c44761eb398a157d809a04840865c347e1831ae3859b6100c0ee457bc1a" dependencies = [ - "async-channel", - "bytes", - "crossbeam-channel", - "futures-util", - "histogram", - "indexmap 2.1.0", - "itertools", - "libc", - "log", - "nix", - "pem", - "percentage", - "pkcs8", - "quinn", - "quinn-proto", "rand 0.8.5", - "rcgen", - "rustls", - "solana-metrics", - "solana-perf", - "solana-sdk", - "thiserror", - "tokio", - "x509-parser", ] [[package]] -name = "solana-system-program" -version = "1.17.14" +name = "solana-udp-client" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "24147d17f13bef6548d15a7fc63eb8a3271523f7ffc91f13032944b0dc34f974" +checksum = "8b23413db58cc7a1105ab72311ace1c77b80753ff66844065ad9a81fd4af6f56" dependencies = [ - "bincode", - "log", - "serde", - "serde_derive", - "solana-program-runtime", - "solana-sdk", + "async-trait", + "solana-connection-cache", + "solana-keypair 3.0.0", + "solana-net-utils", + "solana-streamer", + "solana-transaction-error 3.2.0", + "thiserror 2.0.18", + "tokio", ] [[package]] -name = "solana-thin-client" -version = "1.17.14" +name = "solana-unified-scheduler-logic" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54e782aabf9443a36d65e74d70ce732cc844707a5fec5a498bcbd81d3de7598c" +checksum = "ddca4dc9a64eadf2ad0d50681cd2ce4603c4d6d23b7dd865feb0af747e221757" dependencies = [ - "bincode", - "log", - "rayon", - "solana-connection-cache", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk", + "assert_matches", + "solana-pubkey 3.0.0", + "solana-runtime-transaction", + "solana-transaction 3.1.0", + "static_assertions", + "unwrap_none", ] [[package]] -name = "solana-tpu-client" -version = "1.17.14" +name = "solana-validator-exit" +version = "2.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "980bee30cbfe3c51f973da7fdcccb9df2c2d9b9175c06066b293499e02108fd4" +checksum = "7bbf6d7a3c0b28dd5335c52c0e9eae49d0ae489a8f324917faf0ded65a812c1d" + +[[package]] +name = "solana-version" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b931acdb55e7954abef34495630d40a6d8f6d9f3115f8292d416a76f14f9d01" dependencies = [ - "async-trait", - "bincode", - "futures-util", - "indexmap 2.1.0", - "indicatif", - "log", - "rayon", - "solana-connection-cache", - "solana-measure", - "solana-metrics", - "solana-pubsub-client", - "solana-rpc-client", - "solana-rpc-client-api", - "solana-sdk", - "thiserror", - "tokio", + "agave-feature-set 3.0.0", + "rand 0.8.5", + "semver", + "serde", + "serde_derive", + "solana-sanitize 3.0.1", + "solana-serde-varint 3.0.1", ] [[package]] -name = "solana-transaction-status" -version = "1.17.14" +name = "solana-vote" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c180013e406418d593ce7b51da7007a638ace18261de14901b090e53a1d7025" +checksum = "155a1c4fb423c33c1dd3ff5408139b4d63e218c5b03d05035c7b7751df674dd9" dependencies = [ - "Inflector", - "base64 0.21.7", - "bincode", - "borsh 0.10.3", - "bs58 0.4.0", - "lazy_static", + "itertools 0.12.1", "log", "serde", "serde_derive", - "serde_json", - "solana-account-decoder", - "solana-sdk", - "spl-associated-token-account", - "spl-memo", - "spl-token", - "spl-token-2022 1.0.0", - "thiserror", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-clock 3.0.1", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-keypair 3.0.0", + "solana-packet 3.0.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-serialize-utils 3.1.1", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "solana-svm-transaction", + "solana-transaction 3.1.0", + "solana-vote-interface 3.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-vote-interface" +version = "2.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b80d57478d6599d30acc31cc5ae7f93ec2361a06aefe8ea79bc81739a08af4c3" +dependencies = [ + "bincode", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "solana-clock 2.2.3", + "solana-decode-error", + "solana-hash 2.3.0", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-rent 2.2.1", + "solana-sdk-ids 2.2.1", + "solana-serde-varint 2.2.2", + "solana-serialize-utils 2.2.1", + "solana-short-vec 2.2.1", + "solana-system-interface 1.0.0", ] [[package]] -name = "solana-udp-client" -version = "1.17.14" +name = "solana-vote-interface" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab995970a424c89b7966a01aec90cdf1685c49aacf38a5f463200fc273a7d86b" +checksum = "66631ddbe889dab5ec663294648cd1df395ec9df7a4476e7b3e095604cfdb539" dependencies = [ - "async-trait", - "solana-connection-cache", - "solana-net-utils", - "solana-sdk", - "solana-streamer", - "thiserror", - "tokio", + "bincode", + "cfg_eval", + "num-derive 0.4.2", + "num-traits", + "serde", + "serde_derive", + "serde_with", + "solana-clock 3.0.1", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-instruction-error", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sdk-ids 3.1.0", + "solana-serde-varint 3.0.1", + "solana-serialize-utils 3.1.1", + "solana-short-vec 3.2.0", + "solana-system-interface 2.0.0", ] [[package]] -name = "solana-version" -version = "1.17.14" +name = "solana-vote-program" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b32cc394aa7132ab7f270801b98bf47fa585ab93f1038e5be27e480d7b5b2dca" +checksum = "823afcd47f3b57f0cffc678ae2f453a9be6e29f684f67d545f6b86cc95f31d8b" dependencies = [ + "agave-feature-set 3.0.0", + "bincode", "log", - "rustc_version", - "semver", + "num-derive 0.4.2", + "num-traits", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-sdk", + "solana-account 3.4.0", + "solana-bincode 3.1.0", + "solana-clock 3.0.1", + "solana-epoch-schedule 3.1.0", + "solana-hash 3.1.0", + "solana-instruction 3.4.0", + "solana-keypair 3.0.0", + "solana-packet 3.0.0", + "solana-program-runtime 3.0.0", + "solana-pubkey 3.0.0", + "solana-rent 3.1.0", + "solana-sdk-ids 3.1.0", + "solana-signer 3.0.0", + "solana-slot-hashes 3.0.1", + "solana-transaction 3.1.0", + "solana-transaction-context 3.0.0", + "solana-vote-interface 3.0.0", + "thiserror 2.0.18", +] + +[[package]] +name = "solana-zk-elgamal-proof-program" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "374ef01f09af37c6b1a5a4232a3a1deec1534d1c65fd0ac2a4e76201d6118901" +dependencies = [ + "agave-feature-set 3.0.0", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-instruction 3.4.0", + "solana-program-runtime 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-svm-log-collector", + "solana-zk-sdk 4.0.0", ] [[package]] -name = "solana-vote" -version = "1.17.14" +name = "solana-zk-sdk" +version = "2.3.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6092058284f0e02274177c45a22032eb7288aa4f6f8003ed469b1a562cac3bd" +checksum = "97b9fc6ec37d16d0dccff708ed1dd6ea9ba61796700c3bb7c3b401973f10f63b" dependencies = [ - "crossbeam-channel", - "itertools", - "log", - "rustc_version", + "aes-gcm-siv", + "base64 0.22.1", + "bincode", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", + "js-sys", + "merlin", + "num-derive 0.4.2", + "num-traits", + "rand 0.8.5", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-sdk", - "solana-vote-program", - "thiserror", + "serde_json", + "sha3", + "solana-derivation-path 2.2.1", + "solana-instruction 2.3.3", + "solana-pubkey 2.4.0", + "solana-sdk-ids 2.2.1", + "solana-seed-derivable 2.2.1", + "solana-seed-phrase 2.2.1", + "solana-signature 2.3.0", + "solana-signer 2.2.1", + "subtle", + "thiserror 2.0.18", + "wasm-bindgen", + "zeroize", ] [[package]] -name = "solana-vote-program" -version = "1.17.14" +name = "solana-zk-sdk" +version = "4.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "589cad4dccb4392e23f5ae4ccdd1f0aaa10f2823b264b27c4feb6382f40f4fd4" +checksum = "9602bcb1f7af15caef92b91132ec2347e1c51a72ecdbefdaefa3eac4b8711475" dependencies = [ + "aes-gcm-siv", + "base64 0.22.1", "bincode", - "log", - "num-derive 0.3.3", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "getrandom 0.2.17", + "itertools 0.12.1", + "js-sys", + "merlin", + "num-derive 0.4.2", "num-traits", - "rustc_version", + "rand 0.8.5", "serde", "serde_derive", - "solana-frozen-abi", - "solana-frozen-abi-macro", - "solana-metrics", - "solana-program", - "solana-program-runtime", - "solana-sdk", - "thiserror", + "serde_json", + "sha3", + "solana-derivation-path 3.0.0", + "solana-instruction 3.4.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-seed-derivable 3.0.0", + "solana-seed-phrase 3.0.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", + "subtle", + "thiserror 2.0.18", + "wasm-bindgen", + "zeroize", ] [[package]] name = "solana-zk-token-proof-program" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cc6b02ddeb2ab414b513b523aa678fac81109214f08d5c080165c15483a22cce" +checksum = "6b10c52c79f2b5e0147433ec956e8e4d05c86bf6322e4524748ac5091b24b37b" dependencies = [ + "agave-feature-set 3.0.0", "bytemuck", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", - "solana-program-runtime", - "solana-sdk", + "solana-instruction 3.4.0", + "solana-program-runtime 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-svm-log-collector", "solana-zk-token-sdk", ] [[package]] name = "solana-zk-token-sdk" -version = "1.17.14" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d932d7b13a223a6c1068d7061df7e9d2de14bfc0a874350eef19d59086b04a" +checksum = "7772e69c53780afa0de290627040209db81d32f3f87c7831137897bdbc461de8" dependencies = [ "aes-gcm-siv", - "base64 0.21.7", + "base64 0.22.1", "bincode", - "bytemuck", - "byteorder", - "curve25519-dalek", - "getrandom 0.1.16", - "itertools", - "lazy_static", + "bytemuck", + "bytemuck_derive", + "curve25519-dalek 4.1.3", + "itertools 0.12.1", "merlin", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", - "rand 0.7.3", + "rand 0.8.5", "serde", + "serde_derive", "serde_json", - "sha3 0.9.1", - "solana-program", - "solana-sdk", + "sha3", + "solana-curve25519 3.0.0", + "solana-derivation-path 3.0.0", + "solana-instruction 3.4.0", + "solana-pubkey 3.0.0", + "solana-sdk-ids 3.1.0", + "solana-seed-derivable 3.0.0", + "solana-seed-phrase 3.0.0", + "solana-signature 3.4.0", + "solana-signer 3.0.0", "subtle", - "thiserror", + "thiserror 2.0.18", "zeroize", ] [[package]] -name = "solana_rbpf" -version = "0.8.0" +name = "spinning_top" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d457cc2ba742c120492a64b7fa60e22c575e891f6b55039f4d736568fb112a3" +checksum = "d96d2d1d716fb500937168cc09353ffdc7a012be8475ac7308e1bdf0e3923300" dependencies = [ - "byteorder", - "combine", - "goblin", - "hash32", - "libc", - "log", - "rand 0.8.5", - "rustc-demangle", - "scroll", - "thiserror", - "winapi", + "lock_api", ] -[[package]] -name = "spin" -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" +version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d01ac02a6ccf3e07db148d2be087da624fea0221a16152ed01f0496a6b0a27" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" dependencies = [ "base64ct", "der", ] -[[package]] -name = "spl-associated-token-account" -version = "2.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "992d9c64c2564cc8f63a4b508bf3ebcdf2254b0429b13cd1d31adb6162432a5f" -dependencies = [ - "assert_matches", - "borsh 0.10.3", - "num-derive 0.4.1", - "num-traits", - "solana-program", - "spl-token", - "spl-token-2022 1.0.0", - "thiserror", -] - [[package]] name = "spl-discriminator" -version = "0.1.0" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cce5d563b58ef1bb2cdbbfe0dfb9ffdc24903b10ae6a4df2d8f425ece375033f" +checksum = "a7398da23554a31660f17718164e31d31900956054f54f52d5ec1be51cb4f4b3" dependencies = [ "bytemuck", - "solana-program", + "solana-program-error 2.2.2", + "solana-sha256-hasher 2.3.0", "spl-discriminator-derive", ] [[package]] name = "spl-discriminator-derive" -version = "0.1.1" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fadbefec4f3c678215ca72bd71862697bb06b41fd77c0088902dd3203354387b" +checksum = "d9e8418ea6269dcfb01c712f0444d2c75542c04448b480e87de59d2865edc750" dependencies = [ "quote", "spl-discriminator-syn", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "spl-discriminator-syn" -version = "0.1.1" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e5f2044ca42c8938d54d1255ce599c79a1ffd86b677dfab695caa20f9ffc3f2" +checksum = "5d1dbc82ab91422345b6df40a79e2b78c7bce1ebb366da323572dd60b7076b67" dependencies = [ "proc-macro2", "quote", - "sha2 0.10.8", - "syn 2.0.48", - "thiserror", + "sha2 0.10.9", + "syn 2.0.117", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-elgamal-registry" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce0f668975d2b0536e8a8fd60e56a05c467f06021dae037f1d0cfed0de2e231d" +dependencies = [ + "bytemuck", + "solana-program 2.3.0", + "solana-zk-sdk 2.3.13", + "spl-pod", + "spl-token-confidential-transfer-proof-extraction", +] + +[[package]] +name = "spl-generic-token" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "233df81b75ab99b42f002b5cdd6e65a7505ffa930624f7096a7580a56765e9cf" +dependencies = [ + "bytemuck", + "solana-pubkey 3.0.0", ] [[package]] name = "spl-memo" -version = "4.0.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f180b03318c3dbab3ef4e1e4d46d5211ae3c780940dd0a28695aba4b59a75a" +checksum = "9f09647c0974e33366efeb83b8e2daebb329f0420149e74d3a4bd2c08cf9f7cb" dependencies = [ - "solana-program", + "solana-account-info 2.3.0", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-entrypoint 2.3.0", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", ] [[package]] name = "spl-noop" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6dd67ea3d0070a12ff141f5da46f9695f49384a03bce1203a5608f5739437950" +checksum = "1c3bc351f7543a46f6807c231fc29ef2c4912c79bd6a4fb7d038cba6836f0fd7" dependencies = [ - "solana-program", + "solana-program 2.3.0", ] [[package]] name = "spl-pod" -version = "0.1.0" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2881dddfca792737c0706fa0175345ab282b1b0879c7d877bad129645737c079" +checksum = "d994afaf86b779104b4a95ba9ca75b8ced3fdb17ee934e38cb69e72afbe17799" dependencies = [ - "borsh 0.10.3", + "borsh 1.6.1", "bytemuck", - "solana-program", - "solana-zk-token-sdk", - "spl-program-error", + "bytemuck_derive", + "num-derive 0.4.2", + "num-traits", + "solana-decode-error", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-program-option 2.2.1", + "solana-pubkey 2.4.0", + "solana-zk-sdk 2.3.13", + "thiserror 2.0.18", ] [[package]] name = "spl-program-error" -version = "0.3.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "249e0318493b6bcf27ae9902600566c689b7dfba9f1bdff5893e92253374e78c" +checksum = "9d39b5186f42b2b50168029d81e58e800b690877ef0b30580d107659250da1d1" dependencies = [ - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", - "solana-program", + "solana-program 2.3.0", "spl-program-error-derive", - "thiserror", + "thiserror 1.0.69", ] [[package]] name = "spl-program-error-derive" -version = "0.3.1" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ab5269c8e868da17b6552ef35a51355a017bd8e0eae269c201fef830d35fa52c" +checksum = "e6d375dd76c517836353e093c2dbb490938ff72821ab568b545fd30ab3256b3e" dependencies = [ "proc-macro2", "quote", - "sha2 0.10.8", - "syn 2.0.48", -] - -[[package]] -name = "spl-tlv-account-resolution" -version = "0.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7960b1e1a41e4238807fca0865e72a341b668137a3f2ddcd770d04fd1b374c96" -dependencies = [ - "bytemuck", - "solana-program", - "spl-discriminator", - "spl-pod", - "spl-program-error", - "spl-type-length-value", + "sha2 0.10.9", + "syn 2.0.117", ] [[package]] name = "spl-tlv-account-resolution" -version = "0.5.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "615d381f48ddd2bb3c57c7f7fb207591a2a05054639b18a62e785117dd7a8683" +checksum = "cd99ff1e9ed2ab86e3fd582850d47a739fec1be9f4661cba1782d3a0f26805f3" dependencies = [ "bytemuck", - "solana-program", + "num-derive 0.4.2", + "num-traits", + "solana-account-info 2.3.0", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", "spl-discriminator", "spl-pod", "spl-program-error", "spl-type-length-value", + "thiserror 1.0.69", ] [[package]] name = "spl-token" -version = "4.0.0" +version = "7.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08459ba1b8f7c1020b4582c4edf0f5c7511a5e099a7a97570c9698d4f2337060" +checksum = "ed320a6c934128d4f7e54fe00e16b8aeaecf215799d060ae14f93378da6dc834" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.3.3", + "num-derive 0.4.2", "num-traits", - "num_enum 0.6.1", - "solana-program", - "thiserror", + "num_enum", + "solana-program 2.3.0", + "thiserror 1.0.69", ] [[package]] name = "spl-token-2022" -version = "0.8.0" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "84fc0c7a763c3f53fa12581d07ed324548a771bb648a1217e4f330b1d0a59331" +checksum = "5b27f7405010ef816587c944536b0eafbcc35206ab6ba0f2ca79f1d28e488f4f" dependencies = [ "arrayref", "bytemuck", - "num-derive 0.4.1", + "num-derive 0.4.2", "num-traits", - "num_enum 0.7.2", - "solana-program", - "solana-zk-token-sdk", + "num_enum", + "solana-program 2.3.0", + "solana-security-txt", + "solana-zk-sdk 2.3.13", + "spl-elgamal-registry", "spl-memo", "spl-pod", "spl-token", + "spl-token-confidential-transfer-ciphertext-arithmetic", + "spl-token-confidential-transfer-proof-extraction", + "spl-token-confidential-transfer-proof-generation", + "spl-token-group-interface", "spl-token-metadata-interface", - "spl-transfer-hook-interface 0.2.0", + "spl-transfer-hook-interface", "spl-type-length-value", - "thiserror", + "thiserror 1.0.69", ] [[package]] -name = "spl-token-2022" -version = "1.0.0" +name = "spl-token-confidential-transfer-ciphertext-arithmetic" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d697fac19fd74ff472dfcc13f0b442dd71403178ce1de7b5d16f83a33561c059" +checksum = "170378693c5516090f6d37ae9bad2b9b6125069be68d9acd4865bbe9fc8499fd" dependencies = [ - "arrayref", + "base64 0.22.1", "bytemuck", - "num-derive 0.4.1", - "num-traits", - "num_enum 0.7.2", - "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 0.4.1", - "spl-type-length-value", - "thiserror", + "solana-curve25519 2.3.13", + "solana-zk-sdk 2.3.13", ] [[package]] -name = "spl-token-group-interface" -version = "0.1.0" +name = "spl-token-confidential-transfer-proof-extraction" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b889509d49fa74a4a033ca5dae6c2307e9e918122d97e58562f5c4ffa795c75d" +checksum = "eff2d6a445a147c9d6dd77b8301b1e116c8299601794b558eafa409b342faf96" dependencies = [ "bytemuck", - "solana-program", - "spl-discriminator", + "solana-curve25519 2.3.13", + "solana-program 2.3.0", + "solana-zk-sdk 2.3.13", "spl-pod", - "spl-program-error", + "thiserror 2.0.18", ] [[package]] -name = "spl-token-metadata-interface" +name = "spl-token-confidential-transfer-proof-generation" version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c16ce3ba6979645fb7627aa1e435576172dd63088dc7848cb09aa331fa1fe4f" +checksum = "8627184782eec1894de8ea26129c61303f1f0adeed65c20e0b10bc584f09356d" +dependencies = [ + "curve25519-dalek 4.1.3", + "solana-zk-sdk 2.3.13", + "thiserror 1.0.69", +] + +[[package]] +name = "spl-token-group-interface" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d595667ed72dbfed8c251708f406d7c2814a3fa6879893b323d56a10bedfc799" dependencies = [ - "borsh 0.10.3", - "solana-program", + "bytemuck", + "num-derive 0.4.2", + "num-traits", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", "spl-discriminator", "spl-pod", - "spl-program-error", - "spl-type-length-value", + "thiserror 1.0.69", ] [[package]] -name = "spl-transfer-hook-interface" -version = "0.2.0" +name = "spl-token-metadata-interface" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7489940049417ae5ce909314bead0670e2a5ea5c82d43ab96dc15c8fcbbccba" +checksum = "dfb9c89dbc877abd735f05547dcf9e6e12c00c11d6d74d8817506cab4c99fdbb" dependencies = [ - "arrayref", - "bytemuck", - "solana-program", + "borsh 1.6.1", + "num-derive 0.4.2", + "num-traits", + "solana-borsh 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", "spl-discriminator", "spl-pod", - "spl-program-error", - "spl-tlv-account-resolution 0.3.0", "spl-type-length-value", + "thiserror 1.0.69", ] [[package]] name = "spl-transfer-hook-interface" -version = "0.4.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7aabdb7c471566f6ddcee724beb8618449ea24b399e58d464d6b5bc7db550259" +checksum = "4aa7503d52107c33c88e845e1351565050362c2314036ddf19a36cd25137c043" dependencies = [ "arrayref", "bytemuck", - "solana-program", + "num-derive 0.4.2", + "num-traits", + "solana-account-info 2.3.0", + "solana-cpi 2.2.1", + "solana-decode-error", + "solana-instruction 2.3.3", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", + "solana-pubkey 2.4.0", "spl-discriminator", "spl-pod", "spl-program-error", - "spl-tlv-account-resolution 0.5.1", + "spl-tlv-account-resolution", "spl-type-length-value", + "thiserror 1.0.69", ] [[package]] name = "spl-type-length-value" -version = "0.3.0" +version = "0.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a468e6f6371f9c69aae760186ea9f1a01c2908351b06a5e0026d21cfc4d7ecac" +checksum = "ba70ef09b13af616a4c987797870122863cba03acc4284f226a4473b043923f9" dependencies = [ "bytemuck", - "solana-program", + "num-derive 0.4.2", + "num-traits", + "solana-account-info 2.3.0", + "solana-decode-error", + "solana-msg 2.2.1", + "solana-program-error 2.2.2", "spl-discriminator", "spl-pod", - "spl-program-error", + "thiserror 1.0.69", ] [[package]] -name = "static_assertions" -version = "1.1.0" +name = "stable_deref_trait" +version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" [[package]] -name = "strsim" -version = "0.8.0" +name = "static_assertions" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" [[package]] name = "strsim" -version = "0.10.0" +version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" [[package]] name = "strum" @@ -5091,11 +10205,11 @@ dependencies = [ [[package]] name = "strum" -version = "0.26.1" +version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "723b93e8addf9aa965ebe2d11da6d7540fa2283fcea14b3371ff055f7ba13f5f" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" dependencies = [ - "strum_macros 0.26.1", + "strum_macros 0.26.4", ] [[package]] @@ -5113,22 +10227,22 @@ dependencies = [ [[package]] name = "strum_macros" -version = "0.26.1" +version = "0.26.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a3417fc93d76740d974a01654a09777cb500428cc874ca9f45edfe0c4d4cd18" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" dependencies = [ - "heck 0.4.1", + "heck 0.5.0", "proc-macro2", "quote", "rustversion", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "subtle" -version = "2.4.1" +version = "2.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "symlink" @@ -5149,15 +10263,24 @@ dependencies = [ [[package]] name = "syn" -version = "2.0.48" +version = "2.0.117" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" dependencies = [ "proc-macro2", "quote", "unicode-ident", ] +[[package]] +name = "sync_wrapper" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf256ce5efdfa370213c1dabab5935a12e49f2c58d15e9eac2870d3b4f27263" +dependencies = [ + "futures-core", +] + [[package]] name = "synstructure" version = "0.12.6" @@ -5171,31 +10294,21 @@ dependencies = [ ] [[package]] -name = "system-configuration" -version = "0.5.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba3a3adc5c275d719af8cb4272ea1c4a6d668a777f37e115f6d11ddbc1c8e0e7" -dependencies = [ - "bitflags 1.3.2", - "core-foundation", - "system-configuration-sys", -] - -[[package]] -name = "system-configuration-sys" -version = "0.5.0" +name = "synstructure" +version = "0.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75fb188eb626b924683e3b95e3a48e63551fcfb51949de2f06a9d91dbee93c9" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" dependencies = [ - "core-foundation-sys", - "libc", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "tar" -version = "0.4.40" +version = "0.4.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b16afcea1f22891c49a00c751c7b63b2233284064f11a200fc624137c51e2ddb" +checksum = "22692a6476a21fa75fdfc11d452fda482af402c008cdbaf3476414e122040973" dependencies = [ "filetime", "libc", @@ -5218,7 +10331,7 @@ dependencies = [ "serde", "static_assertions", "tarpc-plugins", - "thiserror", + "thiserror 1.0.69", "tokio", "tokio-serde", "tokio-util 0.6.10", @@ -5239,15 +10352,15 @@ dependencies = [ [[package]] name = "tempfile" -version = "3.9.0" +version = "3.27.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "01ce4141aa927a6d1bd34a041795abd0db1cccba5d5f24b009f694bdf3a1f3fa" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" dependencies = [ - "cfg-if", "fastrand", - "redox_syscall", + "getrandom 0.3.4", + "once_cell", "rustix", - "windows-sys 0.52.0", + "windows-sys 0.61.2", ] [[package]] @@ -5260,136 +10373,106 @@ dependencies = [ ] [[package]] -name = "test-case" -version = "3.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eb2550dd13afcd286853192af8601920d959b14c401fcece38071d53bf0768a8" -dependencies = [ - "test-case-macros", -] - -[[package]] -name = "test-case-core" -version = "3.3.1" +name = "termtree" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adcb7fd841cd518e279be3d5a3eb0636409487998a4aff22f3de87b81e88384f" -dependencies = [ - "cfg-if", - "proc-macro2", - "quote", - "syn 2.0.48", -] +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" [[package]] -name = "test-case-macros" -version = "3.3.1" +name = "thiserror" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c89e72a01ed4c579669add59014b9a524d609c0c88c6a585ce37485879f6ffb" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", - "test-case-core", + "thiserror-impl 1.0.69", ] [[package]] -name = "textwrap" -version = "0.11.0" +name = "thiserror" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" dependencies = [ - "unicode-width", + "thiserror-impl 2.0.18", ] [[package]] -name = "textwrap" -version = "0.16.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "222a222a5bfe1bba4a77b45ec488a741b3cb8872e5e499451fd7d0129c9c7c3d" - -[[package]] -name = "thiserror" -version = "1.0.56" +name = "thiserror-impl" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ - "thiserror-impl", + "proc-macro2", + "quote", + "syn 2.0.117", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "2.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "thread_local" -version = "1.1.7" +version = "1.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fdd6f064ccff2d6567adcb3873ca630700f00b5ad3f060c25b5dcfd9a4ce152" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" dependencies = [ "cfg-if", - "once_cell", ] [[package]] name = "time" -version = "0.3.31" +version = "0.3.47" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f657ba42c3f86e7680e53c8cd3af8abbe56b5491790b46e22e19c0d57463583e" +checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" dependencies = [ "deranged", "itoa", + "num-conv", "powerfmt", - "serde", + "serde_core", "time-core", "time-macros", ] [[package]] name = "time-core" -version = "0.1.2" +version = "0.1.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" [[package]] name = "time-macros" -version = "0.2.16" +version = "0.2.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "26197e33420244aeb70c3e8c78376ca46571bc4e701e4791c2cd9f57dcb3a43f" +checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" dependencies = [ + "num-conv", "time-core", ] [[package]] -name = "tiny-bip39" -version = "0.8.2" +name = "tinystr" +version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc59cb9dfc85bb312c3a78fd6aa8a8582e310b0fa885d5bb877f6dcc601839d" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" 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", + "displaydoc", + "zerovec", ] [[package]] name = "tinyvec" -version = "1.6.0" +version = "1.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" +checksum = "3e61e67053d25a4e82c844e8424039d9745781b3fc4f32b8d55ed50f5f667ef3" dependencies = [ "tinyvec_macros", ] @@ -5402,32 +10485,30 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20" [[package]] name = "tokio" -version = "1.35.1" +version = "1.52.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c89b4efa943be685f629b149f53829423f8f5531ea21249408e8e2f8671ec104" +checksum = "b67dee974fe86fd92cc45b7a95fdd2f99a36a6d7b0d431a231178d3d670bbcc6" dependencies = [ - "backtrace", "bytes", "libc", "mio", - "num_cpus", "parking_lot", "pin-project-lite", "signal-hook-registry", "socket2", "tokio-macros", - "windows-sys 0.48.0", + "windows-sys 0.61.2", ] [[package]] name = "tokio-macros" -version = "2.2.0" +version = "2.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b8a1e28f2deaa14e508979454cb3a223b10b938b45af148bc0986de36f1923b" +checksum = "385a6cb71ab9ab790c5fe8d67f1645e6c450a7ce006a33de03daa956cf70a496" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] @@ -5436,7 +10517,17 @@ version = "0.24.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c28327cf380ac148141087fbfb9de9d7bd4e84ab5d2c28fbc911d753de8a7081" dependencies = [ - "rustls", + "rustls 0.21.12", + "tokio", +] + +[[package]] +name = "tokio-rustls" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1729aa945f29d91ba541258c8df89027d5792d85a8841fb65e8bf0f4ede4ef61" +dependencies = [ + "rustls 0.23.38", "tokio", ] @@ -5448,7 +10539,7 @@ checksum = "911a61637386b789af998ee23f50aa30d5fd7edcec8d6d3dedae5e5815205466" dependencies = [ "bincode", "bytes", - "educe", + "educe 0.4.23", "futures-core", "futures-sink", "pin-project", @@ -5458,9 +10549,9 @@ dependencies = [ [[package]] name = "tokio-stream" -version = "0.1.14" +version = "0.1.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "397c988d37662c7dda6d2208364a706264bf3d6138b11d436cbac0ad38832842" +checksum = "32da49809aab5c3bc678af03902d4ccddea2a87d028d86392a4b1560c6906c70" dependencies = [ "futures-core", "pin-project-lite", @@ -5475,11 +10566,11 @@ checksum = "212d5dcb2a1ce06d81107c3d0ffa3121fe974b73f068c8282cb1c32328113b6c" dependencies = [ "futures-util", "log", - "rustls", + "rustls 0.21.12", "tokio", - "tokio-rustls", + "tokio-rustls 0.24.1", "tungstenite", - "webpki-roots 0.25.3", + "webpki-roots 0.25.4", ] [[package]] @@ -5499,16 +10590,15 @@ dependencies = [ [[package]] name = "tokio-util" -version = "0.7.10" +version = "0.7.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5419f34732d9eb6ee4c3578b7989078579b7f039cbbb9ca2c4da015749371e15" +checksum = "9ae9cec805b01e8fc3fd2fe289f89149a9b66dd16786abd8b19cfa7b48cb0098" dependencies = [ "bytes", "futures-core", "futures-sink", "pin-project-lite", "tokio", - "tracing", ] [[package]] @@ -5522,43 +10612,89 @@ dependencies = [ [[package]] name = "toml_datetime" -version = "0.6.5" +version = "1.1.1+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3550f4e9685620ac18a50ed434eb3aec30db8ba93b0287467bca5826ea25baf1" +checksum = "3165f65f62e28e0115a00b2ebdd37eb6f3b641855f9d636d3cd4103767159ad7" +dependencies = [ + "serde_core", +] [[package]] name = "toml_edit" -version = "0.19.15" +version = "0.25.11+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b5bb770da30e5cbfde35a2d7b9b8a2c4b8ef89548a7a6aeab5c9a576e3e7421" +checksum = "0b59c4d22ed448339746c59b905d24568fcbb3ab65a500494f7b8c3e97739f2b" dependencies = [ - "indexmap 2.1.0", + "indexmap 2.14.0", "toml_datetime", + "toml_parser", "winnow", ] [[package]] -name = "toml_edit" -version = "0.21.0" +name = "toml_parser" +version = "1.1.2+spec-1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d34d383cd00a163b4a5b85053df514d45bc330f6de7737edfe0a93311d1eaa03" +checksum = "a2abe9b86193656635d2411dc43050282ca48aa31c2451210f4202550afb7526" dependencies = [ - "indexmap 2.1.0", - "toml_datetime", "winnow", ] +[[package]] +name = "tower" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebe5ef63511595f1344e2d5cfa636d973292adc0eec1f0ad45fae9f0851ab1d4" +dependencies = [ + "futures-core", + "futures-util", + "pin-project-lite", + "sync_wrapper", + "tokio", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-http" +version = "0.6.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4e6559d53cc268e5031cd8429d05415bc4cb4aefc4aa5d6cc35fbf5b924a1f8" +dependencies = [ + "async-compression", + "bitflags", + "bytes", + "futures-core", + "futures-util", + "http 1.4.0", + "http-body", + "http-body-util", + "iri-string", + "pin-project-lite", + "tokio", + "tokio-util 0.7.18", + "tower", + "tower-layer", + "tower-service", +] + +[[package]] +name = "tower-layer" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "121c2a6cda46980bb0fcd1647ffaf6cd3fc79a013de288782836f6df9c48780e" + [[package]] name = "tower-service" -version = "0.3.2" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6bc1c9ce2b5135ac7f93c72918fc37feb872bdc6a5533a8b85eb4b86bfdae52" +checksum = "8df9b6e13f2d32c91b9bd719c00d1958837bc7dec474d94952798cc8e69eeec3" [[package]] name = "tracing" -version = "0.1.40" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" dependencies = [ "log", "pin-project-lite", @@ -5568,20 +10704,20 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.27" +version = "0.1.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] [[package]] name = "tracing-core" -version = "0.1.32" +version = "0.1.36" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" dependencies = [ "once_cell", "valuable", @@ -5602,9 +10738,9 @@ dependencies = [ [[package]] name = "tracing-subscriber" -version = "0.3.18" +version = "0.3.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ad0f048c97dbd9faa9b7df56362b8ebcaa52adb06b498c050d2f4e32f90a7a8b" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" dependencies = [ "sharded-slab", "thread_local", @@ -5626,13 +10762,13 @@ dependencies = [ "byteorder", "bytes", "data-encoding", - "http", + "http 0.2.12", "httparse", "log", "rand 0.8.5", - "rustls", + "rustls 0.21.12", "sha1", - "thiserror", + "thiserror 1.0.69", "url", "utf-8", "webpki-roots 0.24.0", @@ -5640,56 +10776,47 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" - -[[package]] -name = "unicode-bidi" -version = "0.3.15" +version = "1.19.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08f95100a766bf4f8f28f90d77e0a5461bbdb219042e7679bebe79004fed8d75" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" [[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.22" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c5713f0fc4b5db668a2ac63cdb7bb4469d8c9fed047b1d0292cc7b0ce2ba921" -dependencies = [ - "tinyvec", -] +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" [[package]] name = "unicode-segmentation" -version = "1.11.0" +version = "1.13.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4c87d22b6e3f4a18d4d40ef354e97c90fcb14dd91d7dc0aa9d8a1172ebf7202" +checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" [[package]] name = "unicode-width" -version = "0.1.11" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e51733f11c9c4f72aa0c160008246859e340b00807569a0da0e7a1079b27ba85" +checksum = "b4ac048d71ede7ee76d585517add45da530660ef4390e49b098733c6e897f254" [[package]] name = "unicode-xid" -version = "0.2.4" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "unit-prefix" +version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" +checksum = "81e544489bf3d8ef66c953931f56617f423cd4b5494be343d9b9d3dda037b9a3" [[package]] name = "universal-hash" -version = "0.4.1" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f214e8f697e925001e66ec2c6e37a4ef93f0f78c2eed7814394e10c62025b05" +checksum = "fc1de2c688dc15305988b563c3854064043356019f97a4b46276fe734c4f07ea" dependencies = [ - "generic-array", + "crypto-common 0.1.7", "subtle", ] @@ -5704,15 +10831,15 @@ dependencies = [ [[package]] name = "untrusted" -version = "0.7.1" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a156c684c91ea7d62626509bce3cb4e1d9ed5c4d978f7b4352658f96a4c26b4a" +checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] -name = "untrusted" -version = "0.9.0" +name = "unwrap_none" +version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" +checksum = "461d0c5956fcc728ecc03a3a961e4adc9a7975d86f6f8371389a289517c02ca9" [[package]] name = "uriparse" @@ -5726,13 +10853,14 @@ dependencies = [ [[package]] name = "url" -version = "2.5.0" +version = "2.5.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "31e6302e3bb753d46e83516cae55ae196fc0c309407cf11ab35cc51a4c2a4633" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" dependencies = [ "form_urlencoded", "idna", "percent-encoding", + "serde", ] [[package]] @@ -5741,23 +10869,35 @@ version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9" +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + [[package]] name = "valuable" -version = "0.1.0" +version = "0.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830b7e5d4d90034032940e4ace0d9a9a057e7a45cd94e6c007832e39edb82f6d" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" [[package]] -name = "vec_map" -version = "0.8.2" +name = "vcpkg" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" [[package]] name = "version_check" -version = "0.9.4" +version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "void" @@ -5767,9 +10907,9 @@ checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" [[package]] name = "walkdir" -version = "2.4.0" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" dependencies = [ "same-file", "winapi-util", @@ -5792,52 +10932,47 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" [[package]] name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +version = "0.11.1+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" [[package]] -name = "wasm-bindgen" -version = "0.2.90" +name = "wasip2" +version = "1.0.2+wasi-0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1223296a201415c7fad14792dbefaace9bd52b62d33453ade1c5b5f07555406" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" dependencies = [ - "cfg-if", - "wasm-bindgen-macro", + "wit-bindgen", ] [[package]] -name = "wasm-bindgen-backend" -version = "0.2.90" +name = "wasm-bindgen" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fcdc935b63408d58a32f8cc9738a0bffd8f05cc7c002086c6ef20b7312ad9dcd" +checksum = "0bf938a0bacb0469e83c1e148908bd7d5a6010354cf4fb73279b7447422e3a89" dependencies = [ - "bumpalo", - "log", + "cfg-if", "once_cell", - "proc-macro2", - "quote", - "syn 2.0.48", + "rustversion", + "wasm-bindgen-macro", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-futures" -version = "0.4.40" +version = "0.4.68" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bde2032aeb86bdfaecc8b261eef3cba735cc426c1f3a3416d1e0791be95fc461" +checksum = "f371d383f2fb139252e0bfac3b81b265689bf45b6874af544ffa4c975ac1ebf8" dependencies = [ - "cfg-if", "js-sys", "wasm-bindgen", - "web-sys", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.90" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e4c238561b2d428924c49815533a8b9121c664599558a5d9ec51f8a1740a999" +checksum = "eeff24f84126c0ec2db7a449f0c2ec963c6a49efe0698c4242929da037ca28ed" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -5845,47 +10980,78 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.90" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bae1abb6806dc1ad9e560ed242107c0f6c84335f1749dd4e8ddb012ebd5e25a7" +checksum = "9d08065faf983b2b80a79fd87d8254c409281cf7de75fc4b773019824196c904" dependencies = [ + "bumpalo", "proc-macro2", "quote", - "syn 2.0.48", - "wasm-bindgen-backend", + "syn 2.0.117", "wasm-bindgen-shared", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.90" +version = "0.2.118" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d91413b1c31d7539ba5ef2451af3f0b833a005eb27a631cec32bc0635a8602b" +checksum = "5fd04d9e306f1907bd13c6361b5c6bfc7b3b3c095ed3f8a9246390f8dbdee129" +dependencies = [ + "unicode-ident", +] [[package]] name = "web-sys" -version = "0.3.67" +version = "0.3.95" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f2dfbb17949fa2088e5d39408c48368947b86f7834484e87b73de55bc14d97d" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "58cd2333b6e0be7a39605f0e255892fd7418a682d8da8fe042fe25128794d2ed" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" dependencies = [ "js-sys", "wasm-bindgen", ] +[[package]] +name = "webpki-root-certs" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31141ce3fc3e300ae89b78c0dd67f9708061d1d2eda54b8209346fd6be9a92c" +dependencies = [ + "rustls-pki-types", +] + [[package]] name = "webpki-roots" version = "0.24.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b291546d5d9d1eab74f069c77749f2cb8504a12caa20f0f2de93ddbf6f411888" dependencies = [ - "rustls-webpki", + "rustls-webpki 0.101.7", ] [[package]] name = "webpki-roots" -version = "0.25.3" +version = "0.25.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f20c57d8d7db6d3b86154206ae5d8fba62dd39573114de97c2cb0578251f8e1" + +[[package]] +name = "webpki-roots" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1778a42e8b3b90bff8d0f5032bf22250792889a5cdc752aa0020c84abe3aaf10" +checksum = "52f5ee44c96cf55f1b349600768e3ece3a8f26010c05265ab73f945bb1a2eb9d" +dependencies = [ + "rustls-pki-types", +] [[package]] name = "winapi" @@ -5905,11 +11071,11 @@ checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" [[package]] name = "winapi-util" -version = "0.1.6" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "winapi", + "windows-sys 0.61.2", ] [[package]] @@ -5918,22 +11084,97 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "wincode" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2f42dd20febad683d07044c5f543e57f822512ebebaf2c827705c99a0ad4575" +dependencies = [ + "pastey", + "proc-macro2", + "quote", + "thiserror 2.0.18", + "wincode-derive", +] + +[[package]] +name = "wincode-derive" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fca057fc9a13dd19cdb64ef558635d43c42667c0afa1ae7915ea1fa66993fd1a" +dependencies = [ + "darling 0.21.3", + "proc-macro2", + "quote", + "syn 2.0.117", +] + [[package]] name = "windows-core" -version = "0.52.0" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement", + "windows-interface", + "windows-link", + "windows-result", + "windows-strings", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33ab640c8d7e35bf8ba19b884ba838ceb4fba93a4e8c65a9059d08afcfc683d9" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" dependencies = [ - "windows-targets 0.52.0", + "windows-link", ] [[package]] name = "windows-sys" -version = "0.48.0" +version = "0.45.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" dependencies = [ - "windows-targets 0.48.5", + "windows-targets 0.42.2", ] [[package]] @@ -5942,141 +11183,233 @@ version = "0.52.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" dependencies = [ - "windows-targets 0.52.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", ] [[package]] name = "windows-targets" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "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", ] [[package]] name = "windows-targets" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a18201040b24831fbb9e4eb208f8892e1f50a37feb53cc7ff887feb8f50e7cd" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" dependencies = [ - "windows_aarch64_gnullvm 0.52.0", - "windows_aarch64_msvc 0.52.0", - "windows_i686_gnu 0.52.0", - "windows_i686_msvc 0.52.0", - "windows_x86_64_gnu 0.52.0", - "windows_x86_64_gnullvm 0.52.0", - "windows_x86_64_msvc 0.52.0", + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", ] [[package]] name = "windows_aarch64_gnullvm" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" [[package]] name = "windows_aarch64_gnullvm" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cb7764e35d4db8a7921e09562a0304bf2f93e0a51bfccee0bd0bb0b666b015ea" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" [[package]] name = "windows_aarch64_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" [[package]] name = "windows_aarch64_msvc" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbaa0368d4f1d2aaefc55b6fcfee13f41544ddf36801e793edbbfd7d7df075ef" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" [[package]] name = "windows_i686_gnu" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" [[package]] name = "windows_i686_gnu" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a28637cb1fa3560a16915793afb20081aba2c92ee8af57b4d5f28e4b3e7df313" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" [[package]] name = "windows_i686_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" [[package]] name = "windows_i686_msvc" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffe5e8e31046ce6230cc7215707b816e339ff4d4d67c65dffa206fd0f7aa7b9a" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" [[package]] name = "windows_x86_64_gnu" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" [[package]] name = "windows_x86_64_gnu" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6fa32db2bc4a2f5abeacf2b69f7992cd09dca97498da74a151a3132c26befd" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" [[package]] name = "windows_x86_64_gnullvm" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" [[package]] name = "windows_x86_64_gnullvm" -version = "0.52.0" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a657e1e9d3f514745a572a6846d3c7aa7dbe1658c056ed9c3344c4109a6949e" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" [[package]] name = "windows_x86_64_msvc" -version = "0.48.5" +version = "0.42.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" [[package]] name = "windows_x86_64_msvc" -version = "0.52.0" +version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dff9641d1cd4be8d1a070daf9e3773c5f67e78b4d9d42263020c057706765c04" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" [[package]] name = "winnow" -version = "0.5.34" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7cf47b659b318dccbd69cc4797a39ae128f533dce7902a1096044d1967b9c16" +checksum = "09dac053f1cd375980747450bfc7250c264eaae0583872e845c0c7cd578872b5" dependencies = [ "memchr", ] [[package]] -name = "winreg" -version = "0.50.0" +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "524e57b2c537c0f9b1e69f1965311ec12182b4122e45035b1508cd24d2adadb1" -dependencies = [ - "cfg-if", - "windows-sys 0.48.0", -] +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" [[package]] name = "x509-parser" @@ -6092,94 +11425,166 @@ dependencies = [ "nom", "oid-registry", "rusticata-macros", - "thiserror", + "thiserror 1.0.69", "time", ] [[package]] name = "xattr" -version = "1.3.1" +version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8da84f1a25939b27f6820d92aed108f83ff920fdf11a7b19366c27c4cda81d4f" +checksum = "32e45ad4206f6d2479085147f02bc2ef834ac85886624a23575ae137c8aa8156" dependencies = [ "libc", - "linux-raw-sys", "rustix", ] [[package]] -name = "yasna" -version = "0.5.2" +name = "yoke" +version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e17bb3549cc1321ae1296b9cdc2698e2b6cb1992adfa19a8c72e5b7a738f44cd" +checksum = "abe8c5fda708d9ca3df187cae8bfb9ceda00dd96231bed36e445a1a48e66f9ca" dependencies = [ - "time", + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", + "synstructure 0.13.2", ] [[package]] name = "zerocopy" -version = "0.7.32" +version = "0.8.48" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "74d4d3961e53fa4c9a25a8637fc2bfaf2595b3d3ae34875568a5cf64787716be" +checksum = "eed437bf9d6692032087e337407a86f04cd8d6a16a37199ed57949d415bd68e9" dependencies = [ "zerocopy-derive", ] [[package]] name = "zerocopy-derive" -version = "0.7.32" +version = "0.8.48" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70e3cd084b1788766f53af483dd21f93881ff30d7320490ec3ef7526d203bad4" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerofrom" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69faa1f2a1ea75661980b013019ed6687ed0e83d069bc1114e2cc74c6c04c4df" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ce1b18ccd8e73a9321186f97e46f9f04b778851177567b1975109d26a08d2a6" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", + "synstructure 0.13.2", ] [[package]] name = "zeroize" -version = "1.3.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.117", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" dependencies = [ "proc-macro2", "quote", - "syn 2.0.48", + "syn 2.0.117", ] +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + [[package]] name = "zstd" -version = "0.11.2+zstd.1.5.2" +version = "0.13.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "20cc960326ece64f010d2d2107537f26dc589a6573a316bd5b1dba685fa5fde4" +checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a" dependencies = [ "zstd-safe", ] [[package]] name = "zstd-safe" -version = "5.0.2+zstd.1.5.2" +version = "7.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1d2a5585e04f9eea4b2a3d1eca508c4dee9592a89ef6f450c11719da0726f4db" +checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d" dependencies = [ - "libc", "zstd-sys", ] [[package]] name = "zstd-sys" -version = "2.0.9+zstd.1.5.5" +version = "2.0.16+zstd.1.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e16efa8a874a0481a574084d34cc26fdb3b99627480f785888deb6386506656" +checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748" dependencies = [ "cc", "pkg-config", diff --git a/clients/js/.npmrc b/clients/js/.npmrc new file mode 100644 index 00000000..865aaa9f --- /dev/null +++ b/clients/js/.npmrc @@ -0,0 +1 @@ +only-built-dependencies[]="" \ No newline at end of file diff --git a/clients/js/package.json b/clients/js/package.json index 2e3f9428..e31ecb13 100644 --- a/clients/js/package.json +++ b/clients/js/package.json @@ -1,6 +1,6 @@ { "name": "@metaplex-foundation/mpl-core", - "version": "1.2.0", + "version": "1.9.0", "description": "Digital Assets", "main": "dist/src/index.js", "types": "dist/src/index.d.ts", @@ -26,7 +26,7 @@ "author": "Metaplex Maintainers ", "license": "Apache-2.0", "peerDependencies": { - "@metaplex-foundation/umi": ">=0.8.2 <= 1.0", + "@metaplex-foundation/umi": ">=0.8.2 <2.0.0", "@noble/hashes": "^1.3.1" }, "dependencies": { @@ -35,10 +35,11 @@ "devDependencies": { "@ava/typescript": "^5.0.0", "@metaplex-foundation/mpl-core-oracle-example": "^0.0.2", - "@metaplex-foundation/mpl-toolbox": "^0.8.0", - "@metaplex-foundation/umi": "^1.0.0", - "@metaplex-foundation/umi-bundle-tests": "^1.0.0", - "@solana/web3.js": "^1.73.0", + "@solana/web3.js": "^1.98.2", + "@types/node": "^24.0.3", + "@metaplex-foundation/mpl-toolbox": "^0.10.0", + "@metaplex-foundation/umi": "^1.2.0", + "@metaplex-foundation/umi-bundle-tests": "^1.2.0", "@typescript-eslint/eslint-plugin": "^5.0.0", "@typescript-eslint/parser": "^5.46.1", "ava": "^6.1.3", @@ -57,6 +58,7 @@ "vercel": "^28.16.0" }, "ava": { + "concurrency": 2, "typescript": { "compile": false, "rewritePaths": { @@ -66,5 +68,5 @@ } } }, - "packageManager": "pnpm@8.2.0" + "packageManager": "pnpm@8.9.0" } diff --git a/clients/js/pnpm-lock.yaml b/clients/js/pnpm-lock.yaml index f5f2eb2e..7ef03156 100644 --- a/clients/js/pnpm-lock.yaml +++ b/clients/js/pnpm-lock.yaml @@ -1,12 +1,19 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +onlyBuiltDependencies: + - '' + dependencies: '@msgpack/msgpack': specifier: ^3.0.0-beta2 - version: 3.0.0-beta2 + version: 3.1.2 '@noble/hashes': specifier: ^1.3.1 - version: 1.3.1 + version: 1.8.0 devDependencies: '@ava/typescript': @@ -14,67 +21,70 @@ devDependencies: version: 5.0.0 '@metaplex-foundation/mpl-core-oracle-example': specifier: ^0.0.2 - version: 0.0.2(@metaplex-foundation/umi@1.0.0)(@noble/hashes@1.3.1) + version: 0.0.2(@metaplex-foundation/umi@1.2.0)(@noble/hashes@1.8.0) '@metaplex-foundation/mpl-toolbox': - specifier: ^0.8.0 - version: 0.8.0(@metaplex-foundation/umi@1.0.0) + specifier: ^0.10.0 + version: 0.10.0(@metaplex-foundation/umi@1.2.0) '@metaplex-foundation/umi': - specifier: ^1.0.0 - version: 1.0.0 + specifier: ^1.2.0 + version: 1.2.0 '@metaplex-foundation/umi-bundle-tests': - specifier: ^1.0.0 - version: 1.0.0(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0) + specifier: ^1.2.0 + version: 1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2) '@solana/web3.js': - specifier: ^1.73.0 - version: 1.73.0 + specifier: ^1.98.2 + version: 1.98.2(typescript@4.9.5) + '@types/node': + specifier: ^24.0.3 + version: 24.0.14 '@typescript-eslint/eslint-plugin': specifier: ^5.0.0 - version: 5.0.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1)(typescript@4.9.4) + version: 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1)(typescript@4.9.5) '@typescript-eslint/parser': specifier: ^5.46.1 - version: 5.46.1(eslint@8.0.1)(typescript@4.9.4) + version: 5.62.0(eslint@8.57.1)(typescript@4.9.5) ava: specifier: ^6.1.3 - version: 6.1.3(@ava/typescript@5.0.0) + version: 6.4.1(@ava/typescript@5.0.0) bs58: specifier: 5.0.0 version: 5.0.0 eslint: specifier: ^8.0.1 - version: 8.0.1 + version: 8.57.1 eslint-config-airbnb-typescript: specifier: ^17.0.0 - version: 17.0.0(@typescript-eslint/eslint-plugin@5.0.0)(@typescript-eslint/parser@5.46.1)(eslint-plugin-import@2.26.0)(eslint@8.0.1) + version: 17.1.0(@typescript-eslint/eslint-plugin@5.62.0)(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.32.0)(eslint@8.57.1) eslint-config-prettier: specifier: ^8.5.0 - version: 8.5.0(eslint@8.0.1) + version: 8.10.0(eslint@8.57.1) eslint-plugin-import: specifier: ^2.26.0 - version: 2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1) + version: 2.32.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1) eslint-plugin-prettier: specifier: ^4.2.1 - version: 4.2.1(eslint-config-prettier@8.5.0)(eslint@8.0.1)(prettier@3.2.5) + version: 4.2.1(eslint-config-prettier@8.10.0)(eslint@8.57.1)(prettier@3.6.2) prettier: specifier: ^3.2.5 - version: 3.2.5 + version: 3.6.2 rimraf: specifier: ^3.0.2 version: 3.0.2 typedoc: specifier: ^0.23.16 - version: 0.23.16(typescript@4.9.4) + version: 0.23.28(typescript@4.9.5) typedoc-plugin-expand-object-like-types: specifier: ^0.1.1 - version: 0.1.1(typedoc@0.23.16) + version: 0.1.2(typedoc@0.23.28) typedoc-plugin-missing-exports: specifier: ^1.0.0 - version: 1.0.0(typedoc@0.23.16) + version: 1.0.0(typedoc@0.23.28) typescript: specifier: ^4.9.4 - version: 4.9.4 + version: 4.9.5 vercel: specifier: ^28.16.0 - version: 28.16.0(@types/node@14.18.33) + version: 28.20.0(@types/node@24.0.14) packages: @@ -82,8 +92,8 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} dependencies: - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 dev: true /@ava/typescript@5.0.0: @@ -94,36 +104,36 @@ packages: execa: 8.0.1 dev: true - /@babel/code-frame@7.26.2: - resolution: {integrity: sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==} + /@babel/code-frame@7.27.1: + resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-validator-identifier': 7.27.1 js-tokens: 4.0.0 picocolors: 1.1.1 dev: true - /@babel/compat-data@7.26.8: - resolution: {integrity: sha512-oH5UPLMWR3L2wEFLnFJ1TZXqHufiTKAiLfqw5zkhS4dKXLJ10yVztfil/twG8EDTA4F/tvVNw9nOl4ZMslB8rQ==} + /@babel/compat-data@7.28.0: + resolution: {integrity: sha512-60X7qkglvrap8mn1lh2ebxXdZYtUcpd7gsmy9kLaBJ4i/WdY8PqTSdxyA8qraikqKQK5C1KRBKXqznrVapyNaw==} engines: {node: '>=6.9.0'} dev: true - /@babel/core@7.26.9: - resolution: {integrity: sha512-lWBYIrF7qK5+GjY5Uy+/hEgp8OJWOD/rpy74GplYRhEauvbHDeFB8t5hPOZxCZ0Oxf4Cc36tK51/l3ymJysrKw==} + /@babel/core@7.28.0: + resolution: {integrity: sha512-UlLAnTPrFdNGoFtbSXwcGFQBtQZJCNjaN6hQNP3UPvuNXT1i82N26KL3dZeIpNalWywr9IuQuncaAfUaS1g6sQ==} engines: {node: '>=6.9.0'} dependencies: '@ampproject/remapping': 2.3.0 - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.9 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) - '@babel/helpers': 7.26.9 - '@babel/parser': 7.26.9 - '@babel/template': 7.26.9 - '@babel/traverse': 7.26.9 - '@babel/types': 7.26.9 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helpers': 7.27.6 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.1 convert-source-map: 2.0.0 - debug: 4.4.0 + debug: 4.4.1 gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 @@ -131,1014 +141,1039 @@ packages: - supports-color dev: true - /@babel/generator@7.26.9: - resolution: {integrity: sha512-kEWdzjOAUMW4hAyrzJ0ZaTOu9OmpyDIQicIh0zg0EEcEkYXZb2TjtBhnHi2ViX7PKwZqF4xwqfAm299/QMP3lg==} + /@babel/generator@7.28.0: + resolution: {integrity: sha512-lJjzvrbEeWrhB4P3QBsH7tey117PjLZnDbLiQEKjQ/fNJTjuq4HSqgFA+UNSwZT8D7dxxbnuSBMsa1lrWzKlQg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/parser': 7.26.9 - '@babel/types': 7.26.9 - '@jridgewell/gen-mapping': 0.3.8 - '@jridgewell/trace-mapping': 0.3.25 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.1 + '@jridgewell/gen-mapping': 0.3.12 + '@jridgewell/trace-mapping': 0.3.29 jsesc: 3.0.2 dev: true - /@babel/helper-annotate-as-pure@7.25.9: - resolution: {integrity: sha512-gv7320KBUFJz1RnylIg5WWYPRXKZ884AGkYpgpWW02TH66Dl+HaC1t1CKd0z3R4b6hdYEcmrNZHUmfCP+1u3/g==} + /@babel/helper-annotate-as-pure@7.27.3: + resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.26.9 + '@babel/types': 7.28.1 dev: true - /@babel/helper-compilation-targets@7.26.5: - resolution: {integrity: sha512-IXuyn5EkouFJscIDuFF5EsiSolseme1s0CZB+QxVugqJLYmKdxI1VfIBOst0SUu4rnk2Z7kqTwmoO1lp3HIfnA==} + /@babel/helper-compilation-targets@7.27.2: + resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/compat-data': 7.26.8 - '@babel/helper-validator-option': 7.25.9 - browserslist: 4.24.4 + '@babel/compat-data': 7.28.0 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.25.1 lru-cache: 5.1.1 semver: 6.3.1 dev: true - /@babel/helper-create-class-features-plugin@7.26.9(@babel/core@7.26.9): - resolution: {integrity: sha512-ubbUqCofvxPRurw5L8WTsCLSkQiVpov4Qx0WMA+jUN+nXBK8ADPlJO1grkFw5CWKC5+sZSOfuGMdX1aI1iT9Sg==} + /@babel/helper-create-class-features-plugin@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-QwGAmuvM17btKU5VqXfb+Giw4JcN0hjuufz3DYnpeVDvZLAObloM77bhMXiqry3Iio+Ai4phVRDwl6WU10+r5A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9) - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.0) + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/traverse': 7.28.0 semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-create-regexp-features-plugin@7.26.3(@babel/core@7.26.9): - resolution: {integrity: sha512-G7ZRb40uUgdKOQqPLjfD12ZmGA54PzqDFUv2BKImnC9QIfGhIHKvVML0oN8IUiDq4iRqpq74ABpvOaerfWdong==} + /@babel/helper-create-regexp-features-plugin@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-uVDC72XVf8UbrH5qQTc18Agb8emwjTiZrQE11Nv3CuBEZmVvTwwE9CBUEvHku06gQCAyYf8Nv6ja1IN+6LMbxQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-annotate-as-pure': 7.25.9 + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 regexpu-core: 6.2.0 semver: 6.3.1 dev: true - /@babel/helper-define-polyfill-provider@0.6.3(@babel/core@7.26.9): - resolution: {integrity: sha512-HK7Bi+Hj6H+VTHA3ZvBis7V/6hu9QuTrnMXNybfUf2iiuU/N97I8VjB+KbhFF8Rld/Lx5MzoCwPCpPjfK+n8Cg==} + /@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.0): + resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - debug: 4.4.0 + '@babel/core': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + debug: 4.4.1 lodash.debounce: 4.0.8 resolve: 1.22.10 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-member-expression-to-functions@7.25.9: - resolution: {integrity: sha512-wbfdZ9w5vk0C0oyHqAJbc62+vet5prjj01jjJ8sKn3j9h3MQQlflEdXYvuqRWjHnM12coDEqiC1IRCi0U/EKwQ==} + /@babel/helper-globals@7.28.0: + resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + engines: {node: '>=6.9.0'} + dev: true + + /@babel/helper-member-expression-to-functions@7.27.1: + resolution: {integrity: sha512-E5chM8eWjTp/aNoVpcbfM7mLxu9XGLWYise2eBKGQomAk/Mb4XoxyqXTZbuTohbsl8EKqdlMhnDI2CCLfcs9wA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/traverse': 7.26.9 - '@babel/types': 7.26.9 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.1 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-module-imports@7.25.9: - resolution: {integrity: sha512-tnUA4RsrmflIM6W6RFTLFSXITtl0wKjgpnLgXyowocVPrbYrLUXSBXDgTs8BlbmIzIdlBySRQjINYs2BAkiLtw==} + /@babel/helper-module-imports@7.27.1: + resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} dependencies: - '@babel/traverse': 7.26.9 - '@babel/types': 7.26.9 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.1 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-module-transforms@7.26.0(@babel/core@7.26.9): - resolution: {integrity: sha512-xO+xu6B5K2czEnQye6BHA7DolFFmS3LB7stHZFaOLb1pAwO1HWLS8fXA+eh0A2yIvltPVmx3eNNDBJA2SLHXFw==} + /@babel/helper-module-transforms@7.27.3(@babel/core@7.28.0): + resolution: {integrity: sha512-dSOvYwvyLsWBeIRyOeHXp5vPj5l1I011r52FM1+r1jCERv+aFXYk4whgQccYEGYxK2H3ZAIA8nuPkQ0HaUo3qg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-optimise-call-expression@7.25.9: - resolution: {integrity: sha512-FIpuNaz5ow8VyrYcnXQTDRGvV6tTjkNtCK/RYNDXGSLlUD6cBuQTSw43CShGxjvfBTfcUA/r6UhUCbtYqkhcuQ==} + /@babel/helper-optimise-call-expression@7.27.1: + resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.26.9 + '@babel/types': 7.28.1 dev: true - /@babel/helper-plugin-utils@7.26.5: - resolution: {integrity: sha512-RS+jZcRdZdRFzMyr+wcsaqOmld1/EqTghfaBGQQd/WnRdzdlvSZ//kF7U8VQTxf1ynZ4cjUcYgjVGx13ewNPMg==} + /@babel/helper-plugin-utils@7.27.1: + resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-remap-async-to-generator@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-IZtukuUeBbhgOcaW2s06OXTzVNJR0ybm4W5xC1opWFFJMZbwRj5LCk+ByYH7WdZPZTt8KnFwA8pvjN2yqcPlgw==} + /@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-wrap-function': 7.25.9 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-wrap-function': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-replace-supers@7.26.5(@babel/core@7.26.9): - resolution: {integrity: sha512-bJ6iIVdYX1YooY2X7w1q6VITt+LnUILtNk7zT78ykuwStx8BauCzxvFqFaHjOpW1bVnSUM1PN1f0p5P21wHxvg==} + /@babel/helper-replace-supers@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-member-expression-to-functions': 7.25.9 - '@babel/helper-optimise-call-expression': 7.25.9 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-member-expression-to-functions': 7.27.1 + '@babel/helper-optimise-call-expression': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-skip-transparent-expression-wrappers@7.25.9: - resolution: {integrity: sha512-K4Du3BFa3gvyhzgPcntrkDgZzQaq6uozzcpGbOO1OEJaI+EJdqWIMTLgFgQf6lrfiDFo5FU+BxKepI9RmZqahA==} + /@babel/helper-skip-transparent-expression-wrappers@7.27.1: + resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/traverse': 7.26.9 - '@babel/types': 7.26.9 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.1 transitivePeerDependencies: - supports-color dev: true - /@babel/helper-string-parser@7.25.9: - resolution: {integrity: sha512-4A/SCr/2KLd5jrtOMFzaKjVtAei3+2r/NChoBNoZ3EyP/+GlhoaEGoWOZUmFmoITP7zOJyHIMm+DYRd8o3PvHA==} + /@babel/helper-string-parser@7.27.1: + resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-identifier@7.25.9: - resolution: {integrity: sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==} + /@babel/helper-validator-identifier@7.27.1: + resolution: {integrity: sha512-D2hP9eA+Sqx1kBZgzxZh0y1trbuU+JoDkiEwqhQ36nodYqJwyEIhPSdMNd7lOm/4io72luTPWH20Yda0xOuUow==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-validator-option@7.25.9: - resolution: {integrity: sha512-e/zv1co8pp55dNdEcCynfj9X7nyUKUXoUEwfXqaZt0omVOmDe9oOTdKStH4GmAw6zxMFs50ZayuMfHDKlO7Tfw==} + /@babel/helper-validator-option@7.27.1: + resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} dev: true - /@babel/helper-wrap-function@7.25.9: - resolution: {integrity: sha512-ETzz9UTjQSTmw39GboatdymDq4XIQbR8ySgVrylRhPOFpsd+JrKHIuF0de7GCWmem+T4uC5z7EZguod7Wj4A4g==} + /@babel/helper-wrap-function@7.27.1: + resolution: {integrity: sha512-NFJK2sHUvrjo8wAU/nQTWU890/zB2jj0qBcCbZbbf+005cAsv6tMjXz31fBign6M5ov1o0Bllu+9nbqkfsjjJQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.26.9 - '@babel/traverse': 7.26.9 - '@babel/types': 7.26.9 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.1 transitivePeerDependencies: - supports-color dev: true - /@babel/helpers@7.26.9: - resolution: {integrity: sha512-Mz/4+y8udxBKdmzt/UjPACs4G3j5SshJJEFFKxlCGPydG4JAHXxjWjAwjd09tf6oINvl1VfMJo+nB7H2YKQ0dA==} + /@babel/helpers@7.27.6: + resolution: {integrity: sha512-muE8Tt8M22638HU31A3CgfSUciwz1fhATfoVai05aPXGor//CdWDCbnlY1yvBPo07njuVOCNGCSp/GTt12lIug==} engines: {node: '>=6.9.0'} dependencies: - '@babel/template': 7.26.9 - '@babel/types': 7.26.9 + '@babel/template': 7.27.2 + '@babel/types': 7.28.1 dev: true - /@babel/parser@7.26.9: - resolution: {integrity: sha512-81NWa1njQblgZbQHxWHpxxCzNsa3ZwvFqpUg7P+NNUU6f3UU2jBEg4OlF/J6rl8+PQGh1q6/zWScd001YwcA5A==} + /@babel/parser@7.28.0: + resolution: {integrity: sha512-jVZGvOxOuNSsuQuLRTh13nU0AogFlw32w/MT+LV6D3sP5WdbW61E77RnkbaO2dUvmPAYrBDJXGn5gGS6tH4j8g==} engines: {node: '>=6.0.0'} hasBin: true dependencies: - '@babel/types': 7.26.9 + '@babel/types': 7.28.1 dev: true - /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-ZkRyVkThtxQ/J6nv3JFYv1RYY+JT5BvU0y3k5bWrmuG4woXypRa4PXmm9RhOwodRkYFWqC0C0cqcJ4OqR7kW+g==} + /@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-QPG3C9cCVRQLxAVwmefEmwdTanECuUBMQZ/ym5kiw3XKCGA7qkuQLcjWWHcrD/GKbn/WmJwaezfuuAOcyKlRPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-bugfix-safari-class-field-initializer-scope@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-MrGRLZxLD/Zjj0gdU15dfs+HH/OXvnw/U4jJD8vpcP2CJQapPEv1IWwjc/qMg7ItBlPwSv1hRBbb7LeuANdcnw==} + /@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-2qUwwfAFpJLZqxd02YW9btUCZHl+RFvdDkNfZwaIJrvB8Tesjsk8pEQkTvGwZXLqXUx/2oyY3ySRhm6HOXuCug==} + /@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-6xWgLZTJXwilVjlnV7ospI3xi+sl8lN8rXXbBD6vYn3UYDlGsag8wrZkKcSI8G6KgqKP7vNFaDgeDnfAABq61g==} + /@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.9) + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-aLnMXYPnzwwqhYSCyXfKkIkYgJ8zv9RK+roo9DkTXz38ynIhd9XCbN08s3MGvqL2MYGVUGdRQLL/JqBIeJhJBg==} + /@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-6BpaYGDavZqkI6yT+KSPdpZFfpnd68UKXbcjI9pJ13pvHhPrCKWOOLp+ysvMeA+DxnhuPpgIaRpxRxo5A9t5jw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.9): + /@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.0): resolution: {integrity: sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 + '@babel/core': 7.28.0 dev: true - /@babel/plugin-syntax-import-assertions@7.26.0(@babel/core@7.26.9): - resolution: {integrity: sha512-QCWT5Hh830hK5EQa7XzuqIkQU9tT/whqbDz7kuaZMHFl1inRRg7JnuAEOQ0Ur0QUl0NufCk1msK2BeY79Aj/eg==} + /@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-syntax-import-attributes@7.26.0(@babel/core@7.26.9): - resolution: {integrity: sha512-e2dttdsJ1ZTpi3B9UYGLw41hifAubg19AtCu/2I/F1QNVclOBr1dYpTdmdyZ84Xiz43BS/tCUkMAZNLv12Pi+A==} + /@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-syntax-jsx@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-ld6oezHQMZsZfp6pWtbjaNDF2tiiCYYDqQszHt5VV437lewP9aSi2Of99CK0D0XB21k7FLgnLcmQKyKzynfeAA==} + /@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-syntax-typescript@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-hjMgRy5hb8uJJjUcdWunWVcoi9bGpJp8p5Ol1229PoN6aytsLwNMgmdftO23wnCLMfVmTwZDWMPNq/D1SY60JQ==} + /@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.26.9): + /@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.0): resolution: {integrity: sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-arrow-functions@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-6jmooXYIwn9ca5/RylZADJ+EnSxVUS5sjeJ9UPk6RWRzXCmOJCy6dqItPJFpw2cuCangPK4OYr5uhGKcmrm5Qg==} + /@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-async-generator-functions@7.26.8(@babel/core@7.26.9): - resolution: {integrity: sha512-He9Ej2X7tNf2zdKMAGOsmg2MrFc+hfoAhd3po4cWfo/NWjzEAKa0oQruj1ROVUdl0e6fb6/kE/G3SSxE0lRJOg==} + /@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.9) - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.0) + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-async-to-generator@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-NT7Ejn7Z/LjUH0Gv5KsBCxh7BH3fbLTV0ptHvpeMvrt3cPThHfJfst9Wrb7S8EvJ7vRTFI7z+VAvFVEQn/m5zQ==} + /@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-module-imports': 7.25.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-remap-async-to-generator': 7.25.9(@babel/core@7.26.9) + '@babel/core': 7.28.0 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-block-scoped-functions@7.26.5(@babel/core@7.26.9): - resolution: {integrity: sha512-chuTSY+hq09+/f5lMj8ZSYgCFpppV2CbYrhNFJ1BFoXpiWPnnAb7R0MqrafCpN8E1+YRrtM1MXZHJdIx8B6rMQ==} + /@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-block-scoping@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-1F05O7AYjymAtqbsFETboN1NvBdcnzMerO+zlMyJBEz6WkMdejvGWw9p05iTSjC85RLlBseHHQpYaM4gzJkBGg==} + /@babel/plugin-transform-block-scoping@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-gKKnwjpdx5sER/wl0WN0efUBFzF/56YZO0RJrSYP4CljXnP31ByY7fol89AzomdlLNzI36AvOTmYHsnZTCkq8Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-class-properties@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-bbMAII8GRSkcd0h0b4X+36GksxuheLFjP65ul9w6C3KgAamI3JqErNgSrosX6ZPj+Mpim5VvEbawXxJCyEUV3Q==} + /@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-class-static-block@7.26.0(@babel/core@7.26.9): - resolution: {integrity: sha512-6J2APTs7BDDm+UMqP1useWqhcRAXo0WIoVj26N7kPFB6S73Lgvyka4KTZYIxtgYXiN5HTyRObA72N2iu628iTQ==} + /@babel/plugin-transform-class-static-block@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-s734HmYU78MVzZ++joYM+NkJusItbdRcbm+AGRgJCt3iA+yux0QpD9cBVdz3tKyrjVYWRl7j0mHSmv4lhV0aoA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-classes@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-mD8APIXmseE7oZvZgGABDyM34GUmK45Um2TXiBUt7PnuAxrgoSVf123qUzPxEr/+/BHrRn5NMZCdE2m/1F8DGg==} + /@babel/plugin-transform-classes@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-IjM1IoJNw72AZFlj33Cu8X0q2XK/6AaVC3jQu+cgQ5lThWD5ajnuUAml80dqRmOhmPkTH8uAwnpMu9Rvj0LTRA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9) - '@babel/traverse': 7.26.9 - globals: 11.12.0 + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-globals': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.0) + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-computed-properties@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-HnBegGqXZR12xbcTHlJ9HGxw1OniltT26J5YpfruGqtUHlz/xKf/G2ak9e+t0rVqrjXa9WOhvYPz1ERfMj23AA==} + /@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/template': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/template': 7.27.2 dev: true - /@babel/plugin-transform-destructuring@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-WkCGb/3ZxXepmMiX101nnGiU+1CAdut8oHyEOHxkKuS1qKpU2SMXE2uSvfz8PBuLd49V6LEsbtyPhWC7fnkgvQ==} + /@babel/plugin-transform-destructuring@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-v1nrSMBiKcodhsyJ4Gf+Z0U/yawmJDBOTpEB3mcQY52r9RIyPneGyAS/yM6seP/8I+mWI3elOMtT5dB8GJVs+A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.0 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-dotall-regex@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-t7ZQ7g5trIgSRYhI9pIJtRl64KHotutUJsh4Eze5l7olJv+mRSg4/MmbZ0tv1eeqRbdvo/+trvJD/Oc5DmW2cA==} + /@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-duplicate-keys@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-LZxhJ6dvBb/f3x8xwWIuyiAHy56nrRG3PeYTpBkkzkYRRQ6tJLu68lEF5VIqMUZiAV7a8+Tb78nEoMCMcqjXBw==} + /@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-0UfuJS0EsXbRvKnwcLjFtJy/Sxc5J5jhLHnFhy7u4zih97Hz6tJkLU+O+FMMrNZrosUPxDi6sYxJ/EA8jDiAog==} + /@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-dynamic-import@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-GCggjexbmSLaFhqsojeugBpeaRIgWNTcgKVq/0qIteFEqY2A+b9QidYadrWlnbWQUrW5fn+mCvf3tr7OeBFTyg==} + /@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-exponentiation-operator@7.26.3(@babel/core@7.26.9): - resolution: {integrity: sha512-7CAHcQ58z2chuXPWblnn1K6rLDnDWieghSOEmqQsrBenH0P9InCUtOJYD89pvngljmZlJcz3fcmgYsXFNGa1ZQ==} + /@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.0) + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-export-namespace-from@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-2NsEz+CxzJIVOPx2o9UsW1rXLqtChtLoVnwYHHiB04wS5sgn7mrV45fWMBX0Kk+ub9uXytVYfNP2HjbVbCB3Ww==} + /@babel/plugin-transform-exponentiation-operator@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-uspvXnhHvGKf2r4VVtBpeFnuDWsJLQ6MF6lGJLC89jBR1uoVeqM416AZtTuhTezOfgHicpJQmoD5YUakO/YmXQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-for-of@7.26.9(@babel/core@7.26.9): - resolution: {integrity: sha512-Hry8AusVm8LW5BVFgiyUReuoGzPUpdHQQqJY5bZnbbf+ngOHWuCuYFKw/BqaaWlvEUrF91HMhDtEaI1hZzNbLg==} + /@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + dev: true + + /@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-function-name@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-8lP+Yxjv14Vc5MuWBpJsoUCd3hD6V9DgBon2FVYL4jJgbnVQ9fTgYmonchzZJOVNgzEgbxp4OwAf6xz6M/14XA==} + /@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-json-strings@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-xoTMk0WXceiiIvsaquQQUaLLXSW1KJ159KP87VilruQm0LNNGxWzahxSS6T6i4Zg3ezp4vA4zuwiNUR53qmQAw==} + /@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-literals@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-9N7+2lFziW8W9pBl2TzaNht3+pgMIRP74zizeCSrtnSKVdUl8mAjjOP2OOVQAfZ881P2cNjDj1uAMEdeD50nuQ==} + /@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-logical-assignment-operators@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-wI4wRAzGko551Y8eVf6iOY9EouIDTtPb0ByZx+ktDGHwv6bHFimrgJM/2T021txPZ2s4c7bqvHbd+vXG6K948Q==} + /@babel/plugin-transform-logical-assignment-operators@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-SJvDs5dXxiae4FbSL1aBJlG4wvl594N6YEVVn9e3JGulwioy6z3oPjx/sQBO3Y4NwUu5HNix6KJ3wBZoewcdbw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-member-expression-literals@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-PYazBVfofCQkkMzh2P6IdIUaCEWni3iYEerAsRWuVd8+jlM1S9S9cz1dF9hIzyoZ8IA3+OwVYIp9v9e+GbgZhA==} + /@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-modules-amd@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-g5T11tnI36jVClQlMlt4qKDLlWnG5pP9CSM4GhdRciTNMRgkfpo5cR6b4rGIOYPgRRuFAvwjPQ/Yk+ql4dyhbw==} + /@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-modules-commonjs@7.26.3(@babel/core@7.26.9): - resolution: {integrity: sha512-MgR55l4q9KddUDITEzEFYn5ZsGDXMSsU9E+kh7fjRXTIC3RHqfCo8RPRbyReYJh44HQ/yomFkqbOFohXvDCiIQ==} + /@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-modules-systemjs@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-hyss7iIlH/zLHaehT+xwiymtPOpsiwIIRlCAOwBB04ta5Tt+lNItADdlXw3jAWZ96VJ2jlhl/c+PNIQPKNfvcA==} + /@babel/plugin-transform-modules-systemjs@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-w5N1XzsRbc0PQStASMksmUeqECuzKuTJer7kFagK8AXgpCMkeDMO5S+aaFb7A51ZYDF7XI34qsTX+fkHiIm5yA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-validator-identifier': 7.25.9 - '@babel/traverse': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 + '@babel/traverse': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-modules-umd@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-bS9MVObUgE7ww36HEfwe6g9WakQ0KF07mQF74uuXdkoziUPfKyu/nIm663kz//e5O1nPInPFx36z7WJmJ4yNEw==} + /@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-module-transforms': 7.26.0(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-module-transforms': 7.27.3(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-named-capturing-groups-regex@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-oqB6WHdKTGl3q/ItQhpLSnWWOpjUJLsOCLVyeFgeTktkBSCiurvPOsyt93gibI9CmuKvTUEtWmG5VhZD+5T/KA==} + /@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-new-target@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-U/3p8X1yCSoKyUj2eOBIx3FOn6pElFOKvAAGf8HTtItuPyB+ZeOqfn+mvTtg9ZlOAjsPdK3ayQEjqHjU/yLeVQ==} + /@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-nullish-coalescing-operator@7.26.6(@babel/core@7.26.9): - resolution: {integrity: sha512-CKW8Vu+uUZneQCPtXmSBUC6NCAUdya26hWCElAWh5mVSlSRsmiCPUUDKb3Z0szng1hiAJa098Hkhg9o4SE35Qw==} + /@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-numeric-separator@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-TlprrJ1GBZ3r6s96Yq8gEQv82s8/5HnCVHtEJScUj90thHQbwe+E5MLhi2bbNHBEJuzrvltXSru+BUxHDoog7Q==} + /@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-object-rest-spread@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-fSaXafEE9CVHPweLYw4J0emp1t8zYTXyzN3UuG+lylqkvYd7RMrsOQ8TYx5RF231be0vqtFC6jnx3UmpJmKBYg==} + /@babel/plugin-transform-object-rest-spread@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-9VNGikXxzu5eCiQjdE4IZn8sb9q7Xsk5EXLDBKUYg1e/Tve8/05+KJEtcxGxAgCY5t/BpKQM+JEL/yT4tvgiUA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.9) + '@babel/core': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.0) + '@babel/traverse': 7.28.0 + transitivePeerDependencies: + - supports-color dev: true - /@babel/plugin-transform-object-super@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-Kj/Gh+Rw2RNLbCK1VAWj2U48yxxqL2x0k10nPtSdRa0O2xnHXalD0s+o1A6a0W43gJ00ANo38jxkQreckOzv5A==} + /@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-replace-supers': 7.26.5(@babel/core@7.26.9) + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-optional-catch-binding@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-qM/6m6hQZzDcZF3onzIhZeDHDO43bkNNlOX0i8n3lR6zLbu0GN2d8qfM/IERJZYauhAHSLHy39NF0Ctdvcid7g==} + /@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-optional-chaining@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-6AvV0FsLULbpnXeBjrY4dmWF8F7gf8QnvTEoO/wX/5xm/xE1Xo8oPuD3MPS+KS9f9XBEAWN7X1aWr4z9HdOr7A==} + /@babel/plugin-transform-optional-chaining@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-BQmKPPIuc8EkZgNKsv0X4bPmOoayeu4F1YCwx2/CfmDSXDbp7GnzlUH+/ul5VGfRg1AoFPsrIThlEBj2xb4CAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-parameters@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-wzz6MKwpnshBAiRmn4jR8LYz/g8Ksg0o80XmwZDlordjwEk9SxBzTWC7F5ef1jhbrbOW2DJ5J6ayRukrJmnr0g==} + /@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.0): + resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-private-methods@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-D/JUozNpQLAPUVusvqMxyvjzllRaF8/nSrP1s2YGQT/W4LHK4xxsMcHjhOGTS01mp9Hda8nswb+FblLdJornQw==} + /@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-private-property-in-object@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-Evf3kcMqzXA3xfYJmZ9Pg1OvKdtqsDMSWBDzZOPLvHiTt36E75jLDQo5w1gtRU95Q4E5PDttrTf25Fw8d/uWLw==} + /@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-property-literals@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-IvIUeV5KrS/VPavfSM/Iu+RE6llrHrYIKY1yfCzyO/lMXHQ+p7uGhonmGVisv6tSBSVgWzMBohTcvkC9vQcQFA==} + /@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-regenerator@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-vwDcDNsgMPDGP0nMqzahDWE5/MLcX8sv96+wfX7as7LoF/kr97Bo/7fI00lXY4wUXYfVmwIIyG80fGZ1uvt2qg==} + /@babel/plugin-transform-regenerator@7.28.1(@babel/core@7.28.0): + resolution: {integrity: sha512-P0QiV/taaa3kXpLY+sXla5zec4E+4t4Aqc9ggHlfZ7a2cp8/x/Gv08jfwEtn9gnnYIMvHx6aoOZ8XJL8eU71Dg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - regenerator-transform: 0.15.2 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-regexp-modifiers@7.26.0(@babel/core@7.26.9): - resolution: {integrity: sha512-vN6saax7lrA2yA/Pak3sCxuD6F5InBjn9IcrIKQPjpsLvuHYLVroTxjdlVRHjjBWxKOqIwpTXDkOssYT4BFdRw==} + /@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-reserved-words@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-7DL7DKYjn5Su++4RXu8puKZm2XBPHyjWLUidaPEkCUBbE7IPcsrkRHggAOOKydH1dASWdcUBxrkOGNxUv5P3Jg==} + /@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-shorthand-properties@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-MUv6t0FhO5qHnS/W8XCbHmiRWOphNufpE1IVxhK5kuN3Td9FT1x4rx4K42s3RYdMXCXpfWkGSbCSd0Z64xA7Ng==} + /@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-spread@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-oNknIB0TbURU5pqJFVbOOFspVlrpVwo2H1+HUIsVDvp5VauGGDP1ZEvO8Nn5xyMEs3dakajOxlmkNW7kNgSm6A==} + /@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-sticky-regex@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-WqBUSgeVwucYDP9U/xNRQam7xV8W5Zf+6Eo7T2SRVUFlhRiMNFdFz58u0KZmCVVqs2i7SHgpRnAhzRNmKfi2uA==} + /@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-template-literals@7.26.8(@babel/core@7.26.9): - resolution: {integrity: sha512-OmGDL5/J0CJPJZTHZbi2XpO0tyT2Ia7fzpW5GURwdtp2X3fMmN8au/ej6peC/T33/+CRiIpA8Krse8hFGVmT5Q==} + /@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-typeof-symbol@7.26.7(@babel/core@7.26.9): - resolution: {integrity: sha512-jfoTXXZTgGg36BmhqT3cAYK5qkmqvJpvNrPhaK/52Vgjhw4Rq29s9UqpWWV0D6yuRmgiFH/BUVlkl96zJWqnaw==} + /@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-typescript@7.26.8(@babel/core@7.26.9): - resolution: {integrity: sha512-bME5J9AC8ChwA7aEPJ6zym3w7aObZULHhbNLU0bKUhKsAkylkzUdq+0kdymh9rzi8nlNFl2bmldFBCKNJBUpuw==} + /@babel/plugin-transform-typescript@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-4AEiDEBPIZvLQaWlc9liCavE0xRM0dNca41WtBeM3jgFptfUOSG9z0uteLhq6+3rq+WB6jIvUwKDTpXEHPJ2Vg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-annotate-as-pure': 7.25.9 - '@babel/helper-create-class-features-plugin': 7.26.9(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-skip-transparent-expression-wrappers': 7.25.9 - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9) + '@babel/core': 7.28.0 + '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/helper-create-class-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0) transitivePeerDependencies: - supports-color dev: true - /@babel/plugin-transform-unicode-escapes@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-s5EDrE6bW97LtxOcGj1Khcx5AaXwiMmi4toFWRDP9/y0Woo6pXC+iyPu/KuhKtfSrNFd7jJB+/fkOtZy6aIC6Q==} + /@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-unicode-property-regex@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-Jt2d8Ga+QwRluxRQ307Vlxa6dMrYEMZCgGxoPR8V52rxPyldHu3hdlHspxaqYmE7oID5+kB+UKUB/eWS+DkkWg==} + /@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-unicode-regex@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-yoxstj7Rg9dlNn9UQxzk4fcNivwv4nUYz7fYXBaKxvw/lnmPuOm/ikoELygbYq68Bls3D/D+NBPHiLwZdZZ4HA==} + /@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/plugin-transform-unicode-sets-regex@7.25.9(@babel/core@7.26.9): - resolution: {integrity: sha512-8BYqO3GeVNHtx69fdPshN3fnzUNLrWdHhk/icSwigksJGczKSizZ+Z6SBCxTs723Fr5VSNorTIK7a+R2tISvwQ==} + /@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-create-regexp-features-plugin': 7.26.3(@babel/core@7.26.9) - '@babel/helper-plugin-utils': 7.26.5 + '@babel/core': 7.28.0 + '@babel/helper-create-regexp-features-plugin': 7.27.1(@babel/core@7.28.0) + '@babel/helper-plugin-utils': 7.27.1 dev: true - /@babel/preset-env@7.26.9(@babel/core@7.26.9): - resolution: {integrity: sha512-vX3qPGE8sEKEAZCWk05k3cpTAE3/nOYca++JA+Rd0z2NCNzabmYvEiSShKzm10zdquOIAVXsy2Ei/DTW34KlKQ==} + /@babel/preset-env@7.28.0(@babel/core@7.28.0): + resolution: {integrity: sha512-VmaxeGOwuDqzLl5JUkIRM1X2Qu2uKGxHEQWh+cvvbl7JuJRgKGJSfsEF/bUaxFhJl/XAyxBe7q7qSuTbKFuCyg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/compat-data': 7.26.8 - '@babel/core': 7.26.9 - '@babel/helper-compilation-targets': 7.26.5 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.26.9) - '@babel/plugin-syntax-import-assertions': 7.26.0(@babel/core@7.26.9) - '@babel/plugin-syntax-import-attributes': 7.26.0(@babel/core@7.26.9) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.26.9) - '@babel/plugin-transform-arrow-functions': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-async-generator-functions': 7.26.8(@babel/core@7.26.9) - '@babel/plugin-transform-async-to-generator': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-block-scoped-functions': 7.26.5(@babel/core@7.26.9) - '@babel/plugin-transform-block-scoping': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-class-properties': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-class-static-block': 7.26.0(@babel/core@7.26.9) - '@babel/plugin-transform-classes': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-computed-properties': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-destructuring': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-dotall-regex': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-duplicate-keys': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-dynamic-import': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-exponentiation-operator': 7.26.3(@babel/core@7.26.9) - '@babel/plugin-transform-export-namespace-from': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-for-of': 7.26.9(@babel/core@7.26.9) - '@babel/plugin-transform-function-name': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-json-strings': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-literals': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-logical-assignment-operators': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-member-expression-literals': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-modules-amd': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.9) - '@babel/plugin-transform-modules-systemjs': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-modules-umd': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-named-capturing-groups-regex': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-new-target': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-nullish-coalescing-operator': 7.26.6(@babel/core@7.26.9) - '@babel/plugin-transform-numeric-separator': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-object-rest-spread': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-object-super': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-optional-catch-binding': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-optional-chaining': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-parameters': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-private-methods': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-private-property-in-object': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-property-literals': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-regexp-modifiers': 7.26.0(@babel/core@7.26.9) - '@babel/plugin-transform-reserved-words': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-template-literals': 7.26.8(@babel/core@7.26.9) - '@babel/plugin-transform-typeof-symbol': 7.26.7(@babel/core@7.26.9) - '@babel/plugin-transform-unicode-escapes': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-unicode-property-regex': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-unicode-regex': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-unicode-sets-regex': 7.25.9(@babel/core@7.26.9) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.26.9) - babel-plugin-polyfill-corejs2: 0.4.12(@babel/core@7.26.9) - babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.26.9) - babel-plugin-polyfill-regenerator: 0.6.3(@babel/core@7.26.9) - core-js-compat: 3.40.0 + '@babel/compat-data': 7.28.0 + '@babel/core': 7.28.0 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.0) + '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.0) + '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-block-scoping': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-class-static-block': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-classes': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-destructuring': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-exponentiation-operator': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-logical-assignment-operators': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-modules-systemjs': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-object-rest-spread': 7.28.0(@babel/core@7.28.0) + '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-optional-chaining': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.0) + '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-regenerator': 7.28.1(@babel/core@7.28.0) + '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.0) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.0) + babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.0) + babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.0) + babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.0) + core-js-compat: 3.44.0 semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.26.9): + /@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.0): resolution: {integrity: sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==} peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/types': 7.26.9 + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/types': 7.28.1 esutils: 2.0.3 dev: true - /@babel/preset-typescript@7.26.0(@babel/core@7.26.9): - resolution: {integrity: sha512-NMk1IGZ5I/oHhoXEElcm+xUnL/szL6xflkFZmoEU9xj1qSJXpiS7rsspYo92B4DRCDvZn2erT5LdsCeXAKNCkg==} + /@babel/preset-typescript@7.27.1(@babel/core@7.28.0): + resolution: {integrity: sha512-l7WfQfX0WK4M0v2RudjuQK4u99BS6yLHYEmdtVPP7lKV013zr9DygFuWNlnbvQ9LR+LS0Egz/XAvGx5U9MX0fQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-plugin-utils': 7.26.5 - '@babel/helper-validator-option': 7.25.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-transform-modules-commonjs': 7.26.3(@babel/core@7.26.9) - '@babel/plugin-transform-typescript': 7.26.8(@babel/core@7.26.9) + '@babel/core': 7.28.0 + '@babel/helper-plugin-utils': 7.27.1 + '@babel/helper-validator-option': 7.27.1 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-transform-typescript': 7.28.0(@babel/core@7.28.0) transitivePeerDependencies: - supports-color dev: true @@ -1149,43 +1184,41 @@ packages: regenerator-runtime: 0.13.11 dev: true - /@babel/runtime@7.26.9: - resolution: {integrity: sha512-aA63XwOkcl4xxQa3HjPMqOP6LiK0ZDv3mUPYEFXkpHbaFjtGggE1A61FjFzJnB+p7/oy2gA8E+rcBNl/zC1tMg==} + /@babel/runtime@7.27.6: + resolution: {integrity: sha512-vbavdySgbTTrmFE+EsiqUTzlOr5bzlnJtUv9PynGCAKvfQqjIXbvFdumPM/GxMDfyuGMJaJAU6TO4zc1Jf1i8Q==} engines: {node: '>=6.9.0'} - dependencies: - regenerator-runtime: 0.14.1 dev: true - /@babel/template@7.26.9: - resolution: {integrity: sha512-qyRplbeIpNZhmzOysF/wFMuP9sctmh2cFzRAZOn1YapxBsE1i9bJIY586R/WBLfLcmcBlM8ROBiQURnnNy+zfA==} + /@babel/template@7.27.2: + resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.26.2 - '@babel/parser': 7.26.9 - '@babel/types': 7.26.9 + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.0 + '@babel/types': 7.28.1 dev: true - /@babel/traverse@7.26.9: - resolution: {integrity: sha512-ZYW7L+pL8ahU5fXmNbPF+iZFHCv5scFak7MZ9bwaRPLUhHh7QQEMjZUg0HevihoqCM5iSYHN61EyCoZvqC+bxg==} + /@babel/traverse@7.28.0: + resolution: {integrity: sha512-mGe7UK5wWyh0bKRfupsUchrQGqvDbZDbKJw+kcRGSmdHVYrv+ltd0pnpDTVpiTqnaBru9iEvA8pz8W46v0Amwg==} engines: {node: '>=6.9.0'} dependencies: - '@babel/code-frame': 7.26.2 - '@babel/generator': 7.26.9 - '@babel/parser': 7.26.9 - '@babel/template': 7.26.9 - '@babel/types': 7.26.9 - debug: 4.4.0 - globals: 11.12.0 + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.0 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.0 + '@babel/template': 7.27.2 + '@babel/types': 7.28.1 + debug: 4.4.1 transitivePeerDependencies: - supports-color dev: true - /@babel/types@7.26.9: - resolution: {integrity: sha512-Y3IR1cRnOxOCDvMmNiym7XpXQ93iGDDPHx+Zj+NM+rg0fBaShfQLkg+hKPaZCEvg5N/LeCo4+Rj/i3FuJsIQaw==} + /@babel/types@7.28.1: + resolution: {integrity: sha512-x0LvFTekgSX+83TI28Y9wYPUfzrnl2aT5+5QLnO6v7mSJYtEEevuDRN0F0uSHRk1G1IWZC43o00Y0xDDrpBGPQ==} engines: {node: '>=6.9.0'} dependencies: - '@babel/helper-string-parser': 7.25.9 - '@babel/helper-validator-identifier': 7.25.9 + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.27.1 dev: true /@cspotcode/source-map-support@0.8.1: @@ -1195,20 +1228,33 @@ packages: '@jridgewell/trace-mapping': 0.3.9 dev: true - /@edge-runtime/format@1.1.0: - resolution: {integrity: sha512-MkLDDtPhXZIMx83NykdFmOpF7gVWIdd6GBHYb8V/E+PKWvD2pK/qWx9B30oN1iDJ2XBm0SGDjz02S8nDHI9lMQ==} + /@edge-runtime/format@2.0.1: + resolution: {integrity: sha512-aE+9DtBvQyg349srixtXEUNauWtIv5HTKPy8Q9dvG1NvpldVIvvhcDBI+SuvDVM8kQl8phbYnp2NTNloBCn/Yg==} + engines: {node: '>=14'} dev: true /@edge-runtime/primitives@2.0.0: resolution: {integrity: sha512-AXqUq1zruTJAICrllUvZcgciIcEGHdF6KJ3r6FM0n4k8LpFxZ62tPWVIJ9HKm+xt+ncTBUZxwgUaQ73QMUQEKw==} dev: true + /@edge-runtime/primitives@2.1.2: + resolution: {integrity: sha512-SR04SMDybALlhIYIi0hiuEUwIl0b7Sn+RKwQkX6hydg4+AKMzBNDFhj2nqHDD1+xkHArV9EhmJIb6iGjShwSzg==} + engines: {node: '>=14'} + dev: true + /@edge-runtime/vm@2.0.0: resolution: {integrity: sha512-BOLrAX8IWHRXu1siZocwLguKJPEUv7cr+rG8tI4hvHgMdIsBWHJlLeB8EjuUVnIURFrUiM49lVKn8DRrECmngw==} dependencies: '@edge-runtime/primitives': 2.0.0 dev: true + /@edge-runtime/vm@2.1.2: + resolution: {integrity: sha512-j4H5S26NJhYOyjVMN8T/YJuwwslfnEX1P0j6N2Rq1FaubgNowdYunA9nlO7lg8Rgjv6dqJ2zKuM7GD1HFtNSGw==} + engines: {node: '>=14'} + dependencies: + '@edge-runtime/primitives': 2.1.2 + dev: true + /@emotion/hash@0.9.2: resolution: {integrity: sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==} dev: true @@ -1228,7 +1274,6 @@ packages: engines: {node: '>=12'} cpu: [ppc64] os: [aix] - requiresBuild: true dev: true optional: true @@ -1237,7 +1282,6 @@ packages: engines: {node: '>=12'} cpu: [ppc64] os: [aix] - requiresBuild: true dev: true optional: true @@ -1246,7 +1290,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true dev: true optional: true @@ -1255,7 +1298,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true dev: true optional: true @@ -1264,7 +1306,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true dev: true optional: true @@ -1273,7 +1314,6 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [android] - requiresBuild: true dev: true optional: true @@ -1282,7 +1322,6 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [android] - requiresBuild: true dev: true optional: true @@ -1291,7 +1330,6 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [android] - requiresBuild: true dev: true optional: true @@ -1300,7 +1338,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true dev: true optional: true @@ -1309,7 +1346,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true dev: true optional: true @@ -1318,7 +1354,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true dev: true optional: true @@ -1327,7 +1362,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -1336,7 +1370,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -1345,7 +1378,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -1354,7 +1386,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -1363,7 +1394,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -1372,7 +1402,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -1381,7 +1410,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -1390,7 +1418,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -1399,7 +1426,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -1408,7 +1434,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -1417,7 +1442,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -1426,7 +1450,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -1435,7 +1458,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1444,7 +1466,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1453,7 +1474,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1462,7 +1482,6 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true @@ -1471,7 +1490,6 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true @@ -1480,7 +1498,6 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true @@ -1489,7 +1506,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true dev: true optional: true @@ -1498,7 +1514,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true dev: true optional: true @@ -1507,7 +1522,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true dev: true optional: true @@ -1516,7 +1530,6 @@ packages: engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1525,7 +1538,6 @@ packages: engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1534,7 +1546,6 @@ packages: engines: {node: '>=12'} cpu: [loong64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1543,7 +1554,6 @@ packages: engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true dev: true optional: true @@ -1552,7 +1562,6 @@ packages: engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true dev: true optional: true @@ -1561,7 +1570,6 @@ packages: engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true dev: true optional: true @@ -1570,7 +1578,6 @@ packages: engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1579,7 +1586,6 @@ packages: engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1588,7 +1594,6 @@ packages: engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1597,7 +1602,6 @@ packages: engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1606,7 +1610,6 @@ packages: engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1615,7 +1618,6 @@ packages: engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1624,7 +1626,6 @@ packages: engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true dev: true optional: true @@ -1633,7 +1634,6 @@ packages: engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true dev: true optional: true @@ -1642,7 +1642,6 @@ packages: engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true dev: true optional: true @@ -1651,7 +1650,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1660,7 +1658,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1669,7 +1666,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true @@ -1678,7 +1674,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true dev: true optional: true @@ -1687,7 +1682,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true dev: true optional: true @@ -1696,7 +1690,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true dev: true optional: true @@ -1705,7 +1698,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true dev: true optional: true @@ -1714,7 +1706,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true dev: true optional: true @@ -1723,7 +1714,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true dev: true optional: true @@ -1732,7 +1722,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [sunos] - requiresBuild: true dev: true optional: true @@ -1741,7 +1730,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [sunos] - requiresBuild: true dev: true optional: true @@ -1750,7 +1738,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [sunos] - requiresBuild: true dev: true optional: true @@ -1759,7 +1746,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [win32] - requiresBuild: true dev: true optional: true @@ -1768,7 +1754,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [win32] - requiresBuild: true dev: true optional: true @@ -1777,7 +1762,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [win32] - requiresBuild: true dev: true optional: true @@ -1786,7 +1770,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [win32] - requiresBuild: true dev: true optional: true @@ -1795,7 +1778,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [win32] - requiresBuild: true dev: true optional: true @@ -1804,7 +1786,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [win32] - requiresBuild: true dev: true optional: true @@ -1813,7 +1794,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [win32] - requiresBuild: true dev: true optional: true @@ -1822,7 +1802,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [win32] - requiresBuild: true dev: true optional: true @@ -1831,16 +1810,30 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [win32] - requiresBuild: true dev: true optional: true - /@eslint/eslintrc@1.4.1: - resolution: {integrity: sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==} + /@eslint-community/eslint-utils@4.7.0(eslint@8.57.1): + resolution: {integrity: sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + dependencies: + eslint: 8.57.1 + eslint-visitor-keys: 3.4.3 + dev: true + + /@eslint-community/regexpp@4.12.1: + resolution: {integrity: sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + dev: true + + /@eslint/eslintrc@2.1.4: + resolution: {integrity: sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: ajv: 6.12.6 - debug: 4.4.0 + debug: 4.4.1 espree: 9.6.1 globals: 13.24.0 ignore: 5.3.2 @@ -1852,272 +1845,309 @@ packages: - supports-color dev: true + /@eslint/js@8.57.1: + resolution: {integrity: sha512-d9zaMRSTIKDLhctzH12MtXvJKSSUhaHcjV+2Z+GK+EEY7XKpP5yR4x+N3TAcHTcu963nIr+TMcCb4DBCYX1z6Q==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + dev: true + /@gar/promisify@1.1.3: resolution: {integrity: sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw==} dev: true - /@humanwhocodes/config-array@0.6.0: - resolution: {integrity: sha512-JQlEKbcgEUjBFhLIF4iqM7u/9lwgHRBcpHrmUNCALK0Q3amXN6lxdoXLnF0sm11E9VqTmBALR87IlUg1bZ8A9A==} + /@humanwhocodes/config-array@0.13.0: + resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==} engines: {node: '>=10.10.0'} deprecated: Use @eslint/config-array instead dependencies: - '@humanwhocodes/object-schema': 1.2.1 - debug: 4.4.0 + '@humanwhocodes/object-schema': 2.0.3 + debug: 4.4.1 minimatch: 3.1.2 transitivePeerDependencies: - supports-color dev: true - /@humanwhocodes/object-schema@1.2.1: - resolution: {integrity: sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==} + /@humanwhocodes/module-importer@1.0.1: + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + dev: true + + /@humanwhocodes/object-schema@2.0.3: + resolution: {integrity: sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==} deprecated: Use @eslint/object-schema instead dev: true - /@jridgewell/gen-mapping@0.3.8: - resolution: {integrity: sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==} - engines: {node: '>=6.0.0'} + /@isaacs/cliui@8.0.2: + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} dependencies: - '@jridgewell/set-array': 1.2.1 - '@jridgewell/sourcemap-codec': 1.5.0 - '@jridgewell/trace-mapping': 0.3.25 + string-width: 5.1.2 + string-width-cjs: /string-width@4.2.3 + strip-ansi: 7.1.0 + strip-ansi-cjs: /strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: /wrap-ansi@7.0.0 dev: true - /@jridgewell/resolve-uri@3.1.2: - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} + /@isaacs/fs-minipass@4.0.1: + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} + dependencies: + minipass: 7.1.2 dev: true - /@jridgewell/set-array@1.2.1: - resolution: {integrity: sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==} + /@jridgewell/gen-mapping@0.3.12: + resolution: {integrity: sha512-OuLGC46TjB5BbN1dH8JULVVZY4WTdkF7tV9Ys6wLL1rubZnCMstOhNHueU5bLCrnRuDhKPDM4g6sw4Bel5Gzqg==} + dependencies: + '@jridgewell/sourcemap-codec': 1.5.4 + '@jridgewell/trace-mapping': 0.3.29 + dev: true + + /@jridgewell/resolve-uri@3.1.2: + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} dev: true - /@jridgewell/sourcemap-codec@1.5.0: - resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + /@jridgewell/sourcemap-codec@1.5.4: + resolution: {integrity: sha512-VT2+G1VQs/9oz078bLrYbecdZKs912zQlkelYpuf+SXF+QvZDYJlbx/LSx+meSAwdDFnF8FVXW92AVjjkVmgFw==} dev: true - /@jridgewell/trace-mapping@0.3.25: - resolution: {integrity: sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==} + /@jridgewell/trace-mapping@0.3.29: + resolution: {integrity: sha512-uw6guiW/gcAGPDhLmd77/6lW8QLeiV5RUTsAX46Db6oLhGaVj4lhnPwb184s1bkc8kdVg/+h988dro8GRDpmYQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.4 dev: true /@jridgewell/trace-mapping@0.3.9: resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.0 + '@jridgewell/sourcemap-codec': 1.5.4 dev: true /@mapbox/node-pre-gyp@1.0.11: resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} hasBin: true dependencies: - detect-libc: 2.0.3 + detect-libc: 2.0.4 https-proxy-agent: 5.0.1 make-dir: 3.1.0 node-fetch: 2.7.0 nopt: 5.0.0 npmlog: 5.0.1 rimraf: 3.0.2 - semver: 7.7.1 + semver: 7.7.2 tar: 6.2.1 transitivePeerDependencies: - encoding - supports-color dev: true - /@metaplex-foundation/mpl-core-oracle-example@0.0.2(@metaplex-foundation/umi@1.0.0)(@noble/hashes@1.3.1): + /@mapbox/node-pre-gyp@2.0.0: + resolution: {integrity: sha512-llMXd39jtP0HpQLVI37Bf1m2ADlEb35GYSh1SDSLsBhR+5iCxiNGlT31yqbNtVHygHAtMy6dWFERpU2JgufhPg==} + engines: {node: '>=18'} + hasBin: true + dependencies: + consola: 3.4.2 + detect-libc: 2.0.4 + https-proxy-agent: 7.0.6 + node-fetch: 2.7.0 + nopt: 8.1.0 + semver: 7.7.2 + tar: 7.4.3 + transitivePeerDependencies: + - encoding + - supports-color + dev: true + + /@metaplex-foundation/mpl-core-oracle-example@0.0.2(@metaplex-foundation/umi@1.2.0)(@noble/hashes@1.8.0): resolution: {integrity: sha512-DxHKLaM04YGMv/EGgIzzxSJnBPv+OTBKeekL7mm7Pcu/DqH+xIuy4K7h9mMhI3E1gSbWIaxtzlbitbvwXvYRcw==} peerDependencies: '@metaplex-foundation/umi': '>=0.8.2 < 1' '@noble/hashes': ^1.3.1 dependencies: - '@metaplex-foundation/umi': 1.0.0 - '@noble/hashes': 1.3.1 + '@metaplex-foundation/umi': 1.2.0 + '@noble/hashes': 1.8.0 dev: true - /@metaplex-foundation/mpl-toolbox@0.8.0(@metaplex-foundation/umi@1.0.0): - resolution: {integrity: sha512-SK1VUPU4hCaL3sozgtoVjjbZxqx2gWiRt0YTFbwEt5LAHWOlCb7J7rcrrA5XwymX4iV2bIWygYs0yz7hYyx2rg==} + /@metaplex-foundation/mpl-toolbox@0.10.0(@metaplex-foundation/umi@1.2.0): + resolution: {integrity: sha512-84KD1L5cFyw5xnntHwL4uPwfcrkKSiwuDeypiVr92qCUFuF3ZENa2zlFVPu+pQcjTlod2LmEX3MhBmNjRMpdKg==} peerDependencies: - '@metaplex-foundation/umi': ^0.8.2 + '@metaplex-foundation/umi': '>= 0.8.2 <= 1' dependencies: - '@metaplex-foundation/umi': 1.0.0 + '@metaplex-foundation/umi': 1.2.0 dev: true - /@metaplex-foundation/umi-bundle-tests@1.0.0(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0): - resolution: {integrity: sha512-i8TvokPZE76YjOI/9ZHnKnRJue9WsrxefUifGWBVUneAIfEmhWrV5UzGNN7Sv+lTK+64NPKH7EuCwdi45LK6UA==} + /@metaplex-foundation/umi-bundle-tests@1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2): + resolution: {integrity: sha512-rmdVjB2nNxTEn/S3FKmg3b8Qlx4cwI6GOvAHX0Njxch1+tC74pedctsNtunTj7w9ijQIzc8UKsbwVMIwI+tq2g==} peerDependencies: - '@metaplex-foundation/umi': ^1.0.0 + '@metaplex-foundation/umi': ^1.2.0 '@solana/web3.js': ^1.72.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 - '@metaplex-foundation/umi-eddsa-web3js': 1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0) - '@metaplex-foundation/umi-http-fetch': 1.1.1(@metaplex-foundation/umi@1.0.0) - '@metaplex-foundation/umi-program-repository': 1.1.1(@metaplex-foundation/umi@1.0.0) - '@metaplex-foundation/umi-rpc-web3js': 1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0) - '@metaplex-foundation/umi-serializer-data-view': 1.1.1(@metaplex-foundation/umi@1.0.0) - '@metaplex-foundation/umi-storage-mock': 1.1.1(@metaplex-foundation/umi@1.0.0) - '@metaplex-foundation/umi-transaction-factory-web3js': 1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0) - '@solana/web3.js': 1.73.0 + '@metaplex-foundation/umi': 1.2.0 + '@metaplex-foundation/umi-eddsa-web3js': 1.1.1(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2) + '@metaplex-foundation/umi-http-fetch': 1.2.0(@metaplex-foundation/umi@1.2.0) + '@metaplex-foundation/umi-program-repository': 1.2.0(@metaplex-foundation/umi@1.2.0) + '@metaplex-foundation/umi-rpc-web3js': 1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2) + '@metaplex-foundation/umi-serializer-data-view': 1.2.0(@metaplex-foundation/umi@1.2.0) + '@metaplex-foundation/umi-storage-mock': 1.2.0(@metaplex-foundation/umi@1.2.0) + '@metaplex-foundation/umi-transaction-factory-web3js': 1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2) + '@solana/web3.js': 1.98.2(typescript@4.9.5) transitivePeerDependencies: - encoding dev: true - /@metaplex-foundation/umi-eddsa-web3js@1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0): + /@metaplex-foundation/umi-eddsa-web3js@1.1.1(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2): resolution: {integrity: sha512-rL22HATY7W02DqJLdBKZ8jedhMtd7iKReIFNPXLGnVeUpDwxXaqWPySZxZ+2TjY6f+Idoq2g2TpPCUGND/iOeA==} peerDependencies: '@metaplex-foundation/umi': 1.1.1 '@solana/web3.js': ^1.72.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 - '@metaplex-foundation/umi-web3js-adapters': 1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0) - '@noble/curves': 1.8.1 - '@solana/web3.js': 1.73.0 - yaml: 2.7.0 + '@metaplex-foundation/umi': 1.2.0 + '@metaplex-foundation/umi-web3js-adapters': 1.1.1(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2) + '@noble/curves': 1.9.4 + '@solana/web3.js': 1.98.2(typescript@4.9.5) + yaml: 2.8.0 dev: true - /@metaplex-foundation/umi-http-fetch@1.1.1(@metaplex-foundation/umi@1.0.0): - resolution: {integrity: sha512-yoGLVZfRBdlAyYzHrTkvCLxh13np8pyAuHmn1+e1nRle6w3DHp86YACeKA635yvhzSKq8inVlaiWt8DK8v9Akw==} + /@metaplex-foundation/umi-http-fetch@1.2.0(@metaplex-foundation/umi@1.2.0): + resolution: {integrity: sha512-rbM97PPCAmjbR90wnSCTxJFkCUIKR++gS5lIm+ZNZ96XrjvOrFURZpSYloyDGvXRNgF44eTYWDYIDLy5zmI2JQ==} peerDependencies: - '@metaplex-foundation/umi': 1.1.1 + '@metaplex-foundation/umi': ^1.2.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 + '@metaplex-foundation/umi': 1.2.0 node-fetch: 2.7.0 transitivePeerDependencies: - encoding dev: true - /@metaplex-foundation/umi-options@1.1.1: - resolution: {integrity: sha512-oOvbnVbF6WIMM4Elr0t7DH+zXkTGuytqUdODuZlsCc8YOHHspn76z+Bl+fMfyYQ/Y1oxVAhjVii9MVdSiUMb7Q==} + /@metaplex-foundation/umi-options@1.2.0: + resolution: {integrity: sha512-dNEfhDg9PUoosU46SnmB8PzdhgAF7qJ0RUkn5keLKU2s0Xy2DKZVtdaELTfMZZckhaDvOzRTKdphTRrEwIjbyw==} dev: true - /@metaplex-foundation/umi-program-repository@1.1.1(@metaplex-foundation/umi@1.0.0): - resolution: {integrity: sha512-rE/mm+GwFRjsYCLRqASWlc/jsx1+KoZPEATkHAHgBC6aKQRHa5wE8L5DKfYKYbuIiXe21ypGoOcA5NJ5l1MUXw==} + /@metaplex-foundation/umi-program-repository@1.2.0(@metaplex-foundation/umi@1.2.0): + resolution: {integrity: sha512-mbsE0BPmqv3cMfk/jn+EKoUDJHbUieFcp8o2eRSkVBJhjXqkfLJgJ8s3koBn8vv5mcmavEBDqPYNqJQs93je0g==} peerDependencies: - '@metaplex-foundation/umi': 1.1.1 + '@metaplex-foundation/umi': ^1.2.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 + '@metaplex-foundation/umi': 1.2.0 dev: true - /@metaplex-foundation/umi-public-keys@1.1.1: - resolution: {integrity: sha512-wboy48lr9vR18IPum9mZ1nSk2bNDfTXKJAon26p6xDZzl3ywGZijOZJwSaDsjPwokKp1Sot1eXd8nrwIdg1Abg==} + /@metaplex-foundation/umi-public-keys@1.2.0: + resolution: {integrity: sha512-UZISKLcrsAQ3M17JCkNIXtacoKHpSNEgXHGcxyJp7zfJkdLDq5Qlvd7KeyZoYC7A7XuA3lAlVY14qhhIwC5p5w==} dependencies: - '@metaplex-foundation/umi-serializers-encodings': 1.1.1 + '@metaplex-foundation/umi-serializers-encodings': 1.2.0 dev: true - /@metaplex-foundation/umi-rpc-web3js@1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0): - resolution: {integrity: sha512-Z03TaNUX1LzbMnUOnvZoHvwYDVJGP8wN7GxSiANKHWRUaSG8qUzp3hyZMDuTq4/KCeO7FSpgInZWDDppJsVftw==} + /@metaplex-foundation/umi-rpc-web3js@1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2): + resolution: {integrity: sha512-nMWJA/v8gnhA3D2iBHSHWyS02YAL9zIhE8gxWufk56GY1fTo/jBp8HQrxI4PZH0E8A1fGnBZSU0SkL4lRm7Ljw==} peerDependencies: - '@metaplex-foundation/umi': 1.1.1 + '@metaplex-foundation/umi': ^1.2.0 '@solana/web3.js': ^1.72.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 - '@metaplex-foundation/umi-web3js-adapters': 1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0) - '@solana/web3.js': 1.73.0 + '@metaplex-foundation/umi': 1.2.0 + '@metaplex-foundation/umi-web3js-adapters': 1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2) + '@solana/web3.js': 1.98.2(typescript@4.9.5) dev: true - /@metaplex-foundation/umi-serializer-data-view@1.1.1(@metaplex-foundation/umi@1.0.0): - resolution: {integrity: sha512-TS61S52CiZvFjXq+ECXHZNB8abJrqTkkwimJKY0K+sMAtMg55Cfck6tkcLDC22KOY2DXESYURXGSl4xxya9iOQ==} + /@metaplex-foundation/umi-serializer-data-view@1.2.0(@metaplex-foundation/umi@1.2.0): + resolution: {integrity: sha512-3w9WQzfrq851cIyvzcbEslJEL4oah3r/9Y/A2zyUwCsri5/3s/G0CcHgHPaS6/cvpyYybqBJjyJKMcGiVxzs8Q==} peerDependencies: - '@metaplex-foundation/umi': 1.1.1 + '@metaplex-foundation/umi': ^1.2.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 + '@metaplex-foundation/umi': 1.2.0 dev: true - /@metaplex-foundation/umi-serializers-core@1.1.1: - resolution: {integrity: sha512-w+0hiOA9tuD7R2EthNiMB01QEeBvFs5Jeegnqjr7z0pfmxWYu2n1J1HkJJcqaPjqyilJ1aOuPZ8lhL3UNhBDjA==} + /@metaplex-foundation/umi-serializers-core@1.2.0: + resolution: {integrity: sha512-9scqhjkjW8tJ+/q1veh73jQjo9vvgTN5iN4OfOYFMtFVTT8/y2AVxGmniV/DbQC5wIgx7WTZkAnJmqOMs2904Q==} dev: true - /@metaplex-foundation/umi-serializers-encodings@1.1.1: - resolution: {integrity: sha512-wDi2MKgfLN9jv6FFxFFkqFYVuRFuaM4HIpKM7Hww6Cdd2zZhbWUatULIfq5aebzxjjNMdjvLPW1+g3BEZPrVsA==} + /@metaplex-foundation/umi-serializers-encodings@1.2.0: + resolution: {integrity: sha512-Yo3TPI9ei8Z5eTJ1UeT12+pYaQ1zMSn57/M/3r4WAOTFtTCOuKsDRKg8eBQCpBuffH8yGUbRs0poy1n25IzeNg==} dependencies: - '@metaplex-foundation/umi-serializers-core': 1.1.1 + '@metaplex-foundation/umi-serializers-core': 1.2.0 dev: true - /@metaplex-foundation/umi-serializers-numbers@1.1.1: - resolution: {integrity: sha512-OkY7k6m9nusBPcFaUulmaw1fs7icc+WUOaq6XK9NXMqHCMRPYOTvr3yLG9iCUI+cRbhpphddtRKFAgPFYoz0mw==} + /@metaplex-foundation/umi-serializers-numbers@1.2.0: + resolution: {integrity: sha512-ZBVb498GHYlfB+1JzOcczJ1LrCYWr0IiiXjeEAf+64mSSp3IFwK7D3rjL6RZ05bjxBzuWDJVRzI+mFVFC9UgtQ==} dependencies: - '@metaplex-foundation/umi-serializers-core': 1.1.1 + '@metaplex-foundation/umi-serializers-core': 1.2.0 dev: true - /@metaplex-foundation/umi-serializers@1.1.1: - resolution: {integrity: sha512-bR3DwA+6N1GMMToZw3C9DvuRQQFYtFOIJRnBDXhBBezpzz2S/imoEMZRaHjWCNdNrZy4x3LZjqcgmO9ynPLpXQ==} + /@metaplex-foundation/umi-serializers@1.2.0: + resolution: {integrity: sha512-7ivgqVP6ZouN13EBN5aMirjoX2x0Ja7IuzrBeIa8YYrxGcy7YQp+fUj4YCPtMClzsETgJ5jL8EZnZPpZX4dxaQ==} dependencies: - '@metaplex-foundation/umi-options': 1.1.1 - '@metaplex-foundation/umi-public-keys': 1.1.1 - '@metaplex-foundation/umi-serializers-core': 1.1.1 - '@metaplex-foundation/umi-serializers-encodings': 1.1.1 - '@metaplex-foundation/umi-serializers-numbers': 1.1.1 + '@metaplex-foundation/umi-options': 1.2.0 + '@metaplex-foundation/umi-public-keys': 1.2.0 + '@metaplex-foundation/umi-serializers-core': 1.2.0 + '@metaplex-foundation/umi-serializers-encodings': 1.2.0 + '@metaplex-foundation/umi-serializers-numbers': 1.2.0 dev: true - /@metaplex-foundation/umi-storage-mock@1.1.1(@metaplex-foundation/umi@1.0.0): - resolution: {integrity: sha512-Gwd/dnm84a4zCKuOg1GYdOOu5dOpSQoldchedLPlkNTUitKb1Uq9k7FoCmOmTfvDyaz7ZMmrTJ1FTN0RTvIqtw==} + /@metaplex-foundation/umi-storage-mock@1.2.0(@metaplex-foundation/umi@1.2.0): + resolution: {integrity: sha512-c2/YO3UnahaKn0n9pnWD9fRSNpyoNUdOLHgauYo/ma3/GBRAVUtMGlDEscP92bu6ubQGp2/+8+gtHVyraddkvg==} peerDependencies: - '@metaplex-foundation/umi': 1.1.1 + '@metaplex-foundation/umi': ^1.2.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 + '@metaplex-foundation/umi': 1.2.0 dev: true - /@metaplex-foundation/umi-transaction-factory-web3js@1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0): - resolution: {integrity: sha512-+orvbvpjGHldpXjy0xQuzRlE6l8+m8xTJEjpruBlkdju8vjd211cPlHj1fTpLroD7jbCBgZGGnQxgxTpLiRWPA==} + /@metaplex-foundation/umi-transaction-factory-web3js@1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2): + resolution: {integrity: sha512-CDpx6KSYOEonWsHJEVUfZTzu3g0ElclUNgeAXhLyKzimS1fd7FvAkbFom6egQz6ZPuqGv/5ZTHQv37UxoGy+Zg==} peerDependencies: - '@metaplex-foundation/umi': 1.1.1 + '@metaplex-foundation/umi': ^1.2.0 '@solana/web3.js': ^1.72.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 - '@metaplex-foundation/umi-web3js-adapters': 1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0) - '@solana/web3.js': 1.73.0 + '@metaplex-foundation/umi': 1.2.0 + '@metaplex-foundation/umi-web3js-adapters': 1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2) + '@solana/web3.js': 1.98.2(typescript@4.9.5) dev: true - /@metaplex-foundation/umi-web3js-adapters@1.1.1(@metaplex-foundation/umi@1.0.0)(@solana/web3.js@1.73.0): + /@metaplex-foundation/umi-web3js-adapters@1.1.1(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2): resolution: {integrity: sha512-UXP2aY3ce59nSxsVJ4sFLtGCHpesqLTxTag2yI6grCXe0dEz+1kONMn0XFRLcYgiSKOcptJSoJWbILlHnUsWDg==} peerDependencies: '@metaplex-foundation/umi': 1.1.1 '@solana/web3.js': ^1.72.0 dependencies: - '@metaplex-foundation/umi': 1.0.0 - '@solana/web3.js': 1.73.0 + '@metaplex-foundation/umi': 1.2.0 + '@solana/web3.js': 1.98.2(typescript@4.9.5) buffer: 6.0.3 dev: true - /@metaplex-foundation/umi@1.0.0: - resolution: {integrity: sha512-kCYwVI4REdDW8SwJGjPkef70t3JBPqkyf6k+zu/tBKUXdGh7jOkbZnUghdXk5GZ2Md+bqh9dtM93u/66N6xcWA==} + /@metaplex-foundation/umi-web3js-adapters@1.2.0(@metaplex-foundation/umi@1.2.0)(@solana/web3.js@1.98.2): + resolution: {integrity: sha512-kKfsva8aoHTZXHbet6U/dV/va+hSFoVpqLiKFoUg3HV2Cp5IgdLXo2PH4/iN6AlE+S+a0S3+jt/7gat2rsskuw==} + peerDependencies: + '@metaplex-foundation/umi': ^1.2.0 + '@solana/web3.js': ^1.72.0 dependencies: - '@metaplex-foundation/umi-options': 1.1.1 - '@metaplex-foundation/umi-public-keys': 1.1.1 - '@metaplex-foundation/umi-serializers': 1.1.1 + '@metaplex-foundation/umi': 1.2.0 + '@solana/web3.js': 1.98.2(typescript@4.9.5) + buffer: 6.0.3 dev: true - /@msgpack/msgpack@3.0.0-beta2: - resolution: {integrity: sha512-y+l1PNV0XDyY8sM3YtuMLK5vE3/hkfId+Do8pLo/OPxfxuFAUwcGz3oiiUuV46/aBpwTzZ+mRWVMtlSKbradhw==} - engines: {node: '>= 14'} - dev: false - - /@noble/curves@1.8.1: - resolution: {integrity: sha512-warwspo+UYUPep0Q+vtdVB4Ugn8GGQj8iyB3gnRWsztmUHTI3S1nhdiWNsPUGL0vud7JlRRk1XEu7Lq1KGTnMQ==} - engines: {node: ^14.21.3 || >=16} + /@metaplex-foundation/umi@1.2.0: + resolution: {integrity: sha512-SIcDO8O9gRYL2C5ntsedVfpRBICK7ZoMB5ap8P5N2TEJ/QC205UxDzhdQsImdWQG1DQ7XJsDXWiiFzccpFZcSg==} dependencies: - '@noble/hashes': 1.7.1 + '@metaplex-foundation/umi-options': 1.2.0 + '@metaplex-foundation/umi-public-keys': 1.2.0 + '@metaplex-foundation/umi-serializers': 1.2.0 dev: true - /@noble/ed25519@1.7.3: - resolution: {integrity: sha512-iR8GBkDt0Q3GyaVcIu7mSsVIqnFbkbRzGLWlvhwunacoLwt4J3swfKhfaM6rN6WY+TBGoYT1GtT1mIh2/jGbRQ==} - dev: true - - /@noble/hashes@1.3.1: - resolution: {integrity: sha512-EbqwksQwz9xDRGfDST86whPBgM65E0OH/pCgqW0GBVzO22bNE+NuIbeTb714+IfSjU3aRk47EUvXIb5bTsenKA==} - engines: {node: '>= 16'} + /@msgpack/msgpack@3.1.2: + resolution: {integrity: sha512-JEW4DEtBzfe8HvUYecLU9e6+XJnKDlUAIve8FvPzF3Kzs6Xo/KuZkZJsDH0wJXl/qEZbeeE7edxDNY3kMs39hQ==} + engines: {node: '>= 18'} + dev: false - /@noble/hashes@1.7.1: - resolution: {integrity: sha512-B8XBPsn4vT/KJAGqDzbwztd+6Yte3P4V7iafm24bxgDe/mlRuK6xmWPuCNrKt2vDafZ8MfJLlchDG/vYafQEjQ==} + /@noble/curves@1.9.4: + resolution: {integrity: sha512-2bKONnuM53lINoDrSmK8qP8W271ms7pygDhZt4SiLOoLwBtoHqeCFi6RG42V8zd3mLHuJFhU/Bmaqo4nX0/kBw==} engines: {node: ^14.21.3 || >=16} + dependencies: + '@noble/hashes': 1.8.0 dev: true - /@noble/secp256k1@1.7.1: - resolution: {integrity: sha512-hOUk6AyBFmqVrv7k5WAw/LpszxVbj9gGN4JRkIX52fdFAj1UA61KXmZDvqVEm+pOyec3+fIeZB02LYa/pWOArw==} - dev: true + /@noble/hashes@1.8.0: + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} /@nodelib/fs.scandir@2.1.5: resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} @@ -2144,7 +2174,7 @@ packages: resolution: {integrity: sha512-8KG5RD0GVP4ydEzRn/I4BNDuxDtqVbOdm8675T49OIG/NGhaK0pjPX7ZcDlvKYbA+ulvVK3ztfcF4uBdOxuJbQ==} dependencies: '@gar/promisify': 1.1.3 - semver: 7.7.1 + semver: 7.7.2 dev: true /@npmcli/move-file@1.1.2: @@ -2163,95 +2193,24 @@ packages: json-parse-even-better-errors: 2.3.1 dev: true - /@remix-run/dev@1.12.0(@types/node@14.18.33): - resolution: {integrity: sha512-lBiA2FlDi+DjpOAE/vn93zFTSxudKag/FGpmbV6O+LQItDCpFARfbBMhTck/uKcc95nyhRd1GGhQ4ZDgQnyjaQ==} + /@pkgjs/parseargs@0.11.0: + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} - hasBin: true - peerDependencies: - '@remix-run/serve': ^1.12.0 - peerDependenciesMeta: - '@remix-run/serve': - optional: true - dependencies: - '@babel/core': 7.26.9 - '@babel/generator': 7.26.9 - '@babel/parser': 7.26.9 - '@babel/plugin-syntax-jsx': 7.25.9(@babel/core@7.26.9) - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9) - '@babel/preset-env': 7.26.9(@babel/core@7.26.9) - '@babel/preset-typescript': 7.26.0(@babel/core@7.26.9) - '@babel/traverse': 7.26.9 - '@babel/types': 7.26.9 - '@esbuild-plugins/node-modules-polyfill': 0.1.4(esbuild@0.16.3) - '@npmcli/package-json': 2.0.0 - '@remix-run/server-runtime': 1.12.0 - '@vanilla-extract/integration': 6.5.0(@types/node@14.18.33) - arg: 5.0.2 - cacache: 15.3.0 - chalk: 4.1.2 - chokidar: 3.6.0 - dotenv: 16.4.7 - esbuild: 0.16.3 - execa: 5.1.1 - exit-hook: 2.2.1 - express: 4.21.2 - fast-glob: 3.2.11 - fs-extra: 10.1.0 - get-port: 5.1.1 - gunzip-maybe: 1.4.2 - inquirer: 8.2.6 - jsesc: 3.0.2 - json5: 2.2.3 - lodash: 4.17.21 - lodash.debounce: 4.0.8 - lru-cache: 7.18.3 - minimatch: 3.1.2 - node-fetch: 2.7.0 - ora: 5.4.1 - postcss: 8.5.3 - postcss-discard-duplicates: 5.1.0(postcss@8.5.3) - postcss-modules: 6.0.1(postcss@8.5.3) - prettier: 2.7.1 - pretty-ms: 7.0.1 - proxy-agent: 5.0.0 - recast: 0.21.5 - remark-frontmatter: 4.0.1 - remark-mdx-frontmatter: 1.1.1 - semver: 7.7.1 - sort-package-json: 1.57.0 - tar-fs: 2.1.2 - tsconfig-paths: 4.2.0 - ws: 7.5.10 - xdm: 2.1.0 - transitivePeerDependencies: - - '@types/node' - - babel-plugin-macros - - bluebird - - bufferutil - - encoding - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - utf-8-validate dev: true + optional: true - /@remix-run/router@1.3.1: - resolution: {integrity: sha512-+eun1Wtf72RNRSqgU7qM2AMX/oHp+dnx7BHk1qhK5ZHzdHTUU4LA1mGG1vT+jMc8sbhG3orvsfOmryjzx2PzQw==} + /@remix-run/router@1.5.0: + resolution: {integrity: sha512-bkUDCp8o1MvFO+qxkODcbhSqRa6P2GXgrGZVpt0dCXNW2HCSCqYI0ZoAqEOSAjRWmmlKcYgFvN4B4S+zo/f8kg==} engines: {node: '>=14'} dev: true - /@remix-run/server-runtime@1.12.0: - resolution: {integrity: sha512-7I0165Ns/ffPfCEfuiqD58lMderTn2s/sew1xJ34ONa21mG/7+5T7diHIgxKST8rS3816JPmlwSqUaHgwbmO6Q==} + /@remix-run/server-runtime@1.15.0: + resolution: {integrity: sha512-DL9xjHfYYrEcOq5VbhYtrjJUWo/nFQAT7Y+Np/oC55HokyU6cb2jGhl52nx96aAxKwaFCse5N90GeodFsRzX7w==} engines: {node: '>=14'} dependencies: - '@remix-run/router': 1.3.1 + '@remix-run/router': 1.5.0 '@types/cookie': 0.4.1 - '@types/react': 18.3.18 + '@types/react': 18.3.23 '@web3-storage/multipart-parser': 1.0.0 cookie: 0.4.2 set-cookie-parser: 2.7.1 @@ -2266,158 +2225,168 @@ packages: picomatch: 2.3.1 dev: true - /@rollup/rollup-android-arm-eabi@4.34.8: - resolution: {integrity: sha512-q217OSE8DTp8AFHuNHXo0Y86e1wtlfVrXiAlwkIvGRQv9zbc6mE3sjIVfwI8sYUyNxwOg0j/Vm1RKM04JcWLJw==} + /@rollup/pluginutils@5.2.0: + resolution: {integrity: sha512-qWJ2ZTbmumwiLFomfzTyt5Kng4hwPi9rwCYN4SHb6eaRU1KNO4ccxINHr/VhH4GgPlt1XfSTLX2LBTme8ne4Zw==} + engines: {node: '>=14.0.0'} + peerDependencies: + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true + dependencies: + '@types/estree': 1.0.8 + estree-walker: 2.0.2 + picomatch: 4.0.3 + dev: true + + /@rollup/rollup-android-arm-eabi@4.45.1: + resolution: {integrity: sha512-NEySIFvMY0ZQO+utJkgoMiCAjMrGvnbDLHvcmlA33UXJpYBCvlBEbMMtV837uCkS+plG2umfhn0T5mMAxGrlRA==} cpu: [arm] os: [android] - requiresBuild: true dev: true optional: true - /@rollup/rollup-android-arm64@4.34.8: - resolution: {integrity: sha512-Gigjz7mNWaOL9wCggvoK3jEIUUbGul656opstjaUSGC3eT0BM7PofdAJaBfPFWWkXNVAXbaQtC99OCg4sJv70Q==} + /@rollup/rollup-android-arm64@4.45.1: + resolution: {integrity: sha512-ujQ+sMXJkg4LRJaYreaVx7Z/VMgBBd89wGS4qMrdtfUFZ+TSY5Rs9asgjitLwzeIbhwdEhyj29zhst3L1lKsRQ==} cpu: [arm64] os: [android] - requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-arm64@4.34.8: - resolution: {integrity: sha512-02rVdZ5tgdUNRxIUrFdcMBZQoaPMrxtwSb+/hOfBdqkatYHR3lZ2A2EGyHq2sGOd0Owk80oV3snlDASC24He3Q==} + /@rollup/rollup-darwin-arm64@4.45.1: + resolution: {integrity: sha512-FSncqHvqTm3lC6Y13xncsdOYfxGSLnP+73k815EfNmpewPs+EyM49haPS105Rh4aF5mJKywk9X0ogzLXZzN9lA==} cpu: [arm64] os: [darwin] - requiresBuild: true dev: true optional: true - /@rollup/rollup-darwin-x64@4.34.8: - resolution: {integrity: sha512-qIP/elwR/tq/dYRx3lgwK31jkZvMiD6qUtOycLhTzCvrjbZ3LjQnEM9rNhSGpbLXVJYQ3rq39A6Re0h9tU2ynw==} + /@rollup/rollup-darwin-x64@4.45.1: + resolution: {integrity: sha512-2/vVn/husP5XI7Fsf/RlhDaQJ7x9zjvC81anIVbr4b/f0xtSmXQTFcGIQ/B1cXIYM6h2nAhJkdMHTnD7OtQ9Og==} cpu: [x64] os: [darwin] - requiresBuild: true dev: true optional: true - /@rollup/rollup-freebsd-arm64@4.34.8: - resolution: {integrity: sha512-IQNVXL9iY6NniYbTaOKdrlVP3XIqazBgJOVkddzJlqnCpRi/yAeSOa8PLcECFSQochzqApIOE1GHNu3pCz+BDA==} + /@rollup/rollup-freebsd-arm64@4.45.1: + resolution: {integrity: sha512-4g1kaDxQItZsrkVTdYQ0bxu4ZIQ32cotoQbmsAnW1jAE4XCMbcBPDirX5fyUzdhVCKgPcrwWuucI8yrVRBw2+g==} cpu: [arm64] os: [freebsd] - requiresBuild: true dev: true optional: true - /@rollup/rollup-freebsd-x64@4.34.8: - resolution: {integrity: sha512-TYXcHghgnCqYFiE3FT5QwXtOZqDj5GmaFNTNt3jNC+vh22dc/ukG2cG+pi75QO4kACohZzidsq7yKTKwq/Jq7Q==} + /@rollup/rollup-freebsd-x64@4.45.1: + resolution: {integrity: sha512-L/6JsfiL74i3uK1Ti2ZFSNsp5NMiM4/kbbGEcOCps99aZx3g8SJMO1/9Y0n/qKlWZfn6sScf98lEOUe2mBvW9A==} cpu: [x64] os: [freebsd] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.34.8: - resolution: {integrity: sha512-A4iphFGNkWRd+5m3VIGuqHnG3MVnqKe7Al57u9mwgbyZ2/xF9Jio72MaY7xxh+Y87VAHmGQr73qoKL9HPbXj1g==} + /@rollup/rollup-linux-arm-gnueabihf@4.45.1: + resolution: {integrity: sha512-RkdOTu2jK7brlu+ZwjMIZfdV2sSYHK2qR08FUWcIoqJC2eywHbXr0L8T/pONFwkGukQqERDheaGTeedG+rra6Q==} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm-musleabihf@4.34.8: - resolution: {integrity: sha512-S0lqKLfTm5u+QTxlFiAnb2J/2dgQqRy/XvziPtDd1rKZFXHTyYLoVL58M/XFwDI01AQCDIevGLbQrMAtdyanpA==} + /@rollup/rollup-linux-arm-musleabihf@4.45.1: + resolution: {integrity: sha512-3kJ8pgfBt6CIIr1o+HQA7OZ9mp/zDk3ctekGl9qn/pRBgrRgfwiffaUmqioUGN9hv0OHv2gxmvdKOkARCtRb8Q==} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-gnu@4.34.8: - resolution: {integrity: sha512-jpz9YOuPiSkL4G4pqKrus0pn9aYwpImGkosRKwNi+sJSkz+WU3anZe6hi73StLOQdfXYXC7hUfsQlTnjMd3s1A==} + /@rollup/rollup-linux-arm64-gnu@4.45.1: + resolution: {integrity: sha512-k3dOKCfIVixWjG7OXTCOmDfJj3vbdhN0QYEqB+OuGArOChek22hn7Uy5A/gTDNAcCy5v2YcXRJ/Qcnm4/ma1xw==} cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-arm64-musl@4.34.8: - resolution: {integrity: sha512-KdSfaROOUJXgTVxJNAZ3KwkRc5nggDk+06P6lgi1HLv1hskgvxHUKZ4xtwHkVYJ1Rep4GNo+uEfycCRRxht7+Q==} + /@rollup/rollup-linux-arm64-musl@4.45.1: + resolution: {integrity: sha512-PmI1vxQetnM58ZmDFl9/Uk2lpBBby6B6rF4muJc65uZbxCs0EA7hhKCk2PKlmZKuyVSHAyIw3+/SiuMLxKxWog==} cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-loongarch64-gnu@4.34.8: - resolution: {integrity: sha512-NyF4gcxwkMFRjgXBM6g2lkT58OWztZvw5KkV2K0qqSnUEqCVcqdh2jN4gQrTn/YUpAcNKyFHfoOZEer9nwo6uQ==} + /@rollup/rollup-linux-loongarch64-gnu@4.45.1: + resolution: {integrity: sha512-9UmI0VzGmNJ28ibHW2GpE2nF0PBQqsyiS4kcJ5vK+wuwGnV5RlqdczVocDSUfGX/Na7/XINRVoUgJyFIgipoRg==} cpu: [loong64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-powerpc64le-gnu@4.34.8: - resolution: {integrity: sha512-LMJc999GkhGvktHU85zNTDImZVUCJ1z/MbAJTnviiWmmjyckP5aQsHtcujMjpNdMZPT2rQEDBlJfubhs3jsMfw==} + /@rollup/rollup-linux-powerpc64le-gnu@4.45.1: + resolution: {integrity: sha512-7nR2KY8oEOUTD3pBAxIBBbZr0U7U+R9HDTPNy+5nVVHDXI4ikYniH1oxQz9VoB5PbBU1CZuDGHkLJkd3zLMWsg==} cpu: [ppc64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-riscv64-gnu@4.34.8: - resolution: {integrity: sha512-xAQCAHPj8nJq1PI3z8CIZzXuXCstquz7cIOL73HHdXiRcKk8Ywwqtx2wrIy23EcTn4aZ2fLJNBB8d0tQENPCmw==} + /@rollup/rollup-linux-riscv64-gnu@4.45.1: + resolution: {integrity: sha512-nlcl3jgUultKROfZijKjRQLUu9Ma0PeNv/VFHkZiKbXTBQXhpytS8CIj5/NfBeECZtY2FJQubm6ltIxm/ftxpw==} cpu: [riscv64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-s390x-gnu@4.34.8: - resolution: {integrity: sha512-DdePVk1NDEuc3fOe3dPPTb+rjMtuFw89gw6gVWxQFAuEqqSdDKnrwzZHrUYdac7A7dXl9Q2Vflxpme15gUWQFA==} + /@rollup/rollup-linux-riscv64-musl@4.45.1: + resolution: {integrity: sha512-HJV65KLS51rW0VY6rvZkiieiBnurSzpzore1bMKAhunQiECPuxsROvyeaot/tcK3A3aGnI+qTHqisrpSgQrpgA==} + cpu: [riscv64] + os: [linux] + dev: true + optional: true + + /@rollup/rollup-linux-s390x-gnu@4.45.1: + resolution: {integrity: sha512-NITBOCv3Qqc6hhwFt7jLV78VEO/il4YcBzoMGGNxznLgRQf43VQDae0aAzKiBeEPIxnDrACiMgbqjuihx08OOw==} cpu: [s390x] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-gnu@4.34.8: - resolution: {integrity: sha512-8y7ED8gjxITUltTUEJLQdgpbPh1sUQ0kMTmufRF/Ns5tI9TNMNlhWtmPKKHCU0SilX+3MJkZ0zERYYGIVBYHIA==} + /@rollup/rollup-linux-x64-gnu@4.45.1: + resolution: {integrity: sha512-+E/lYl6qu1zqgPEnTrs4WysQtvc/Sh4fC2nByfFExqgYrqkKWp1tWIbe+ELhixnenSpBbLXNi6vbEEJ8M7fiHw==} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-linux-x64-musl@4.34.8: - resolution: {integrity: sha512-SCXcP0ZpGFIe7Ge+McxY5zKxiEI5ra+GT3QRxL0pMMtxPfpyLAKleZODi1zdRHkz5/BhueUrYtYVgubqe9JBNQ==} + /@rollup/rollup-linux-x64-musl@4.45.1: + resolution: {integrity: sha512-a6WIAp89p3kpNoYStITT9RbTbTnqarU7D8N8F2CV+4Cl9fwCOZraLVuVFvlpsW0SbIiYtEnhCZBPLoNdRkjQFw==} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-arm64-msvc@4.34.8: - resolution: {integrity: sha512-YHYsgzZgFJzTRbth4h7Or0m5O74Yda+hLin0irAIobkLQFRQd1qWmnoVfwmKm9TXIZVAD0nZ+GEb2ICicLyCnQ==} + /@rollup/rollup-win32-arm64-msvc@4.45.1: + resolution: {integrity: sha512-T5Bi/NS3fQiJeYdGvRpTAP5P02kqSOpqiopwhj0uaXB6nzs5JVi2XMJb18JUSKhCOX8+UE1UKQufyD6Or48dJg==} cpu: [arm64] os: [win32] - requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-ia32-msvc@4.34.8: - resolution: {integrity: sha512-r3NRQrXkHr4uWy5TOjTpTYojR9XmF0j/RYgKCef+Ag46FWUTltm5ziticv8LdNsDMehjJ543x/+TJAek/xBA2w==} + /@rollup/rollup-win32-ia32-msvc@4.45.1: + resolution: {integrity: sha512-lxV2Pako3ujjuUe9jiU3/s7KSrDfH6IgTSQOnDWr9aJ92YsFd7EurmClK0ly/t8dzMkDtd04g60WX6yl0sGfdw==} cpu: [ia32] os: [win32] - requiresBuild: true dev: true optional: true - /@rollup/rollup-win32-x64-msvc@4.34.8: - resolution: {integrity: sha512-U0FaE5O1BCpZSeE6gBl3c5ObhePQSfk9vDRToMmTkbhCOgW4jqvtS5LGyQ76L1fH8sM0keRp4uDTsbjiUyjk0g==} + /@rollup/rollup-win32-x64-msvc@4.45.1: + resolution: {integrity: sha512-M/fKi4sasCdM8i0aWJjCSFm2qEnYRR8AMLG2kxp6wD13+tMGA4Z1tVAuHkNRjud5SW2EM3naLuK35w9twvf6aA==} cpu: [x64] os: [win32] - requiresBuild: true dev: true optional: true + /@rtsao/scc@1.1.0: + resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} + dev: true + + /@sinclair/typebox@0.25.24: + resolution: {integrity: sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==} + dev: true + /@sindresorhus/is@4.6.0: resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==} engines: {node: '>=10'} @@ -2435,32 +2404,70 @@ packages: buffer: 6.0.3 dev: true - /@solana/web3.js@1.73.0: - resolution: {integrity: sha512-YrgX3Py7ylh8NYkbanoINUPCj//bWUjYZ5/WPy9nQ9SK3Cl7QWCR+NmbDjmC/fTspZGR+VO9LTQslM++jr5PRw==} - engines: {node: '>=12.20.0'} + /@solana/codecs-core@2.3.0(typescript@4.9.5): + resolution: {integrity: sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' dependencies: - '@babel/runtime': 7.26.9 - '@noble/ed25519': 1.7.3 - '@noble/hashes': 1.3.1 - '@noble/secp256k1': 1.7.1 + '@solana/errors': 2.3.0(typescript@4.9.5) + typescript: 4.9.5 + dev: true + + /@solana/codecs-numbers@2.3.0(typescript@4.9.5): + resolution: {integrity: sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + dependencies: + '@solana/codecs-core': 2.3.0(typescript@4.9.5) + '@solana/errors': 2.3.0(typescript@4.9.5) + typescript: 4.9.5 + dev: true + + /@solana/errors@2.3.0(typescript@4.9.5): + resolution: {integrity: sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.3.3' + dependencies: + chalk: 5.4.1 + commander: 14.0.0 + typescript: 4.9.5 + dev: true + + /@solana/web3.js@1.98.2(typescript@4.9.5): + resolution: {integrity: sha512-BqVwEG+TaG2yCkBMbD3C4hdpustR4FpuUFRPUmqRZYYlPI9Hg4XMWxHWOWRzHE9Lkc9NDjzXFX7lDXSgzC7R1A==} + dependencies: + '@babel/runtime': 7.27.6 + '@noble/curves': 1.9.4 + '@noble/hashes': 1.8.0 '@solana/buffer-layout': 4.0.1 + '@solana/codecs-numbers': 2.3.0(typescript@4.9.5) agentkeepalive: 4.6.0 - bigint-buffer: 1.1.5 - bn.js: 5.2.1 + bn.js: 5.2.2 borsh: 0.7.0 bs58: 4.0.1 - buffer: 6.0.1 + buffer: 6.0.3 fast-stable-stringify: 1.0.0 - jayson: 3.7.0 + jayson: 4.2.0 node-fetch: 2.7.0 - rpc-websockets: 7.11.2 - superstruct: 0.14.2 + rpc-websockets: 9.1.1 + superstruct: 2.0.2 transitivePeerDependencies: - bufferutil - encoding + - typescript - utf-8-validate dev: true + /@swc/helpers@0.5.17: + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + dependencies: + tslib: 2.8.1 + dev: true + /@szmarczak/http-timer@4.0.6: resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==} engines: {node: '>=10'} @@ -2501,7 +2508,7 @@ packages: /@types/acorn@4.0.6: resolution: {integrity: sha512-veQTnWP+1D/xbxVrPC3zHnCZRjSrKfhbMUlEA43iMZLu7EsnTtkJklIuwrCPbOi8YkvDQAiW05VQQFvvz9oieQ==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 dev: true /@types/cacheable-request@6.0.3: @@ -2509,14 +2516,14 @@ packages: dependencies: '@types/http-cache-semantics': 4.0.4 '@types/keyv': 3.1.4 - '@types/node': 22.13.5 + '@types/node': 24.0.14 '@types/responselike': 1.0.3 dev: true /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: - '@types/node': 12.20.55 + '@types/node': 24.0.14 dev: true /@types/cookie@0.4.1: @@ -2532,24 +2539,24 @@ packages: /@types/estree-jsx@0.0.1: resolution: {integrity: sha512-gcLAYiMfQklDCPjQegGn0TBAn9it05ISEsEhlKQUddIk7o2XDokOcTN7HBO8tznM0D9dGezvHEfRZBfZf6me0A==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 dev: true /@types/estree-jsx@1.0.5: resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 dev: true - /@types/estree@1.0.6: - resolution: {integrity: sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==} + /@types/estree@1.0.8: + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} dev: true /@types/glob@7.2.0: resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} dependencies: - '@types/minimatch': 5.1.2 - '@types/node': 22.13.5 + '@types/minimatch': 6.0.0 + '@types/node': 24.0.14 dev: true /@types/hast@2.3.10: @@ -2573,7 +2580,7 @@ packages: /@types/keyv@3.1.4: resolution: {integrity: sha512-BQ5aZNSCpj7D6K2ksrRCTmKRLEpnPvWDiLPfoGyhZ++8YtiK9d/3DBKPJgry359X/P1PfruyYwvnvwFjuEiEIg==} dependencies: - '@types/node': 22.13.5 + '@types/node': 24.0.14 dev: true /@types/mdast@3.0.15: @@ -2586,8 +2593,11 @@ packages: resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} dev: true - /@types/minimatch@5.1.2: - resolution: {integrity: sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==} + /@types/minimatch@6.0.0: + resolution: {integrity: sha512-zmPitbQ8+6zNutpwgcQuLcsEpn/Cj54Kbn7L5pX0Os5kdWplB7xPgEh/g+SWOB/qmows2gpuCaPyduq8ZZRnxA==} + deprecated: This is a stub types definition. minimatch provides its own type definitions, so you do not need this installed. + dependencies: + minimatch: 9.0.5 dev: true /@types/ms@2.1.0: @@ -2602,41 +2612,55 @@ packages: resolution: {integrity: sha512-qelS/Ra6sacc4loe/3MSjXNL1dNQ/GjxNHVzuChwMfmk7HuycRLVQN2qNY3XahK+fZc5E2szqQSKUyAF0E+2bg==} dev: true - /@types/node@22.13.5: - resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==} + /@types/node@24.0.14: + resolution: {integrity: sha512-4zXMWD91vBLGRtHK3YbIoFMia+1nqEz72coM42C5ETjnNCa/heoj7NT1G67iAfOqMmcfhuCZ4uNpyz8EjlAejw==} dependencies: - undici-types: 6.20.0 + undici-types: 7.8.0 dev: true - /@types/prop-types@15.7.14: - resolution: {integrity: sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==} + /@types/prop-types@15.7.15: + resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} dev: true - /@types/react@18.3.18: - resolution: {integrity: sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==} + /@types/react@18.3.23: + resolution: {integrity: sha512-/LDXMQh55EzZQ0uVAZmKKhfENivEvWz6E+EYzh+/MCjMhNsotd+ZHhBGIjFDTi6+fz0OhQQQLbTgdQIxxCsC0w==} dependencies: - '@types/prop-types': 15.7.14 + '@types/prop-types': 15.7.15 csstype: 3.1.3 dev: true /@types/responselike@1.0.3: resolution: {integrity: sha512-H/+L+UkTV33uf49PH5pCAUBVPNj2nDBXTN+qS1dOwyyg24l3CcicicCA7ca+HMvJBZcFgl5r8e+RR6elsb4Lyw==} dependencies: - '@types/node': 22.13.5 + '@types/node': 24.0.14 + dev: true + + /@types/semver@7.7.0: + resolution: {integrity: sha512-k107IF4+Xr7UHjwDc7Cfd6PRQfbdkiRabXGRjo07b4WyPahFBZCZ1sE+BNxYIJPPg73UkfOsVOLwqVc/6ETrIA==} dev: true /@types/unist@2.0.11: resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} dev: true + /@types/uuid@8.3.4: + resolution: {integrity: sha512-c/I8ZRb51j+pYGAu5CrFMRxqZ2ke4y2grEBO5AUjgSkSk+qT2Ea+OdWElz/OiMf5MNpn2b17kuVBwZLQJXzihw==} + dev: true + /@types/ws@7.4.7: resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} dependencies: - '@types/node': 12.20.55 + '@types/node': 24.0.14 dev: true - /@typescript-eslint/eslint-plugin@5.0.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1)(typescript@4.9.4): - resolution: {integrity: sha512-T6V6fCD2U0YesOedvydTnrNtsC8E+c2QzpawIpDdlaObX0OX5dLo7tLU5c64FhTZvA1Xrdim+cXDI7NPsVx8Cg==} + /@types/ws@8.18.1: + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + dependencies: + '@types/node': 24.0.14 + dev: true + + /@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1)(typescript@4.9.5): + resolution: {integrity: sha512-TiZzBSJja/LbhNPvk6yc0JrX9XqhQ0hdh6M2svYfsHGejaKFIAGd9MQ+ERIMzLGlN/kZoYIgdxFV0PuljTKXag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: '@typescript-eslint/parser': ^5.0.0 @@ -2646,41 +2670,25 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/experimental-utils': 5.0.0(eslint@8.0.1)(typescript@4.9.4) - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) - '@typescript-eslint/scope-manager': 5.0.0 - debug: 4.4.0 - eslint: 8.0.1 - functional-red-black-tree: 1.0.1 + '@eslint-community/regexpp': 4.12.1 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + debug: 4.4.1 + eslint: 8.57.1 + graphemer: 1.4.0 ignore: 5.3.2 - regexpp: 3.2.0 - semver: 7.7.1 - tsutils: 3.21.0(typescript@4.9.4) - typescript: 4.9.4 - transitivePeerDependencies: - - supports-color - dev: true - - /@typescript-eslint/experimental-utils@5.0.0(eslint@8.0.1)(typescript@4.9.4): - resolution: {integrity: sha512-Dnp4dFIsZcPawD6CT1p5NibNUQyGSEz80sULJZkyhyna8AEqArmfwMwJPbmKzWVo4PabqNVzHYlzmcdLQWk+pg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: '*' - dependencies: - '@types/json-schema': 7.0.15 - '@typescript-eslint/scope-manager': 5.0.0 - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/typescript-estree': 5.0.0(typescript@4.9.4) - eslint: 8.0.1 - eslint-scope: 5.1.1 - eslint-utils: 3.0.0(eslint@8.0.1) + natural-compare-lite: 1.4.0 + semver: 7.7.2 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 transitivePeerDependencies: - supports-color - - typescript dev: true - /@typescript-eslint/parser@5.46.1(eslint@8.0.1)(typescript@4.9.4): - resolution: {integrity: sha512-RelQ5cGypPh4ySAtfIMBzBGyrNerQcmfA1oJvPj5f+H4jI59rl9xxpn4bonC0tQvUKOEN7eGBFWxFLK3Xepneg==} + /@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@4.9.5): + resolution: {integrity: sha512-VlJEV0fOQ7BExOsHYAGrgbEiZoi8D+Bl2+f6V2RrXerRSylnp+ZBHmPvaIa8cz0Ajx7WO7Z5RqfgYg7ED1nRhA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 @@ -2689,44 +2697,51 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/scope-manager': 5.46.1 - '@typescript-eslint/types': 5.46.1 - '@typescript-eslint/typescript-estree': 5.46.1(typescript@4.9.4) - debug: 4.4.0 - eslint: 8.0.1 - typescript: 4.9.4 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) + debug: 4.4.1 + eslint: 8.57.1 + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/scope-manager@5.0.0: - resolution: {integrity: sha512-5RFjdA/ain/MDUHYXdF173btOKncIrLuBmA9s6FJhzDrRAyVSA+70BHg0/MW6TE+UiKVyRtX91XpVS0gVNwVDQ==} + /@typescript-eslint/scope-manager@5.62.0: + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/visitor-keys': 5.0.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 dev: true - /@typescript-eslint/scope-manager@5.46.1: - resolution: {integrity: sha512-iOChVivo4jpwUdrJZyXSMrEIM/PvsbbDOX1y3UCKjSgWn+W89skxWaYXACQfxmIGhPVpRWK/VWPYc+bad6smIA==} + /@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@4.9.5): + resolution: {integrity: sha512-xsSQreu+VnfbqQpW5vnCJdq1Z3Q0U31qiWmRhr98ONQmcp/yhiPJFPq8MXiJVLiksmOKSjIldZzkebzHuCGzew==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: '*' + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@typescript-eslint/types': 5.46.1 - '@typescript-eslint/visitor-keys': 5.46.1 - dev: true - - /@typescript-eslint/types@5.0.0: - resolution: {integrity: sha512-dU/pKBUpehdEqYuvkojmlv0FtHuZnLXFBn16zsDmlFF3LXkOpkAQ2vrKc3BidIIve9EMH2zfTlxqw9XM0fFN5w==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + debug: 4.4.1 + eslint: 8.57.1 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 + transitivePeerDependencies: + - supports-color dev: true - /@typescript-eslint/types@5.46.1: - resolution: {integrity: sha512-Z5pvlCaZgU+93ryiYUwGwLl9AQVB/PQ1TsJ9NZ/gHzZjN7g9IAn6RSDkpCV8hqTwAiaj6fmCcKSQeBPlIpW28w==} + /@typescript-eslint/types@5.62.0: + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /@typescript-eslint/typescript-estree@5.0.0(typescript@4.9.4): - resolution: {integrity: sha512-V/6w+PPQMhinWKSn+fCiX5jwvd1vRBm7AX7SJQXEGQtwtBvjMPjaU3YTQ1ik2UF1u96X7tsB96HMnulG3eLi9Q==} + /@typescript-eslint/typescript-estree@5.62.0(typescript@4.9.5): + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: typescript: '*' @@ -2734,72 +2749,67 @@ packages: typescript: optional: true dependencies: - '@typescript-eslint/types': 5.0.0 - '@typescript-eslint/visitor-keys': 5.0.0 - debug: 4.4.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.4.1 globby: 11.1.0 is-glob: 4.0.3 - semver: 7.7.1 - tsutils: 3.21.0(typescript@4.9.4) - typescript: 4.9.4 + semver: 7.7.2 + tsutils: 3.21.0(typescript@4.9.5) + typescript: 4.9.5 transitivePeerDependencies: - supports-color dev: true - /@typescript-eslint/typescript-estree@5.46.1(typescript@4.9.4): - resolution: {integrity: sha512-j9W4t67QiNp90kh5Nbr1w92wzt+toiIsaVPnEblB2Ih2U9fqBTyqV9T3pYWZBRt6QoMh/zVWP59EpuCjc4VRBg==} + /@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@4.9.5): + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: - typescript: '*' - peerDependenciesMeta: - typescript: - optional: true + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - '@typescript-eslint/types': 5.46.1 - '@typescript-eslint/visitor-keys': 5.46.1 - debug: 4.4.0 - globby: 11.1.0 - is-glob: 4.0.3 - semver: 7.7.1 - tsutils: 3.21.0(typescript@4.9.4) - typescript: 4.9.4 + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.0 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@4.9.5) + eslint: 8.57.1 + eslint-scope: 5.1.1 + semver: 7.7.2 transitivePeerDependencies: - supports-color + - typescript dev: true - /@typescript-eslint/visitor-keys@5.0.0: - resolution: {integrity: sha512-yRyd2++o/IrJdyHuYMxyFyBhU762MRHQ/bAGQeTnN3pGikfh+nEmM61XTqaDH1XDp53afZ+waXrk0ZvenoZ6xw==} + /@typescript-eslint/visitor-keys@5.62.0: + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - '@typescript-eslint/types': 5.0.0 + '@typescript-eslint/types': 5.62.0 eslint-visitor-keys: 3.4.3 dev: true - /@typescript-eslint/visitor-keys@5.46.1: - resolution: {integrity: sha512-jczZ9noovXwy59KjRTk1OftT78pwygdcmCuBf8yMoWt/8O8l+6x2LSEze0E4TeepXK4MezW3zGSyoDRZK7Y9cg==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dependencies: - '@typescript-eslint/types': 5.46.1 - eslint-visitor-keys: 3.4.3 + /@ungap/structured-clone@1.3.0: + resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} dev: true - /@vanilla-extract/babel-plugin-debug-ids@1.2.0: - resolution: {integrity: sha512-z5nx2QBnOhvmlmBKeRX5sPVLz437wV30u+GJL+Hzj1rGiJYVNvgIIlzUpRNjVQ0MgAgiQIqIUbqPnmMc6HmDlQ==} + /@vanilla-extract/babel-plugin-debug-ids@1.2.2: + resolution: {integrity: sha512-MeDWGICAF9zA/OZLOKwhoRlsUW+fiMwnfuOAqFVohL31Agj7Q/RBWAYweqjHLgFBCsdnr6XIfwjJnmb2znEWxw==} dependencies: - '@babel/core': 7.26.9 + '@babel/core': 7.28.0 transitivePeerDependencies: - supports-color dev: true - /@vanilla-extract/css@1.17.1: - resolution: {integrity: sha512-tOHQXHm10FrJeXKFeWE09JfDGN/tvV6mbjwoNB9k03u930Vg021vTnbrCwVLkECj9Zvh/SHLBHJ4r2flGqfovw==} + /@vanilla-extract/css@1.17.4: + resolution: {integrity: sha512-m3g9nQDWPtL+sTFdtCGRMI1Vrp86Ay4PBYq1Bo7Bnchj5ElNtAJpOqD+zg+apthVA4fB7oVpMWNjwpa6ElDWFQ==} dependencies: '@emotion/hash': 0.9.2 - '@vanilla-extract/private': 1.0.6 - css-what: 6.1.0 + '@vanilla-extract/private': 1.0.9 + css-what: 6.2.2 cssesc: 3.0.0 csstype: 3.1.3 - dedent: 1.5.3 + dedent: 1.6.0 deep-object-diff: 1.1.9 deepmerge: 4.3.1 lru-cache: 10.4.3 @@ -2810,13 +2820,13 @@ packages: - babel-plugin-macros dev: true - /@vanilla-extract/integration@6.5.0(@types/node@14.18.33): + /@vanilla-extract/integration@6.5.0(@types/node@24.0.14): resolution: {integrity: sha512-E2YcfO8vA+vs+ua+gpvy1HRqvgWbI+MTlUpxA8FvatOvybuNcWAY0CKwQ/Gpj7rswYKtC6C7+xw33emM6/ImdQ==} dependencies: - '@babel/core': 7.26.9 - '@babel/plugin-syntax-typescript': 7.25.9(@babel/core@7.26.9) - '@vanilla-extract/babel-plugin-debug-ids': 1.2.0 - '@vanilla-extract/css': 1.17.1 + '@babel/core': 7.28.0 + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0) + '@vanilla-extract/babel-plugin-debug-ids': 1.2.2 + '@vanilla-extract/css': 1.17.4 esbuild: 0.19.12 eval: 0.1.8 find-up: 5.0.0 @@ -2824,8 +2834,8 @@ packages: lodash: 4.17.21 mlly: 1.7.4 outdent: 0.8.0 - vite: 5.4.14(@types/node@14.18.33) - vite-node: 1.6.1(@types/node@14.18.33) + vite: 5.4.19(@types/node@24.0.14) + vite-node: 1.6.1(@types/node@24.0.14) transitivePeerDependencies: - '@types/node' - babel-plugin-macros @@ -2839,28 +2849,32 @@ packages: - terser dev: true - /@vanilla-extract/private@1.0.6: - resolution: {integrity: sha512-ytsG/JLweEjw7DBuZ/0JCN4WAQgM9erfSTdS1NQY778hFQSZ6cfCDEZZ0sgVm4k54uNz6ImKB33AYvSR//fjxw==} + /@vanilla-extract/private@1.0.9: + resolution: {integrity: sha512-gT2jbfZuaaCLrAxwXbRgIhGhcXbRZCG3v4TTUnjw0EJ7ArdBRxkq4msNJkbuRkCgfIK5ATmprB5t9ljvLeFDEA==} + dev: true + + /@vercel/build-utils@6.7.1: + resolution: {integrity: sha512-Ecc9oQBSVwk1suENcRcj1L6gQrUt4+0XA9oPFxrUpoFEk04lP/ZV3qAQPk+ex08N+vfUulYdqb+cmVTnwqsmqw==} dev: true - /@vercel/build-utils@6.3.0: - resolution: {integrity: sha512-Nbu/CIsv8HMp1+KPZ0n2YlHTKPfGRDrwhMgKW9Dx4z2S5sQWkXpe9WQ5ajePgwZVd7V1XiJYx1CCRaupIVgUwA==} + /@vercel/error-utils@1.0.8: + resolution: {integrity: sha512-s+f7jP2oH1koICbQ8e3K9hOpOeUct7rbCnF9qsNwXemq850wAh2e90tp9R6oYBM0BNpiLRRm+oG5zD2sCIm3HQ==} dev: true - /@vercel/gatsby-plugin-vercel-analytics@1.0.7: - resolution: {integrity: sha512-j4DsneQ+oOF0Zurvisj+H2ds8s8ZEqfI4iD6xgFY9mB2UdGixhzFRjvDBH6g4pfUQXfO76K5GiA1afumGlJbwA==} + /@vercel/gatsby-plugin-vercel-analytics@1.0.10: + resolution: {integrity: sha512-v329WHdtIce+y7oAmaWRvEx59Xfo0FxlQqK4BJG0u6VWYoKWPaflohDAiehIZf/YHCRVb59ZxnzmMOcm/LR8YQ==} dependencies: '@babel/runtime': 7.12.1 web-vitals: 0.2.4 dev: true - /@vercel/gatsby-plugin-vercel-builder@1.1.7: - resolution: {integrity: sha512-XSGT/EOk2BgZ0qRQCn+qGoJmFZHRJ0t9SF+cOtyQ79CtYx0JWDWDlbYEx2r6hDSPsUAsiRnaUmxL5qLzDg4sQg==} + /@vercel/gatsby-plugin-vercel-builder@1.2.10: + resolution: {integrity: sha512-7iSCCOe5XyU8lJVcWd9dDxXq8qF91nEKkO6McxOOVRgiPsJU4T/x48o/+gIbUa35zIv7XltZojRQDRq3jzyfWQ==} dependencies: - '@vercel/build-utils': 6.3.0 - '@vercel/node': 2.9.6 - '@vercel/routing-utils': 2.1.9 - ajv: 8.12.0 + '@sinclair/typebox': 0.25.24 + '@vercel/build-utils': 6.7.1 + '@vercel/node': 2.12.0 + '@vercel/routing-utils': 2.2.0 esbuild: 0.14.47 etag: 1.8.1 fs-extra: 11.1.0 @@ -2870,16 +2884,16 @@ packages: - encoding dev: true - /@vercel/go@2.3.7: - resolution: {integrity: sha512-ffmvGJzalWeOUQ8FfQ4pfqcd4YcQ4y52pTVS5fZXrjCwPYduIdKOowLDXRq08Kv8Llpl42reDaSGWuusFLKF7A==} + /@vercel/go@2.5.0: + resolution: {integrity: sha512-KUUuFpl65oxyCbc7gDWkhbRUg2ZcAa5bpUrhnqYW4ohDicPGe7F7mo/v4GCp/zsFGFNJf9msbmycJA1f9Sk9Ug==} dev: true - /@vercel/hydrogen@0.0.53: - resolution: {integrity: sha512-gJvAL0SbAOR1gS6MMr0EHnKlD3Ri1F0eniIfDpV5qgSNqjzVSSVI3tT8ag4KCS70H1tawj16XMR7oPRcKmyebQ==} + /@vercel/hydrogen@0.0.63: + resolution: {integrity: sha512-FxBjgX0Mt22eqvHGrMKDcfxt/81y9QrHM6md+hGIflkQ9DvrtyYmmFze588yXWAv/I04eCgVoE+/KsgETkRi3w==} dev: true - /@vercel/next@3.4.7: - resolution: {integrity: sha512-C57Uhckij/X9Fx1BaYLWugUiUKrI1ZpmwYIttZgYIM0XdnBArZ14hc+p4shhjWDy7+sG0Fq2IMfANEMLxaJq3A==} + /@vercel/next@3.7.5: + resolution: {integrity: sha512-NonL8rt49EnwooMnAXYUDpz2B+e+yoQRdEZoekZlnFzP6VF1F1r14N2X9zUqxeRH7rY6X53MgiRNSHeZKqTXPA==} dev: true /@vercel/nft@0.22.5: @@ -2889,7 +2903,7 @@ packages: dependencies: '@mapbox/node-pre-gyp': 1.0.11 '@rollup/pluginutils': 4.2.1 - acorn: 8.14.0 + acorn: 8.15.0 async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 @@ -2903,44 +2917,49 @@ packages: - supports-color dev: true - /@vercel/nft@0.26.5: - resolution: {integrity: sha512-NHxohEqad6Ra/r4lGknO52uc/GrWILXAMs1BB4401GTqww0fw1bAqzpG1XHuDO+dprg4GvsD9ZLLSsdo78p9hQ==} - engines: {node: '>=16'} + /@vercel/nft@0.29.4: + resolution: {integrity: sha512-6lLqMNX3TuycBPABycx7A9F1bHQR7kiQln6abjFbPrf5C/05qHM9M5E4PeTE59c7z8g6vHnx1Ioihb2AQl7BTA==} + engines: {node: '>=18'} hasBin: true dependencies: - '@mapbox/node-pre-gyp': 1.0.11 - '@rollup/pluginutils': 4.2.1 - acorn: 8.14.0 - acorn-import-attributes: 1.9.5(acorn@8.14.0) + '@mapbox/node-pre-gyp': 2.0.0 + '@rollup/pluginutils': 5.2.0 + acorn: 8.15.0 + acorn-import-attributes: 1.9.5(acorn@8.15.0) async-sema: 3.1.1 bindings: 1.5.0 estree-walker: 2.0.2 - glob: 7.2.3 + glob: 10.4.5 graceful-fs: 4.2.11 - micromatch: 4.0.8 node-gyp-build: 4.8.4 + picomatch: 4.0.3 resolve-from: 5.0.0 transitivePeerDependencies: - encoding + - rollup - supports-color dev: true - /@vercel/node-bridge@3.1.11: - resolution: {integrity: sha512-LGbj+kPGgRnIlKo3949z01mLbHVi4BnRE7V5R6+J4E3f7xpQ12I9Wek10V7ivLB+LyS1+ATdjasdXAF4HOhqQw==} + /@vercel/node-bridge@4.0.1: + resolution: {integrity: sha512-XEfKfnLGzlIBpad7eGNPql1HnMhoSTv9q3uDNC4axdaAC/kI5yvl8kXjuCPAXYvpbJnVQPpcSUC5/r5ap8F3jA==} dev: true - /@vercel/node@2.9.6: - resolution: {integrity: sha512-A1/1LucW54jUH8YspTTQYeGdhOPK8Z17bt5vrnB4PW5PGnq5Dn2DaC1mly0/Lo4Qlz44xDIiknwGvAitLAs2gQ==} + /@vercel/node@2.12.0: + resolution: {integrity: sha512-QItQ4DjKrHqTMk/hmtX64V5RfDdp+fDoFzbSbPUICkIOHK3EBCJ5c/392Iv05AwSv+mJIALZUGRQz5o4HKvs6A==} dependencies: '@edge-runtime/vm': 2.0.0 '@types/node': 14.18.33 - '@vercel/build-utils': 6.3.0 - '@vercel/node-bridge': 3.1.11 - '@vercel/static-config': 2.0.13 - edge-runtime: 2.0.0 + '@vercel/build-utils': 6.7.1 + '@vercel/error-utils': 1.0.8 + '@vercel/node-bridge': 4.0.1 + '@vercel/static-config': 2.0.16 + async-listen: 1.2.0 + edge-runtime: 2.1.4 esbuild: 0.14.47 exit-hook: 2.2.1 node-fetch: 2.6.7 + path-to-regexp: 6.2.1 + ts-morph: 12.0.0 ts-node: 10.9.1(@types/node@14.18.33)(typescript@4.3.4) typescript: 4.3.4 transitivePeerDependencies: @@ -2949,31 +2968,114 @@ packages: - encoding dev: true - /@vercel/python@3.1.49: - resolution: {integrity: sha512-0HfFoaU2k+9+Q3oAmUihkpfNonswQq99smhjntBOJfpUTHGbBu/6IXAJJFBYWnRF6sObyaNNoE61NKe84drAtQ==} + /@vercel/python@3.1.59: + resolution: {integrity: sha512-38/KM33nJK5Jk+FiNhi3MTB7arWGGoCF8blejAexpw+NTL70nNy+4O7TN+y7qqx7Az4nygEgBBTgQVfkgIj0Yg==} dev: true - /@vercel/redwood@1.1.5: - resolution: {integrity: sha512-JLgzxhE/g4KgXLoQb7OXTkVFdOkpr/cnY3MAYJa8xw+TD0Nxo9hisXRjoIOQlmpRy4P7HYVruqs9JgCNJ7GRxQ==} + /@vercel/redwood@1.1.14: + resolution: {integrity: sha512-QFIhLegvfVp2OLdv96krTyz6C5/cUncUg4CEEfx3U48+l31hWaWcnjI6+MhgN4PZC4YN+s21vKZNz/UWnGnTiA==} dependencies: '@vercel/nft': 0.22.5 - '@vercel/routing-utils': 2.1.9 + '@vercel/routing-utils': 2.2.0 semver: 6.1.1 transitivePeerDependencies: - encoding - supports-color dev: true - /@vercel/remix@1.3.3(@types/node@14.18.33): - resolution: {integrity: sha512-adUiEJJNG7Ca89go3mf6X0e6yXx971aTLnT1DhZG5IFAAyc82Gqq+0TZb4m2LYmfvXp6HMJZNv1K57psYJxIiw==} + /@vercel/remix-builder@1.8.5(@types/node@24.0.14): + resolution: {integrity: sha512-nXUNsW6+gfHRqnZdXNm9Myx8G8nihbfRe/myAbvUHAXaym+9Bz+WHC3hXXr6YqAOVhjWvCfxAlA9eYqHbhlvKA==} dependencies: - '@remix-run/dev': 1.12.0(@types/node@14.18.33) + '@remix-run/dev': /@vercel/remix-run-dev@1.15.0(@types/node@24.0.14) + '@vercel/build-utils': 6.7.1 '@vercel/nft': 0.22.5 - '@vercel/static-config': 2.0.13 + '@vercel/static-config': 2.0.16 path-to-regexp: 6.2.1 + semver: 7.3.8 ts-morph: 12.0.0 transitivePeerDependencies: - - '@remix-run/serve' + - '@remix-run/serve' + - '@types/node' + - babel-plugin-macros + - bluebird + - bufferutil + - encoding + - less + - lightningcss + - sass + - sass-embedded + - stylus + - sugarss + - supports-color + - terser + - ts-node + - utf-8-validate + dev: true + + /@vercel/remix-run-dev@1.15.0(@types/node@24.0.14): + resolution: {integrity: sha512-pQTM5WmOzrvhpPSHFDShwqX71YnLaTUxffhnly4MxVNKJ2WKV9zqx8bGQ/7cLfpEu9JfY2c+pVjYYb3wAMBt+Q==} + engines: {node: '>=14'} + hasBin: true + peerDependencies: + '@remix-run/serve': ^1.15.0 + peerDependenciesMeta: + '@remix-run/serve': + optional: true + dependencies: + '@babel/core': 7.28.0 + '@babel/generator': 7.28.0 + '@babel/parser': 7.28.0 + '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.0) + '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.0) + '@babel/preset-env': 7.28.0(@babel/core@7.28.0) + '@babel/preset-typescript': 7.27.1(@babel/core@7.28.0) + '@babel/traverse': 7.28.0 + '@babel/types': 7.28.1 + '@esbuild-plugins/node-modules-polyfill': 0.1.4(esbuild@0.16.3) + '@npmcli/package-json': 2.0.0 + '@remix-run/server-runtime': 1.15.0 + '@vanilla-extract/integration': 6.5.0(@types/node@24.0.14) + arg: 5.0.2 + cacache: 15.3.0 + chalk: 4.1.2 + chokidar: 3.6.0 + dotenv: 16.6.1 + esbuild: 0.16.3 + execa: 5.1.1 + exit-hook: 2.2.1 + express: 4.21.2 + fast-glob: 3.2.11 + fs-extra: 10.1.0 + get-port: 5.1.1 + glob-to-regexp: 0.4.1 + gunzip-maybe: 1.4.2 + inquirer: 8.2.6 + jsesc: 3.0.2 + json5: 2.2.3 + lodash: 4.17.21 + lodash.debounce: 4.0.8 + lru-cache: 7.18.3 + minimatch: 3.1.2 + node-fetch: 2.7.0 + ora: 5.4.1 + postcss: 8.5.6 + postcss-discard-duplicates: 5.1.0(postcss@8.5.6) + postcss-load-config: 4.0.2(postcss@8.5.6) + postcss-modules: 6.0.1(postcss@8.5.6) + prettier: 2.7.1 + pretty-ms: 7.0.1 + proxy-agent: 5.0.0 + react-refresh: 0.14.2 + recast: 0.21.5 + remark-frontmatter: 4.0.1 + remark-mdx-frontmatter: 1.1.1 + semver: 7.7.2 + sort-package-json: 1.57.0 + tar-fs: 2.1.3 + tsconfig-paths: 4.2.0 + ws: 7.5.10 + xdm: 2.1.0 + transitivePeerDependencies: - '@types/node' - babel-plugin-macros - bluebird @@ -2987,34 +3089,35 @@ packages: - sugarss - supports-color - terser + - ts-node - utf-8-validate dev: true - /@vercel/routing-utils@2.1.9: - resolution: {integrity: sha512-DVE9coIpicZQBKWL0DgIe5wnZsi4SRPbD51XxFCvvnRyYxG34DY09R0aMz4ZQQdPK2asJF57i5rbcplXYaEOkg==} + /@vercel/routing-utils@2.2.0: + resolution: {integrity: sha512-Ro90s1mStpbgu2HV8I4LFEKNG8GVxkWm238ebD/23BCO9/DxIJ3+wCzga8j8BMmG57x4etVlaHNV25bbzW5r2g==} dependencies: path-to-regexp: 6.1.0 optionalDependencies: ajv: 6.12.6 dev: true - /@vercel/ruby@1.3.65: - resolution: {integrity: sha512-MXQ6WlzxVh6ibvVlotRBP/oi27M7QnX0BWPBI4DakNJ7sGPbWbO1bOd66A1GaAK27MFvdKETIXcgvabfhIaSYQ==} + /@vercel/ruby@1.3.75: + resolution: {integrity: sha512-sUmzJnd9O1N7StFEpKG9JvHJvHmJjgfrmhgQsQLEQ7OOQJkO9DYoLomlrIDW9qNdu7dNOeyj7gQY5B8y8RMntw==} dev: true - /@vercel/static-build@1.3.9: - resolution: {integrity: sha512-3cZuQol7nIe2yxfTOq2JGbUIryaQ+W6XEN/PPLZ5nDHdjzCBeFIIHbjxlX4NtyDcPIrfoCZG+UdsCl6fEGpwAA==} + /@vercel/static-build@1.3.25: + resolution: {integrity: sha512-yBb37pPGLlQEF/QPUezENo4Eu9gq7Ctzl56Dff/Kv6pApzYZ6Zj88OvRoNBTXhxDi0g4EGSYnP0uYtB7lBQcHA==} dependencies: - '@vercel/gatsby-plugin-vercel-analytics': 1.0.7 - '@vercel/gatsby-plugin-vercel-builder': 1.1.7 + '@vercel/gatsby-plugin-vercel-analytics': 1.0.10 + '@vercel/gatsby-plugin-vercel-builder': 1.2.10 transitivePeerDependencies: - '@swc/core' - '@swc/wasm' - encoding dev: true - /@vercel/static-config@2.0.13: - resolution: {integrity: sha512-09bVISGyhRMoL6gQTfM7n89SeUmyOlIzVMo2oNOj3thy4AIKGuN0SzEp0qNRw8d9j07rifp9JPD4rOuDRx4+eA==} + /@vercel/static-config@2.0.16: + resolution: {integrity: sha512-lULo+NWBMpTJb9kR4AwYYK/2e7wknTJO2iFxgYYOkG5i12WHgPhMnXDKrEOcotxctd0yPKx3TsWVGEXniNm63g==} dependencies: ajv: 8.6.3 json-schema-to-ts: 1.6.4 @@ -3025,18 +3128,15 @@ packages: resolution: {integrity: sha512-BEO6al7BYqcnfX15W2cnGR+Q566ACXAT9UQykORCWW80lmkpWsnEob6zJS1ZVBKsSJC8+7vJkHwlp+lXG1UCdw==} dev: true - /JSONStream@1.3.5: - resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} - hasBin: true - dependencies: - jsonparse: 1.3.1 - through: 2.3.8 - dev: true - /abbrev@1.1.1: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} dev: true + /abbrev@3.0.1: + resolution: {integrity: sha512-AO2ac6pjRB3SJmGJo+v5/aK6Omggp6fsLrs6wN9bd35ulu4cCwaAU9+7ZhXjeqHVkaHThLuzH0nZr0YpCDhygg==} + engines: {node: ^18.17.0 || >=20.5.0} + dev: true + /accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} @@ -3045,31 +3145,31 @@ packages: negotiator: 0.6.3 dev: true - /acorn-import-attributes@1.9.5(acorn@8.14.0): + /acorn-import-attributes@1.9.5(acorn@8.15.0): resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} peerDependencies: acorn: ^8 dependencies: - acorn: 8.14.0 + acorn: 8.15.0 dev: true - /acorn-jsx@5.3.2(acorn@8.14.0): + /acorn-jsx@5.3.2(acorn@8.15.0): resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 dependencies: - acorn: 8.14.0 + acorn: 8.15.0 dev: true /acorn-walk@8.3.4: resolution: {integrity: sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==} engines: {node: '>=0.4.0'} dependencies: - acorn: 8.14.0 + acorn: 8.15.0 dev: true - /acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} + /acorn@8.15.0: + resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true dev: true @@ -3078,11 +3178,16 @@ packages: resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} engines: {node: '>= 6.0.0'} dependencies: - debug: 4.4.0 + debug: 4.4.1 transitivePeerDependencies: - supports-color dev: true + /agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + dev: true + /agentkeepalive@4.6.0: resolution: {integrity: sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==} engines: {node: '>= 8.0.0'} @@ -3107,15 +3212,6 @@ packages: uri-js: 4.4.1 dev: true - /ajv@8.12.0: - resolution: {integrity: sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==} - dependencies: - fast-deep-equal: 3.1.3 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - uri-js: 4.4.1 - dev: true - /ajv@8.6.3: resolution: {integrity: sha512-SMJOdDP6LqTkD0Uq8qLi+gMwSt0imXLSV080qFVwJCpH9U6Mb+SUGHAXM0KNbcBPguytWyvFxcHgMLe2D2XSpw==} dependencies: @@ -3125,11 +3221,6 @@ packages: uri-js: 4.4.1 dev: true - /ansi-colors@4.1.3: - resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} - engines: {node: '>=6'} - dev: true - /ansi-escapes@4.3.2: resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} engines: {node: '>=8'} @@ -3147,6 +3238,10 @@ packages: engines: {node: '>=12'} dev: true + /ansi-sequence-parser@1.1.3: + resolution: {integrity: sha512-+fksAx9eG3Ab6LDnLs3ZqZa8KVJ/jYnX+D4Qe1azX+LFGFAXqynCQLOdLpNYN/l9e7l6hMWwZbrnctqr6eSQSw==} + dev: true + /ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} @@ -3167,8 +3262,8 @@ packages: picomatch: 2.3.1 dev: true - /aproba@2.0.0: - resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + /aproba@2.1.0: + resolution: {integrity: sha512-tLIEcj5GuR2RSTnxNKdkK0dJ/GrC7P38sUkiDmDuHfsHmbagTFAxDVIBltoklXEVIQ/f14IL8IMJ5pn9Hez1Ew==} dev: true /are-we-there-yet@2.0.0: @@ -3202,7 +3297,7 @@ packages: resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 is-array-buffer: 3.0.5 dev: true @@ -3215,16 +3310,18 @@ packages: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} dev: true - /array-includes@3.1.8: - resolution: {integrity: sha512-itaWrbYbqpGXkGhZPGUulwnhVf5Hpy1xiCFsGqyIGglbBxmG5vSjxQen3/WGOjPpNEv1RtBLKxbmVXm8HpJStQ==} + /array-includes@3.1.9: + resolution: {integrity: sha512-FmeCCAenzH0KH381SPT5FZmiA/TmpndpcaShhfgEN9eCVjnFBqq3l1xrI42y8+PPLI6hypzou4GXw00WHmPBLQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 + call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 is-string: 1.1.1 + math-intrinsics: 1.1.0 dev: true /array-union@2.1.0: @@ -3232,13 +3329,36 @@ packages: engines: {node: '>=8'} dev: true + /array.prototype.findlastindex@1.2.6: + resolution: {integrity: sha512-F/TKATkzseUExPlfvmwQKGITM3DGTK+vkAsCZoDc5daVygbJBnjEUCbgkAvVFsgfXfX4YIqZ/27G3k3tdXrTxQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-abstract: 1.24.0 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + es-shim-unscopables: 1.1.0 + dev: true + /array.prototype.flat@1.3.3: resolution: {integrity: sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 + es-shim-unscopables: 1.1.0 + dev: true + + /array.prototype.flatmap@1.3.3: + resolution: {integrity: sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 es-shim-unscopables: 1.1.0 dev: true @@ -3249,7 +3369,7 @@ packages: array-buffer-byte-length: 1.0.2 call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 @@ -3289,13 +3409,22 @@ packages: engines: {node: '>= 0.4'} dev: true + /async-listen@1.2.0: + resolution: {integrity: sha512-CcEtRh/oc9Jc4uWeUwdpG/+Mb2YUHKmdaTf0gUr7Wa+bfp4xx70HOb3RuSTJMvqKNB1TkdTfjLdrcz2X4rkkZA==} + dev: true + + /async-listen@2.0.3: + resolution: {integrity: sha512-WVLi/FGIQaXyfYyNvmkwKT1RZbkzszLLnmW/gFCc5lbVvN/0QQCWpBwRBk2OWSdkkmKRBc8yD6BrKsjA3XKaSw==} + engines: {node: '>= 14'} + dev: true + /async-sema@3.1.1: resolution: {integrity: sha512-tLRNUXati5MFePdAk8dw7Qt7DpxPB60ofAgn8WRhW6a2rcimZnYBP9oxHiv0OHy+Wz7kPMG+t4LGdt31+4EmGg==} dev: true - /ava@6.1.3(@ava/typescript@5.0.0): - resolution: {integrity: sha512-tkKbpF1pIiC+q09wNU9OfyTDYZa8yuWvU2up3+lFJ3lr1RmnYh2GBpPwzYUEB0wvTPIUysGjcZLNZr7STDviRA==} - engines: {node: ^18.18 || ^20.8 || ^21 || ^22} + /ava@6.4.1(@ava/typescript@5.0.0): + resolution: {integrity: sha512-vxmPbi1gZx9zhAjHBgw81w/iEDKcrokeRk/fqDTyA2DQygZ0o+dUGRHFOtX8RA5N0heGJTTsIk7+xYxitDb61Q==} + engines: {node: ^18.18 || ^20.8 || ^22 || ^23 || >=24} hasBin: true peerDependencies: '@ava/typescript': '*' @@ -3304,25 +3433,25 @@ packages: optional: true dependencies: '@ava/typescript': 5.0.0 - '@vercel/nft': 0.26.5 - acorn: 8.14.0 + '@vercel/nft': 0.29.4 + acorn: 8.15.0 acorn-walk: 8.3.4 ansi-styles: 6.2.1 arrgv: 1.0.2 arrify: 3.0.0 callsites: 4.2.0 - cbor: 9.0.2 + cbor: 10.0.9 chalk: 5.4.1 chunkd: 2.0.1 - ci-info: 4.1.0 + ci-info: 4.3.0 ci-parallel-vars: 1.0.1 cli-truncate: 4.0.0 code-excerpt: 4.0.0 common-path-prefix: 3.0.0 concordance: 5.0.4 currently-unhandled: 0.4.1 - debug: 4.4.0 - emittery: 1.1.0 + debug: 4.4.1 + emittery: 1.2.0 figures: 6.1.0 globby: 14.1.0 ignore-by-default: 2.1.0 @@ -3334,7 +3463,7 @@ packages: ms: 2.1.3 p-map: 7.0.3 package-config: 5.0.0 - picomatch: 3.0.1 + picomatch: 4.0.3 plur: 5.1.0 pretty-ms: 9.2.0 resolve-cwd: 3.0.0 @@ -3342,10 +3471,11 @@ packages: strip-ansi: 7.1.0 supertap: 3.0.1 temp-dir: 3.0.0 - write-file-atomic: 5.0.1 + write-file-atomic: 6.0.0 yargs: 17.7.2 transitivePeerDependencies: - encoding + - rollup - supports-color dev: true @@ -3356,38 +3486,38 @@ packages: possible-typed-array-names: 1.1.0 dev: true - /babel-plugin-polyfill-corejs2@0.4.12(@babel/core@7.26.9): - resolution: {integrity: sha512-CPWT6BwvhrTO2d8QVorhTCQw9Y43zOu7G9HigcfxvepOU6b8o3tcWad6oVgZIsZCTt42FFv97aA7ZJsbM4+8og==} + /babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.0): + resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/compat-data': 7.26.8 - '@babel/core': 7.26.9 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.9) + '@babel/compat-data': 7.28.0 + '@babel/core': 7.28.0 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.0) semver: 6.3.1 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-corejs3@0.11.1(@babel/core@7.26.9): - resolution: {integrity: sha512-yGCqvBT4rwMczo28xkH/noxJ6MZ4nJfkVYdoDaC/utLtWrXxv27HVrzAeSbqR8SxDsp46n0YF47EbHoixy6rXQ==} + /babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.0): + resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.9) - core-js-compat: 3.40.0 + '@babel/core': 7.28.0 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.0) + core-js-compat: 3.44.0 transitivePeerDependencies: - supports-color dev: true - /babel-plugin-polyfill-regenerator@0.6.3(@babel/core@7.26.9): - resolution: {integrity: sha512-LiWSbl4CRSIa5x/JAU6jZiG9eit9w6mz+yVMFwDE83LAWvt0AfGBoZ7HS/mkhrKuh2ZlzfVZYKoLjXdqw6Yt7Q==} + /babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.0): + resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 dependencies: - '@babel/core': 7.26.9 - '@babel/helper-define-polyfill-provider': 0.6.3(@babel/core@7.26.9) + '@babel/core': 7.28.0 + '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.0) transitivePeerDependencies: - supports-color dev: true @@ -3400,14 +3530,14 @@ packages: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} dev: true - /base-x@3.0.10: - resolution: {integrity: sha512-7d0s06rR9rYaIWHkpfLIFICM/tkSVdoPC9qYAQRpxn9DdKNWNsKC0uk++akckyLq16Tx2WIinnZ6WRriAt6njQ==} + /base-x@3.0.11: + resolution: {integrity: sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==} dependencies: safe-buffer: 5.2.1 dev: true - /base-x@4.0.0: - resolution: {integrity: sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==} + /base-x@4.0.1: + resolution: {integrity: sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==} dev: true /base64-js@1.5.1: @@ -3418,14 +3548,6 @@ packages: resolution: {integrity: sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==} dev: true - /bigint-buffer@1.1.5: - resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} - engines: {node: '>= 10.0.0'} - requiresBuild: true - dependencies: - bindings: 1.5.0 - dev: true - /binary-extensions@2.3.0: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} @@ -3449,8 +3571,8 @@ packages: resolution: {integrity: sha512-DRQrD6gJyy8FbiE4s+bDoXS9hiW3Vbx5uCdwvcCf3zLHL+Iv7LtGHLpr+GZV8rHG8tK766FGYBwRbu8pELTt+w==} dev: true - /bn.js@5.2.1: - resolution: {integrity: sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==} + /bn.js@5.2.2: + resolution: {integrity: sha512-v2YAxEmKaBLahNwE1mjp4WON6huMNeuDvagFZW+ASCuA/ku0bXR9hSMw0XpiqMoA3+rmnyck/tPRSFQkoC9Cuw==} dev: true /body-parser@1.20.3: @@ -3476,20 +3598,20 @@ packages: /borsh@0.7.0: resolution: {integrity: sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==} dependencies: - bn.js: 5.2.1 + bn.js: 5.2.2 bs58: 4.0.1 text-encoding-utf-8: 1.0.2 dev: true - /brace-expansion@1.1.11: - resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + /brace-expansion@1.1.12: + resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} dependencies: balanced-match: 1.0.2 concat-map: 0.0.1 dev: true - /brace-expansion@2.0.1: - resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} + /brace-expansion@2.0.2: + resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} dependencies: balanced-match: 1.0.2 dev: true @@ -3507,27 +3629,27 @@ packages: pako: 0.2.9 dev: true - /browserslist@4.24.4: - resolution: {integrity: sha512-KDi1Ny1gSePi1vm0q4oxSF8b4DR44GF4BbmS2YdhPLOEqd8pDviZOGH/GsmRwoWJ2+5Lr085X7naowMwKHDG1A==} + /browserslist@4.25.1: + resolution: {integrity: sha512-KGj0KoOMXLpSNkkEI6Z6mShmQy0bc1I+T7K9N81k4WWMrfz+6fQ6es80B/YLAeRoKvjYE1YSHHOW1qe9xIVzHw==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true dependencies: - caniuse-lite: 1.0.30001701 - electron-to-chromium: 1.5.108 + caniuse-lite: 1.0.30001727 + electron-to-chromium: 1.5.187 node-releases: 2.0.19 - update-browserslist-db: 1.1.3(browserslist@4.24.4) + update-browserslist-db: 1.1.3(browserslist@4.25.1) dev: true /bs58@4.0.1: resolution: {integrity: sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==} dependencies: - base-x: 3.0.10 + base-x: 3.0.11 dev: true /bs58@5.0.0: resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} dependencies: - base-x: 4.0.0 + base-x: 4.0.1 dev: true /buffer-from@1.1.2: @@ -3541,13 +3663,6 @@ packages: ieee754: 1.2.1 dev: true - /buffer@6.0.1: - resolution: {integrity: sha512-rVAXBwEcEoYtxnHSO5iWyhzV/O1WMtkUYWlfdLS7FjU4PnSJJHEfHXi/uHPI5EwltmOA794gN3bm3/pzuctWjQ==} - dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 - dev: true - /buffer@6.0.3: resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==} dependencies: @@ -3558,7 +3673,6 @@ packages: /bufferutil@4.0.9: resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} engines: {node: '>=6.14.2'} - requiresBuild: true dependencies: node-gyp-build: 4.8.4 dev: true @@ -3610,7 +3724,7 @@ packages: dependencies: clone-response: 1.0.3 get-stream: 5.2.0 - http-cache-semantics: 4.1.1 + http-cache-semantics: 4.2.0 keyv: 4.5.4 lowercase-keys: 2.0.0 normalize-url: 6.1.0 @@ -3635,8 +3749,8 @@ packages: set-function-length: 1.2.2 dev: true - /call-bound@1.0.3: - resolution: {integrity: sha512-YTd+6wGlNlPxSuri7Y6X8tY2dmm12UMH66RpKMhiX6rsk5wXXnYgbUcOt8kiS31/AjfoTOvCsE+w8nZQLQnzHA==} + /call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} engines: {node: '>= 0.4'} dependencies: call-bind-apply-helpers: 1.0.2 @@ -3653,13 +3767,13 @@ packages: engines: {node: '>=12.20'} dev: true - /caniuse-lite@1.0.30001701: - resolution: {integrity: sha512-faRs/AW3jA9nTwmJBSO1PQ6L/EOgsB5HMQQq4iCu5zhPgVVgO/pZRHlmatwijZKetFw8/Pr4q6dEN8sJuq8qTw==} + /caniuse-lite@1.0.30001727: + resolution: {integrity: sha512-pB68nIHmbN6L/4C6MH1DokyR3bYqFwjaSs/sWDHGj4CTcFtQUQMuJftVwWkXq7mNWOybD3KhUv3oWHoGxgP14Q==} dev: true - /cbor@9.0.2: - resolution: {integrity: sha512-JPypkxsB10s9QOWwa6zwPzqE1Md3vqpPc+cai4sAecuCsRyAtAl/pMyhPlMbT/xtPnm2dznJZYRLui57qiRhaQ==} - engines: {node: '>=16'} + /cbor@10.0.9: + resolution: {integrity: sha512-KEWYehb/vJkRmigctVQLsz73Us2RNnITo/wOwQV5AtZpLGH1r2PPlsNHdsX460YuHZCyhLklbYzAOuJfOeg34Q==} + engines: {node: '>=20'} dependencies: nofilter: 3.1.0 dev: true @@ -3721,12 +3835,17 @@ packages: engines: {node: '>=10'} dev: true + /chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} + dev: true + /chunkd@2.0.1: resolution: {integrity: sha512-7d58XsFmOq0j6el67Ug9mHf9ELUXsQXYJBkyxhH/k+6Ke0qXRnv0kbemx+Twc6fRJ07C49lcbdgm9FL1Ei/6SQ==} dev: true - /ci-info@4.1.0: - resolution: {integrity: sha512-HutrvTNsF48wnxkzERIXOe5/mlcfFcbfCmwcg6CJnizbSue78AbDt+1cgl26zwn61WFxhcPykPfZrbqjGmBb4A==} + /ci-info@4.3.0: + resolution: {integrity: sha512-l+2bNRMiQgcfILUi33labAZYIWlH1kWDp+ecNo5iisRKrbm0xcRyCww71/YU0Fkw0mAFpz9bJayXPjey6vkmaQ==} engines: {node: '>=8'} dev: true @@ -3815,6 +3934,11 @@ packages: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} dev: true + /commander@14.0.0: + resolution: {integrity: sha512-2uM9rYjPvyq39NwLRqaiLtWHyDC1FvryJDa2ATTVims5YAS4PupsEQsDvP14FqhFr0P49CYDugi59xaxJlTXRA==} + engines: {node: '>=20'} + dev: true + /commander@2.20.3: resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} dev: true @@ -3837,7 +3961,7 @@ packages: js-string-escape: 1.0.1 lodash: 4.17.21 md5-hex: 3.0.1 - semver: 7.7.1 + semver: 7.7.2 well-known-symbols: 2.0.0 dev: true @@ -3849,6 +3973,11 @@ packages: resolution: {integrity: sha512-JsPKdmh8ZkmnHxDk55FZ1TqVLvEQTvoByJZRN9jzI0UjxK/QgAmsphz7PGtqgPieQZ/CQcHWXCR7ATDNhGe+YA==} dev: true + /consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + dev: true + /console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: true @@ -3893,10 +4022,10 @@ packages: engines: {node: '>= 0.6'} dev: true - /core-js-compat@3.40.0: - resolution: {integrity: sha512-0XEDpr5y5mijvw8Lbc6E5AkjrHfp7eEoPlu36SWeAbcL8fn1G1ANe8DBlo2XoNN89oVpxWwOjYIPVzR4ZvsKCQ==} + /core-js-compat@3.44.0: + resolution: {integrity: sha512-JepmAj2zfl6ogy34qfWtcE7nHKAJnKsQFRn++scjVS2bZFllwptzw61BZcZFYBPpUznLfAvh0LGhxKppk04ClA==} dependencies: - browserslist: 4.24.4 + browserslist: 4.25.1 dev: true /core-util-is@1.0.3: @@ -3916,8 +4045,8 @@ packages: which: 2.0.2 dev: true - /css-what@6.1.0: - resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==} + /css-what@6.2.2: + resolution: {integrity: sha512-u/O3vwbptzhMs3L1fQE82ZSLHQQfto5gyZzwteVIEyeaY5Fc7R4dapF/BvRoSYFeqfBk4m0V1Vafq5Pjv25wvA==} engines: {node: '>= 6'} dev: true @@ -3947,7 +4076,7 @@ packages: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 dev: true @@ -3956,7 +4085,7 @@ packages: resolution: {integrity: sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 dev: true @@ -3965,7 +4094,7 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 is-data-view: 1.0.2 dev: true @@ -3980,7 +4109,6 @@ packages: /deasync@0.1.30: resolution: {integrity: sha512-OaAjvEQuQ9tJsKG4oHO9nV1UHTwb2Qc2+fadB0VeVtD0Z9wiG1XPGLJ4W3aLhAoQSYTaLROFRbd5X20Dkzf7MQ==} engines: {node: '>=0.11.0'} - requiresBuild: true dependencies: bindings: 1.5.0 node-addon-api: 1.7.2 @@ -4009,8 +4137,8 @@ packages: ms: 2.1.3 dev: true - /debug@4.4.0: - resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + /debug@4.4.1: + resolution: {integrity: sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ==} engines: {node: '>=6.0'} peerDependencies: supports-color: '*' @@ -4021,8 +4149,8 @@ packages: ms: 2.1.3 dev: true - /decode-named-character-reference@1.0.2: - resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==} + /decode-named-character-reference@1.2.0: + resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} dependencies: character-entities: 2.0.2 dev: true @@ -4034,8 +4162,8 @@ packages: mimic-response: 3.1.0 dev: true - /dedent@1.5.3: - resolution: {integrity: sha512-NHQtfOOW68WD8lgypbLA5oT+Bt0xXJhiYvoR6SmmNXZfpzOGXwdKWmcwG8N7PwVVWV3eF/68nmD9BaJSsTBhyQ==} + /dedent@1.6.0: + resolution: {integrity: sha512-F1Z+5UCFpmQUzJa11agbyPVMbpgT/qA3/SKyJ1jyBgm7dUcUEa8v9JwDkerSQXfakBwFljIxhOJqGkjUwZ9FSA==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: @@ -4124,8 +4252,8 @@ packages: engines: {node: '>=8'} dev: true - /detect-libc@2.0.3: - resolution: {integrity: sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==} + /detect-libc@2.0.4: + resolution: {integrity: sha512-3UDv+G9CsCKO1WKMGw9fwq/SWJYbI0c5Y7LU1AXYoDdbhE2AHQ6N6Nb34sG8Fj7T5APy8qXDCKuuIHd1BR0tVA==} engines: {node: '>=8'} dev: true @@ -4165,8 +4293,8 @@ packages: esutils: 2.0.3 dev: true - /dotenv@16.4.7: - resolution: {integrity: sha512-47qPchRCykZC03FhkYAhrvwU4xDBFIj1QPqaarj6mdM/hgUzfPHcpkHJOn3mJAufFeeAxAzeGsr5X0M4k6fLZQ==} + /dotenv@16.6.1: + resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} engines: {node: '>=12'} dev: true @@ -4182,20 +4310,25 @@ packages: /duplexify@3.7.1: resolution: {integrity: sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g==} dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 inherits: 2.0.4 readable-stream: 2.3.8 stream-shift: 1.0.3 dev: true - /edge-runtime@2.0.0: - resolution: {integrity: sha512-TmRJhKi4mlM1e+zgF4CSzVU5gJ1sWj7ia+XhVgZ8PYyYUxk4PPjJU8qScpSLsAbdSxoBghLxdMuwuCzdYLd1sQ==} + /eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + dev: true + + /edge-runtime@2.1.4: + resolution: {integrity: sha512-SertKByzAmjm+MkLbFl1q0ko+/90V24dhZgQM8fcdguQaDYVEVtb6okEBGeg8IQgL1/JUP8oSlUIxSI/bvsVRQ==} + engines: {node: '>=14'} hasBin: true dependencies: - '@edge-runtime/format': 1.1.0 - '@edge-runtime/vm': 2.0.0 + '@edge-runtime/format': 2.0.1 + '@edge-runtime/vm': 2.1.2 + async-listen: 2.0.3 exit-hook: 2.2.1 - http-status: 1.5.3 mri: 1.2.0 picocolors: 1.0.0 pretty-bytes: 5.6.0 @@ -4207,12 +4340,12 @@ packages: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} dev: true - /electron-to-chromium@1.5.108: - resolution: {integrity: sha512-tiGxpQmvXBEzrfU5ertmbCV/nG5yqCkC1G4T1SIKP335Y5rjXzPWmijR6XcoGXZvVoo4dknfdNe4Tl7lcIROLg==} + /electron-to-chromium@1.5.187: + resolution: {integrity: sha512-cl5Jc9I0KGUoOoSbxvTywTa40uspGJt/BDBoDLoxJRSBpWh4FFXBsjNRHfQrONsV/OoEjDfHUmZQa2d6Ze4YgA==} dev: true - /emittery@1.1.0: - resolution: {integrity: sha512-rsX7ktqARv/6UQDgMaLfIqUWAEzzbCQiVh7V9rhDXp6c37yoJcks12NVD+XPkgl4AEavmNhVfrhGoqYwIsMYYA==} + /emittery@1.2.0: + resolution: {integrity: sha512-KxdRyyFcS85pH3dnU8Y5yFUm2YJdaHwcBZWrfG8o89ZY9a13/f9itbN+YG3ELbBo9Pg5zvIozstmuV8bX13q6g==} engines: {node: '>=14.16'} dev: true @@ -4224,6 +4357,10 @@ packages: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} dev: true + /emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + dev: true + /emojis-list@3.0.0: resolution: {integrity: sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==} engines: {node: '>= 4'} @@ -4239,29 +4376,21 @@ packages: engines: {node: '>= 0.8'} dev: true - /end-of-stream@1.4.4: - resolution: {integrity: sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==} + /end-of-stream@1.4.5: + resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} dependencies: once: 1.4.0 dev: true - /enquirer@2.4.1: - resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} - engines: {node: '>=8.6'} - dependencies: - ansi-colors: 4.1.3 - strip-ansi: 6.0.1 - dev: true - - /es-abstract@1.23.9: - resolution: {integrity: sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==} + /es-abstract@1.24.0: + resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} engines: {node: '>= 0.4'} dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 data-view-buffer: 1.0.2 data-view-byte-length: 1.0.2 data-view-byte-offset: 1.0.1 @@ -4284,7 +4413,9 @@ packages: is-array-buffer: 3.0.5 is-callable: 1.2.7 is-data-view: 1.0.2 + is-negative-zero: 2.0.3 is-regex: 1.2.1 + is-set: 2.0.3 is-shared-array-buffer: 1.0.4 is-string: 1.1.1 is-typed-array: 1.1.15 @@ -4299,6 +4430,7 @@ packages: safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 + stop-iteration-iterator: 1.1.0 string.prototype.trim: 1.2.10 string.prototype.trimend: 1.0.9 string.prototype.trimstart: 1.0.8 @@ -4307,7 +4439,7 @@ packages: typed-array-byte-offset: 1.0.4 typed-array-length: 1.0.7 unbox-primitive: 1.1.0 - which-typed-array: 1.1.18 + which-typed-array: 1.1.19 dev: true /es-define-property@1.0.1: @@ -4368,7 +4500,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [android] - requiresBuild: true dev: true optional: true @@ -4377,7 +4508,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [android] - requiresBuild: true dev: true optional: true @@ -4386,7 +4516,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -4395,7 +4524,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [darwin] - requiresBuild: true dev: true optional: true @@ -4404,7 +4532,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -4413,7 +4540,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [freebsd] - requiresBuild: true dev: true optional: true @@ -4422,7 +4548,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [linux] - requiresBuild: true dev: true optional: true @@ -4431,7 +4556,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [linux] - requiresBuild: true dev: true optional: true @@ -4440,7 +4564,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [linux] - requiresBuild: true dev: true optional: true @@ -4449,7 +4572,6 @@ packages: engines: {node: '>=12'} cpu: [arm] os: [linux] - requiresBuild: true dev: true optional: true @@ -4458,7 +4580,6 @@ packages: engines: {node: '>=12'} cpu: [mips64el] os: [linux] - requiresBuild: true dev: true optional: true @@ -4467,7 +4588,6 @@ packages: engines: {node: '>=12'} cpu: [ppc64] os: [linux] - requiresBuild: true dev: true optional: true @@ -4476,7 +4596,6 @@ packages: engines: {node: '>=12'} cpu: [riscv64] os: [linux] - requiresBuild: true dev: true optional: true @@ -4485,7 +4604,6 @@ packages: engines: {node: '>=12'} cpu: [s390x] os: [linux] - requiresBuild: true dev: true optional: true @@ -4494,7 +4612,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [netbsd] - requiresBuild: true dev: true optional: true @@ -4503,7 +4620,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [openbsd] - requiresBuild: true dev: true optional: true @@ -4512,7 +4628,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [sunos] - requiresBuild: true dev: true optional: true @@ -4521,7 +4636,6 @@ packages: engines: {node: '>=12'} cpu: [ia32] os: [win32] - requiresBuild: true dev: true optional: true @@ -4530,7 +4644,6 @@ packages: engines: {node: '>=12'} cpu: [x64] os: [win32] - requiresBuild: true dev: true optional: true @@ -4539,7 +4652,6 @@ packages: engines: {node: '>=12'} cpu: [arm64] os: [win32] - requiresBuild: true dev: true optional: true @@ -4547,7 +4659,6 @@ packages: resolution: {integrity: sha512-wI4ZiIfFxpkuxB8ju4MHrGwGLyp1+awEHAHVpx6w7a+1pmYIq8T9FGEVVwFo0iFierDoMj++Xq69GXWYn2EiwA==} engines: {node: '>=12'} hasBin: true - requiresBuild: true optionalDependencies: esbuild-android-64: 0.14.47 esbuild-android-arm64: 0.14.47 @@ -4575,7 +4686,6 @@ packages: resolution: {integrity: sha512-71f7EjPWTiSguen8X/kxEpkAS7BFHwtQKisCDDV3Y4GLGWBaoSCyD5uXkaUew6JDzA9FEN1W23mdnSwW9kqCeg==} engines: {node: '>=12'} hasBin: true - requiresBuild: true optionalDependencies: '@esbuild/android-arm': 0.16.3 '@esbuild/android-arm64': 0.16.3 @@ -4605,7 +4715,6 @@ packages: resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} engines: {node: '>=12'} hasBin: true - requiresBuild: true optionalDependencies: '@esbuild/aix-ppc64': 0.19.12 '@esbuild/android-arm': 0.19.12 @@ -4636,7 +4745,6 @@ packages: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} hasBin: true - requiresBuild: true optionalDependencies: '@esbuild/aix-ppc64': 0.21.5 '@esbuild/android-arm': 0.21.5 @@ -4705,7 +4813,7 @@ packages: source-map: 0.6.1 dev: true - /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.26.0)(eslint@8.0.1): + /eslint-config-airbnb-base@15.0.0(eslint-plugin-import@2.32.0)(eslint@8.57.1): resolution: {integrity: sha512-xaX3z4ZZIcFLvh2oUNvcX5oEofXda7giYmuplVxoOg5A7EXJMrUyqRgR+mhDhPK8LZ4PttFOBvCYDbX3sUoUig==} engines: {node: ^10.12.0 || >=12.0.0} peerDependencies: @@ -4713,35 +4821,35 @@ packages: eslint-plugin-import: ^2.25.2 dependencies: confusing-browser-globals: 1.0.11 - eslint: 8.0.1 - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1) + eslint: 8.57.1 + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1) object.assign: 4.1.7 - object.entries: 1.1.8 + object.entries: 1.1.9 semver: 6.3.1 dev: true - /eslint-config-airbnb-typescript@17.0.0(@typescript-eslint/eslint-plugin@5.0.0)(@typescript-eslint/parser@5.46.1)(eslint-plugin-import@2.26.0)(eslint@8.0.1): - resolution: {integrity: sha512-elNiuzD0kPAPTXjFWg+lE24nMdHMtuxgYoD30OyMD6yrW1AhFZPAg27VX7d3tzOErw+dgJTNWfRSDqEcXb4V0g==} + /eslint-config-airbnb-typescript@17.1.0(@typescript-eslint/eslint-plugin@5.62.0)(@typescript-eslint/parser@5.62.0)(eslint-plugin-import@2.32.0)(eslint@8.57.1): + resolution: {integrity: sha512-GPxI5URre6dDpJ0CtcthSZVBAfI+Uw7un5OYNVxP2EYi3H81Jw701yFP7AU+/vCE7xBtFmjge7kfhhk4+RAiig==} peerDependencies: - '@typescript-eslint/eslint-plugin': ^5.13.0 - '@typescript-eslint/parser': ^5.0.0 + '@typescript-eslint/eslint-plugin': ^5.13.0 || ^6.0.0 + '@typescript-eslint/parser': ^5.0.0 || ^6.0.0 eslint: ^7.32.0 || ^8.2.0 eslint-plugin-import: ^2.25.3 dependencies: - '@typescript-eslint/eslint-plugin': 5.0.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1)(typescript@4.9.4) - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) - eslint: 8.0.1 - eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.26.0)(eslint@8.0.1) - eslint-plugin-import: 2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1)(typescript@4.9.5) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + eslint: 8.57.1 + eslint-config-airbnb-base: 15.0.0(eslint-plugin-import@2.32.0)(eslint@8.57.1) + eslint-plugin-import: 2.32.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1) dev: true - /eslint-config-prettier@8.5.0(eslint@8.0.1): - resolution: {integrity: sha512-obmWKLUNCnhtQRKc+tmnYuQl0pFU1ibYJQ5BGhTVB08bHe9wC8qUeG7c08dj9XX+AuPj1YSGSQIHl1pnDHZR0Q==} + /eslint-config-prettier@8.10.0(eslint@8.57.1): + resolution: {integrity: sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg==} hasBin: true peerDependencies: eslint: '>=7.0.0' dependencies: - eslint: 8.0.1 + eslint: 8.57.1 dev: true /eslint-import-resolver-node@0.3.9: @@ -4754,8 +4862,8 @@ packages: - supports-color dev: true - /eslint-module-utils@2.12.0(@typescript-eslint/parser@5.46.1)(eslint-import-resolver-node@0.3.9)(eslint@8.0.1): - resolution: {integrity: sha512-wALZ0HFoytlyh/1+4wuZ9FJCD/leWHQzzrxJ8+rebyReSLk7LApMyd3WJaLVoN+D5+WIdJyDK1c6JnE65V4Zyg==} + /eslint-module-utils@2.12.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.1): + resolution: {integrity: sha512-L8jSWTze7K2mTg0vos/RuLRS5soomksDPoJLXIslC7c8Wmut3bx7CPpJijDcBZtxQ5lrbUdM+s0OlNbz0DCDNw==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' @@ -4775,38 +4883,44 @@ packages: eslint-import-resolver-webpack: optional: true dependencies: - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) debug: 3.2.7 - eslint: 8.0.1 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 transitivePeerDependencies: - supports-color dev: true - /eslint-plugin-import@2.26.0(@typescript-eslint/parser@5.46.1)(eslint@8.0.1): - resolution: {integrity: sha512-hYfi3FXaM8WPLf4S1cikh/r4IxnO6zrhZbEGz2b660EJRbuxgpDS5gkCuYgGWg2xxh2rBuIr4Pvhve/7c31koA==} + /eslint-plugin-import@2.32.0(@typescript-eslint/parser@5.62.0)(eslint@8.57.1): + resolution: {integrity: sha512-whOE1HFo/qJDyX4SnXzP4N6zOWn79WhnCUY/iDR0mPfQZO8wcYE4JClzI2oZrhBnnMUCBCHZhO6VQyoBU95mZA==} engines: {node: '>=4'} peerDependencies: '@typescript-eslint/parser': '*' - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 + eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 peerDependenciesMeta: '@typescript-eslint/parser': optional: true dependencies: - '@typescript-eslint/parser': 5.46.1(eslint@8.0.1)(typescript@4.9.4) - array-includes: 3.1.8 + '@rtsao/scc': 1.1.0 + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@4.9.5) + array-includes: 3.1.9 + array.prototype.findlastindex: 1.2.6 array.prototype.flat: 1.3.3 - debug: 2.6.9 + array.prototype.flatmap: 1.3.3 + debug: 3.2.7 doctrine: 2.1.0 - eslint: 8.0.1 + eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@5.46.1)(eslint-import-resolver-node@0.3.9)(eslint@8.0.1) - has: 1.0.4 + eslint-module-utils: 2.12.1(@typescript-eslint/parser@5.62.0)(eslint-import-resolver-node@0.3.9)(eslint@8.57.1) + hasown: 2.0.2 is-core-module: 2.16.1 is-glob: 4.0.3 minimatch: 3.1.2 + object.fromentries: 2.0.8 + object.groupby: 1.0.3 object.values: 1.2.1 - resolve: 1.22.10 + semver: 6.3.1 + string.prototype.trimend: 1.0.9 tsconfig-paths: 3.15.0 transitivePeerDependencies: - eslint-import-resolver-typescript @@ -4814,7 +4928,7 @@ packages: - supports-color dev: true - /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.5.0)(eslint@8.0.1)(prettier@3.2.5): + /eslint-plugin-prettier@4.2.1(eslint-config-prettier@8.10.0)(eslint@8.57.1)(prettier@3.6.2): resolution: {integrity: sha512-f/0rXLXUt0oFYs8ra4w49wYZBG5GKZpAYsJSm6rnYL5uVDjd+zowwMwVZHnAjf4edNrKpCDYfXDgmRE/Ak7QyQ==} engines: {node: '>=12.0.0'} peerDependencies: @@ -4825,9 +4939,9 @@ packages: eslint-config-prettier: optional: true dependencies: - eslint: 8.0.1 - eslint-config-prettier: 8.5.0(eslint@8.0.1) - prettier: 3.2.5 + eslint: 8.57.1 + eslint-config-prettier: 8.10.0(eslint@8.57.1) + prettier: 3.6.2 prettier-linter-helpers: 1.0.0 dev: true @@ -4839,64 +4953,54 @@ packages: estraverse: 4.3.0 dev: true - /eslint-scope@6.0.0: - resolution: {integrity: sha512-uRDL9MWmQCkaFus8RF5K9/L/2fn+80yoW3jkD53l4shjCh26fCtvJGasxjUqP5OT87SYTxCVA3BwTUzuELx9kA==} + /eslint-scope@7.2.2: + resolution: {integrity: sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: esrecurse: 4.3.0 estraverse: 5.3.0 dev: true - /eslint-utils@3.0.0(eslint@8.0.1): - resolution: {integrity: sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==} - engines: {node: ^10.0.0 || ^12.0.0 || >= 14.0.0} - peerDependencies: - eslint: '>=5' - dependencies: - eslint: 8.0.1 - eslint-visitor-keys: 2.1.0 - dev: true - - /eslint-visitor-keys@2.1.0: - resolution: {integrity: sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==} - engines: {node: '>=10'} - dev: true - /eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true - /eslint@8.0.1: - resolution: {integrity: sha512-LsgcwZgQ72vZ+SMp4K6pAnk2yFDWL7Ti4pJaRvsZ0Hsw2h8ZjUIW38a9AFn2cZXdBMlScMFYYgsSp4ttFI/0bA==} + /eslint@8.57.1: + resolution: {integrity: sha512-ypowyDxpVSYpkXr9WPv2PAZCtNip1Mv5KTW0SCurXv/9iOpcrH9PaqUElksqEB6pChqHGDRCFTyrZlGhnLNGiA==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} deprecated: This version is no longer supported. Please see https://eslint.org/version-support for other options. hasBin: true dependencies: - '@eslint/eslintrc': 1.4.1 - '@humanwhocodes/config-array': 0.6.0 + '@eslint-community/eslint-utils': 4.7.0(eslint@8.57.1) + '@eslint-community/regexpp': 4.12.1 + '@eslint/eslintrc': 2.1.4 + '@eslint/js': 8.57.1 + '@humanwhocodes/config-array': 0.13.0 + '@humanwhocodes/module-importer': 1.0.1 + '@nodelib/fs.walk': 1.2.8 + '@ungap/structured-clone': 1.3.0 ajv: 6.12.6 chalk: 4.1.2 cross-spawn: 7.0.6 - debug: 4.4.0 + debug: 4.4.1 doctrine: 3.0.0 - enquirer: 2.4.1 escape-string-regexp: 4.0.0 - eslint-scope: 6.0.0 - eslint-utils: 3.0.0(eslint@8.0.1) + eslint-scope: 7.2.2 eslint-visitor-keys: 3.4.3 espree: 9.6.1 esquery: 1.6.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 file-entry-cache: 6.0.1 - functional-red-black-tree: 1.0.1 + find-up: 5.0.0 glob-parent: 6.0.2 globals: 13.24.0 - ignore: 4.0.6 - import-fresh: 3.3.1 + graphemer: 1.4.0 + ignore: 5.3.2 imurmurhash: 0.1.4 is-glob: 4.0.3 + is-path-inside: 3.0.3 js-yaml: 4.1.0 json-stable-stringify-without-jsonify: 1.0.1 levn: 0.4.1 @@ -4904,13 +5008,8 @@ packages: minimatch: 3.1.2 natural-compare: 1.4.0 optionator: 0.9.4 - progress: 2.0.3 - regexpp: 3.2.0 - semver: 7.7.1 strip-ansi: 6.0.1 - strip-json-comments: 3.1.1 text-table: 0.2.0 - v8-compile-cache: 2.4.0 transitivePeerDependencies: - supports-color dev: true @@ -4919,8 +5018,8 @@ packages: resolution: {integrity: sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) eslint-visitor-keys: 3.4.3 dev: true @@ -4957,7 +5056,7 @@ packages: /estree-util-attach-comments@2.1.1: resolution: {integrity: sha512-+5Ba/xGGS6mnwFbXIuQiDPTbuTxuMCooq3arVv7gPZtYpjp+VXH/NkHAP35OOefPhNG/UGqU3vt/LTABwcHX0w==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 dev: true /estree-util-build-jsx@2.2.2: @@ -5001,7 +5100,7 @@ packages: /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 dev: true /esutils@2.0.3: @@ -5018,12 +5117,12 @@ packages: resolution: {integrity: sha512-EzV94NYKoO09GLXGjXj9JIlXijVck4ONSr5wiCWDvhsvj5jxSrzTmRU/9C1DyB6uToszLs8aifA6NQ7lEQdvFw==} engines: {node: '>= 0.8'} dependencies: - '@types/node': 22.13.5 + '@types/node': 24.0.14 require-like: 0.1.2 dev: true - /eventemitter3@4.0.7: - resolution: {integrity: sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==} + /eventemitter3@5.0.1: + resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} dev: true /execa@5.1.1: @@ -5224,8 +5323,8 @@ packages: - supports-color dev: true - /find-up-simple@1.0.0: - resolution: {integrity: sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==} + /find-up-simple@1.0.1: + resolution: {integrity: sha512-afd4O7zpqHeRyg4PfDQsXmlDe2PfdHtJt6Akt8jOWaApLOZk5JXs6VMR29lz03pRe9mpykrRCYIYxaJYcfpncQ==} engines: {node: '>=18'} dev: true @@ -5257,6 +5356,14 @@ packages: is-callable: 1.2.7 dev: true + /foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + dev: true + /format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -5318,7 +5425,6 @@ packages: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - requiresBuild: true dev: true optional: true @@ -5339,17 +5445,13 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 define-properties: 1.2.1 functions-have-names: 1.2.3 hasown: 2.0.2 is-callable: 1.2.7 dev: true - /functional-red-black-tree@1.0.1: - resolution: {integrity: sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g==} - dev: true - /functions-have-names@1.2.3: resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} dev: true @@ -5359,7 +5461,7 @@ packages: engines: {node: '>=10'} deprecated: This package is no longer supported. dependencies: - aproba: 2.0.0 + aproba: 2.1.0 color-support: 1.1.3 console-control-strings: 1.1.0 has-unicode: 2.0.1 @@ -5424,7 +5526,7 @@ packages: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} dependencies: - pump: 3.0.2 + pump: 3.0.3 dev: true /get-stream@6.0.1: @@ -5441,7 +5543,7 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 dev: true @@ -5452,7 +5554,7 @@ packages: dependencies: '@tootallnate/once': 1.1.2 data-uri-to-buffer: 3.0.1 - debug: 4.4.0 + debug: 4.4.1 file-uri-to-path: 2.0.0 fs-extra: 8.1.0 ftp: 0.3.10 @@ -5478,6 +5580,22 @@ packages: is-glob: 4.0.3 dev: true + /glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: true + + /glob@10.4.5: + resolution: {integrity: sha512-7Bv8RF0k6xjo7d4A/PxYLbUCfb6c+Vpd2/mB2yRDlew7Jb5hEXiCD9ibfO7wpk8i4sevK6DFny9h7EYbM3/sHg==} + hasBin: true + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.2 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + dev: true + /glob@7.2.3: resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} deprecated: Glob versions prior to v9 are no longer supported @@ -5490,11 +5608,6 @@ packages: path-is-absolute: 1.0.1 dev: true - /globals@11.12.0: - resolution: {integrity: sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==} - engines: {node: '>=4'} - dev: true - /globals@13.24.0: resolution: {integrity: sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==} engines: {node: '>=8'} @@ -5517,7 +5630,7 @@ packages: '@types/glob': 7.2.0 array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.2.11 + fast-glob: 3.3.3 glob: 7.2.3 ignore: 5.3.2 merge2: 1.4.1 @@ -5542,7 +5655,7 @@ packages: dependencies: '@sindresorhus/merge-streams': 2.3.0 fast-glob: 3.3.3 - ignore: 7.0.3 + ignore: 7.0.5 path-type: 6.0.0 slash: 5.1.0 unicorn-magic: 0.3.0 @@ -5574,6 +5687,10 @@ packages: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true + /graphemer@1.4.0: + resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} + dev: true + /gunzip-maybe@1.4.2: resolution: {integrity: sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw==} hasBin: true @@ -5625,11 +5742,6 @@ packages: resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} dev: true - /has@1.0.4: - resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} - engines: {node: '>= 0.4.0'} - dev: true - /hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} @@ -5640,7 +5752,7 @@ packages: /hast-util-to-estree@2.3.3: resolution: {integrity: sha512-ihhPIUPxN0v0w6M5+IiAZZrn0LH2uZomeWwhn7uP7avZC6TE7lIiEh2yBMPr5+zi1aUCXq6VoYRgs2Bw9xmycQ==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 '@types/estree-jsx': 1.0.5 '@types/hast': 2.3.10 '@types/unist': 2.0.11 @@ -5663,8 +5775,8 @@ packages: resolution: {integrity: sha512-nAxA0v8+vXSBDt3AnRUNjyRIQ0rD+ntpbAp4LnPkumc5M9yUbSMa4XDU9Q6etY4f1Wp4bNgvc1yjiZtsTTrSng==} dev: true - /http-cache-semantics@4.1.1: - resolution: {integrity: sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==} + /http-cache-semantics@4.2.0: + resolution: {integrity: sha512-dTxcvPXqPvXBQpq5dUr6mEMJX4oIEFv6bwom3FDwKRDsuIjjJGANqhBuoAn9c1RQJIdAKav33ED65E2ys+87QQ==} dev: true /http-errors@2.0.0: @@ -5684,16 +5796,11 @@ packages: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.4.0 + debug: 4.4.1 transitivePeerDependencies: - supports-color dev: true - /http-status@1.5.3: - resolution: {integrity: sha512-jCClqdnnwigYslmtfb28vPplOgoiZ0siP2Z8C5Ua+3UKbx410v+c+jT+jh1bbI4TvcEySuX0vd/CfFZFbDkJeQ==} - engines: {node: '>= 0.4.0'} - dev: true - /http2-wrapper@1.0.3: resolution: {integrity: sha512-V+23sDMr12Wnz7iTcDeJr3O6AIxlnvT/bmaAAAP/Xda35C90p9599p0F1eHR/N1KILWSoWVAiOMFjBBXaXSMxg==} engines: {node: '>=10.19.0'} @@ -5707,7 +5814,17 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.4.0 + debug: 4.4.1 + transitivePeerDependencies: + - supports-color + dev: true + + /https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + dependencies: + agent-base: 7.1.4 + debug: 4.4.1 transitivePeerDependencies: - supports-color dev: true @@ -5735,13 +5852,13 @@ packages: safer-buffer: 2.1.2 dev: true - /icss-utils@5.1.0(postcss@8.5.3): + /icss-utils@5.1.0(postcss@8.5.6): resolution: {integrity: sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.5.3 + postcss: 8.5.6 dev: true /ieee754@1.2.1: @@ -5753,18 +5870,13 @@ packages: engines: {node: '>=10 <11 || >=12 <13 || >=14'} dev: true - /ignore@4.0.6: - resolution: {integrity: sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==} - engines: {node: '>= 4'} - dev: true - /ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} dev: true - /ignore@7.0.3: - resolution: {integrity: sha512-bAH5jbK/F3T3Jls4I0SO1hmPR0dKU0a7+SY6n1yzRtG54FLO8d6w/nxLFX2Nb7dBu6cCWXPaAME6cYqFUMmuCA==} + /ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} dev: true @@ -5879,7 +5991,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 get-intrinsic: 1.3.0 dev: true @@ -5888,7 +6000,7 @@ packages: engines: {node: '>= 0.4'} dependencies: async-function: 1.0.0 - call-bound: 1.0.3 + call-bound: 1.0.4 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 @@ -5912,7 +6024,7 @@ packages: resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 dev: true @@ -5937,7 +6049,7 @@ packages: resolution: {integrity: sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 get-intrinsic: 1.3.0 is-typed-array: 1.1.15 dev: true @@ -5946,7 +6058,7 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 dev: true @@ -5967,7 +6079,7 @@ packages: resolution: {integrity: sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 dev: true /is-fullwidth-code-point@3.0.0: @@ -5984,7 +6096,7 @@ packages: resolution: {integrity: sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 get-proto: 1.0.1 has-tostringtag: 1.0.2 safe-regex-test: 1.1.0 @@ -6016,11 +6128,16 @@ packages: engines: {node: '>= 0.4'} dev: true + /is-negative-zero@2.0.3: + resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} + engines: {node: '>= 0.4'} + dev: true + /is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 dev: true @@ -6029,6 +6146,11 @@ packages: engines: {node: '>=0.12.0'} dev: true + /is-path-inside@3.0.3: + resolution: {integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==} + engines: {node: '>=8'} + dev: true + /is-plain-obj@2.1.0: resolution: {integrity: sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==} engines: {node: '>=8'} @@ -6056,14 +6178,14 @@ packages: /is-reference@3.0.3: resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 dev: true /is-regex@1.2.1: resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 hasown: 2.0.2 @@ -6078,7 +6200,7 @@ packages: resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 dev: true /is-stream@2.0.1: @@ -6095,7 +6217,7 @@ packages: resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-tostringtag: 1.0.2 dev: true @@ -6103,7 +6225,7 @@ packages: resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-symbols: 1.1.0 safe-regex-test: 1.1.0 dev: true @@ -6112,7 +6234,7 @@ packages: resolution: {integrity: sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==} engines: {node: '>= 0.4'} dependencies: - which-typed-array: 1.1.18 + which-typed-array: 1.1.19 dev: true /is-unicode-supported@0.1.0: @@ -6134,14 +6256,14 @@ packages: resolution: {integrity: sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 dev: true /is-weakset@2.0.4: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 get-intrinsic: 1.3.0 dev: true @@ -6169,26 +6291,33 @@ packages: ws: 7.5.10 dev: true + /jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + dev: true + /javascript-stringify@2.1.0: resolution: {integrity: sha512-JVAfqNPTvNq3sB/VHQJAFxN/sPgKnsKrCwyRt15zwNCdrMMJDdcEOdubuy+DuJYYdm0ox1J4uzEuYKkN+9yhVg==} dev: true - /jayson@3.7.0: - resolution: {integrity: sha512-tfy39KJMrrXJ+mFcMpxwBvFDetS8LAID93+rycFglIQM4kl3uNR3W4lBLE/FFhsoUCEox5Dt2adVpDm/XtebbQ==} + /jayson@4.2.0: + resolution: {integrity: sha512-VfJ9t1YLwacIubLhONk0KFeosUBwstRWQ0IRT1KDjEjnVnSOVHC3uwugyV7L0c7R9lpVyrUGT2XWiBA1UTtpyg==} engines: {node: '>=8'} hasBin: true dependencies: '@types/connect': 3.4.38 '@types/node': 12.20.55 '@types/ws': 7.4.7 - JSONStream: 1.3.5 commander: 2.20.3 delay: 5.0.0 es6-promisify: 5.0.0 eyes: 0.1.8 isomorphic-ws: 4.0.1(ws@7.5.10) json-stringify-safe: 5.0.1 - lodash: 4.17.21 + stream-json: 1.9.1 uuid: 8.3.2 ws: 7.5.10 transitivePeerDependencies: @@ -6292,11 +6421,6 @@ packages: graceful-fs: 4.2.11 dev: true - /jsonparse@1.3.1: - resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} - engines: {'0': node >= 0.2.0} - dev: true - /keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} dependencies: @@ -6324,6 +6448,11 @@ packages: type-check: 0.4.0 dev: true + /lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + dev: true + /load-json-file@7.0.1: resolution: {integrity: sha512-Gnxj3ev3mB5TkVBGad0JM6dmLiQL+o0t23JPBZ9sd+yvSLk05mFoqKBw5N8gbbkU4TNXyqCgIrl/VM17OgUIgQ==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} @@ -6419,7 +6548,7 @@ packages: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} engines: {node: '>=8'} dependencies: - semver: 6.3.1 + semver: 6.1.1 dev: true /make-error@1.3.6: @@ -6469,7 +6598,7 @@ packages: dependencies: '@types/mdast': 3.0.15 '@types/unist': 2.0.11 - decode-named-character-reference: 1.0.2 + decode-named-character-reference: 1.2.0 mdast-util-to-string: 3.2.0 micromark: 3.2.0 micromark-util-decode-numeric-character-reference: 1.1.0 @@ -6585,7 +6714,7 @@ packages: /media-query-parser@2.0.2: resolution: {integrity: sha512-1N4qp+jE0pL5Xv4uEcwVUhIkwdUO3S/9gML90nqKA7v7FcOS5vUtatfzok9S9U1EJU8dHWlcv95WLnKmmxZI9w==} dependencies: - '@babel/runtime': 7.26.9 + '@babel/runtime': 7.27.6 dev: true /media-typer@0.3.0: @@ -6621,7 +6750,7 @@ packages: /micromark-core-commonmark@1.1.0: resolution: {integrity: sha512-BgHO1aRbolh2hcrzL2d1La37V0Aoz73ymF8rAcKnohLy93titmv62E0gP8Hrx9PKcKrqCZ1BbLGbP3bEhoXYlw==} dependencies: - decode-named-character-reference: 1.0.2 + decode-named-character-reference: 1.2.0 micromark-factory-destination: 1.1.0 micromark-factory-label: 1.1.0 micromark-factory-space: 1.1.0 @@ -6651,7 +6780,7 @@ packages: /micromark-extension-mdx-expression@1.0.8: resolution: {integrity: sha512-zZpeQtc5wfWKdzDsHRBY003H2Smg+PUi2REhqgIhdzAa5xonhP03FcXxqFSerFiNUr5AWmHpaNPQTBVOS4lrXw==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 micromark-factory-mdx-expression: 1.0.9 micromark-factory-space: 1.1.0 micromark-util-character: 1.2.0 @@ -6665,7 +6794,7 @@ packages: resolution: {integrity: sha512-gPH+9ZdmDflbu19Xkb8+gheqEDqkSpdCEubQyxuz/Hn8DOXiXvrXeikOoBA71+e8Pfi0/UYmU3wW3H58kr7akA==} dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 estree-util-is-identifier-name: 2.1.0 micromark-factory-mdx-expression: 1.0.9 micromark-factory-space: 1.1.0 @@ -6685,7 +6814,7 @@ packages: /micromark-extension-mdxjs-esm@1.0.5: resolution: {integrity: sha512-xNRBw4aoURcyz/S69B19WnZAkWJMxHMT5hE36GtDAyhoyn/8TuAeqjFJQlwk+MKQsUD7b3l7kFX+vlfVWgcX1w==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 micromark-core-commonmark: 1.1.0 micromark-util-character: 1.2.0 micromark-util-events-to-acorn: 1.2.3 @@ -6699,8 +6828,8 @@ packages: /micromark-extension-mdxjs@1.0.1: resolution: {integrity: sha512-7YA7hF6i5eKOfFUzZ+0z6avRG52GpWR8DL+kN47y3f2KhxbBZMhmxe7auOeaTBrW2DenbbZTf1ea9tA2hDpC2Q==} dependencies: - acorn: 8.14.0 - acorn-jsx: 5.3.2(acorn@8.14.0) + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) micromark-extension-mdx-expression: 1.0.8 micromark-extension-mdx-jsx: 1.0.5 micromark-extension-mdx-md: 1.0.1 @@ -6729,7 +6858,7 @@ packages: /micromark-factory-mdx-expression@1.0.9: resolution: {integrity: sha512-jGIWzSmNfdnkJq05c7b0+Wv0Kfz3NJ3N4cBjnbO4zjXIlxJr+f8lk+5ZmwFvqdAbUy2q6B5rCY//g0QAAaXDWA==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 micromark-util-character: 1.2.0 micromark-util-events-to-acorn: 1.2.3 micromark-util-symbol: 1.1.0 @@ -6801,7 +6930,7 @@ packages: /micromark-util-decode-string@1.1.0: resolution: {integrity: sha512-YphLGCK8gM1tG1bd54azwyrQRjCFcmgj2S2GoJDNnh4vYtnL38JS8M4gpxzOPNyHdNEpheyWXCTnnTDY3N+NVQ==} dependencies: - decode-named-character-reference: 1.0.2 + decode-named-character-reference: 1.2.0 micromark-util-character: 1.2.0 micromark-util-decode-numeric-character-reference: 1.1.0 micromark-util-symbol: 1.1.0 @@ -6815,7 +6944,7 @@ packages: resolution: {integrity: sha512-ij4X7Wuc4fED6UoLWkmo0xJQhsktfNh1J0m8g4PbIMPlx+ek/4YdW5mvbye8z/aZvAPUoxgXHrwVlXAPKMRp1w==} dependencies: '@types/acorn': 4.0.6 - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 '@types/unist': 2.0.11 estree-util-visit: 1.2.1 micromark-util-symbol: 1.1.0 @@ -6869,8 +6998,8 @@ packages: resolution: {integrity: sha512-uD66tJj54JLYq0De10AhWycZWGQNUvDI55xPgk2sQM5kn1JYlhbCMTtEeT27+vAhW2FBQxLlOmS3pmA7/2z4aA==} dependencies: '@types/debug': 4.1.12 - debug: 4.4.0 - decode-named-character-reference: 1.0.2 + debug: 4.4.1 + decode-named-character-reference: 1.2.0 micromark-core-commonmark: 1.1.0 micromark-factory-space: 1.1.0 micromark-util-character: 1.2.0 @@ -6943,14 +7072,21 @@ packages: /minimatch@3.1.2: resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} dependencies: - brace-expansion: 1.1.11 + brace-expansion: 1.1.12 dev: true - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + /minimatch@7.4.6: + resolution: {integrity: sha512-sBz8G/YjVniEz6lKPNpKxXwazJe4c19fEfV2GDMX6AjFz+MX9uDWIZW8XreVhkFW3fkIdTv/gxWr/Kks5FFAVw==} engines: {node: '>=10'} dependencies: - brace-expansion: 2.0.1 + brace-expansion: 2.0.2 + dev: true + + /minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.2 dev: true /minimist@1.2.8: @@ -6990,6 +7126,11 @@ packages: engines: {node: '>=8'} dev: true + /minipass@7.1.2: + resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + engines: {node: '>=16 || 14 >=14.17'} + dev: true + /minizlib@2.1.2: resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} engines: {node: '>= 8'} @@ -6998,6 +7139,13 @@ packages: yallist: 4.0.0 dev: true + /minizlib@3.0.2: + resolution: {integrity: sha512-oG62iEk+CYt5Xj2YqI5Xi9xWUeZhDI8jjQmC5oThVH5JGCTgIjr7ciJDzC7MBzYd//WvR1OTmP5Q38Q8ShQtVA==} + engines: {node: '>= 18'} + dependencies: + minipass: 7.1.2 + dev: true + /mkdirp-classic@0.5.3: resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} dev: true @@ -7008,13 +7156,19 @@ packages: hasBin: true dev: true + /mkdirp@3.0.1: + resolution: {integrity: sha512-+NsyUUAZDmo6YVHzL/stxSu3t9YS1iljliy3BSDrXJ/dkn1KYdmtZODGGjLcc9XLgVVpH4KshHB8XmZgMhaBXg==} + engines: {node: '>=10'} + hasBin: true + dev: true + /mlly@1.7.4: resolution: {integrity: sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==} dependencies: - acorn: 8.14.0 + acorn: 8.15.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.5.4 + ufo: 1.6.1 dev: true /modern-ahocorasick@1.1.0: @@ -7038,12 +7192,16 @@ packages: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true - /nanoid@3.3.8: - resolution: {integrity: sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==} + /nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true dev: true + /natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + dev: true + /natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} dev: true @@ -7109,6 +7267,14 @@ packages: abbrev: 1.1.1 dev: true + /nopt@8.1.0: + resolution: {integrity: sha512-ieGu42u/Qsa4TFktmaKEwM6MQH0pOWnaB3htzh0JRtx84+Mebc0cbZYN5bC+6WTZ4+77xrL9Pn5m7CV6VIkV7A==} + engines: {node: ^18.17.0 || >=20.5.0} + hasBin: true + dependencies: + abbrev: 3.0.1 + dev: true + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -7163,28 +7329,48 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 has-symbols: 1.1.0 object-keys: 1.1.1 dev: true - /object.entries@1.1.8: - resolution: {integrity: sha512-cmopxi8VwRIAw/fkijJohSfpef5PdN0pMQJN6VC/ZKvn0LIknWD8KtgY6KlQdEc4tIjcQ3HxSMmnvtzIscdaYQ==} + /object.entries@1.1.9: + resolution: {integrity: sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + call-bound: 1.0.4 + define-properties: 1.2.1 + es-object-atoms: 1.1.1 + dev: true + + /object.fromentries@2.0.8: + resolution: {integrity: sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 define-properties: 1.2.1 + es-abstract: 1.24.0 es-object-atoms: 1.1.1 dev: true + /object.groupby@1.0.3: + resolution: {integrity: sha512-+Lhy3TQTuzXI5hevh8sBGqbmurHbbIjAi0Z4S63nthVLmLxfbj4T54a4CfZrXIrt9iP4mVAPYMo/v99taj3wjQ==} + engines: {node: '>= 0.4'} + dependencies: + call-bind: 1.0.8 + define-properties: 1.2.1 + es-abstract: 1.24.0 + dev: true + /object.values@1.2.1: resolution: {integrity: sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==} engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 dev: true @@ -7310,7 +7496,7 @@ packages: dependencies: '@tootallnate/once': 1.1.2 agent-base: 6.0.2 - debug: 4.4.0 + debug: 4.4.1 get-uri: 3.0.2 http-proxy-agent: 4.0.1 https-proxy-agent: 5.0.1 @@ -7334,10 +7520,14 @@ packages: resolution: {integrity: sha512-GYTTew2slBcYdvRHqjhwaaydVMvn/qrGC323+nKclYioNSLTDUM/lGgtGTgyHVtYcozb+XkE8CNhwcraOmZ9Mg==} engines: {node: '>=18'} dependencies: - find-up-simple: 1.0.0 + find-up-simple: 1.0.1 load-json-file: 7.0.1 dev: true + /package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + dev: true + /pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} dev: true @@ -7355,7 +7545,7 @@ packages: '@types/unist': 2.0.11 character-entities-legacy: 3.0.0 character-reference-invalid: 2.0.1 - decode-named-character-reference: 1.0.2 + decode-named-character-reference: 1.2.0 is-alphanumerical: 2.0.1 is-decimal: 2.0.1 is-hexadecimal: 2.0.1 @@ -7404,6 +7594,14 @@ packages: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} dev: true + /path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.2 + dev: true + /path-to-regexp@0.1.12: resolution: {integrity: sha512-RA1GjUVMnvYFxuqovrEqZoxxW5NUZqbwKtYz/Tt7nXerk0LbLblQmrsgdeOxV5SFHf0UDggjS/bSeOZwt1pmEQ==} dev: true @@ -7445,7 +7643,7 @@ packages: /periscopic@3.1.0: resolution: {integrity: sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==} dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 estree-walker: 3.0.3 is-reference: 3.0.3 dev: true @@ -7463,9 +7661,9 @@ packages: engines: {node: '>=8.6'} dev: true - /picomatch@3.0.1: - resolution: {integrity: sha512-I3EurrIQMlRc9IaAZnqRR044Phh2DXY+55o7uJ0V+hYZAcQYSuFWsc9q5PvyDHUSCe1Qxn/iBz+78s86zWnGag==} - engines: {node: '>=10'} + /picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} dev: true /pkg-types@1.3.1: @@ -7488,69 +7686,86 @@ packages: engines: {node: '>= 0.4'} dev: true - /postcss-discard-duplicates@5.1.0(postcss@8.5.3): + /postcss-discard-duplicates@5.1.0(postcss@8.5.6): resolution: {integrity: sha512-zmX3IoSI2aoenxHV6C7plngHWWhUOV3sP1T8y2ifzxzbtnuhk1EdPwm0S1bIUNaJ2eNbWeGLEwzw8huPD67aQw==} engines: {node: ^10 || ^12 || >=14.0} peerDependencies: postcss: ^8.2.15 dependencies: - postcss: 8.5.3 + postcss: 8.5.6 dev: true - /postcss-modules-extract-imports@3.1.0(postcss@8.5.3): + /postcss-load-config@4.0.2(postcss@8.5.6): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.1.3 + postcss: 8.5.6 + yaml: 2.8.0 + dev: true + + /postcss-modules-extract-imports@3.1.0(postcss@8.5.6): resolution: {integrity: sha512-k3kNe0aNFQDAZGbin48pL2VNidTF0w4/eASDsxlyspobzU3wZQLOGj7L9gfRe0Jo9/4uud09DsjFNH7winGv8Q==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.5.3 + postcss: 8.5.6 dev: true - /postcss-modules-local-by-default@4.2.0(postcss@8.5.3): + /postcss-modules-local-by-default@4.2.0(postcss@8.5.6): resolution: {integrity: sha512-5kcJm/zk+GJDSfw+V/42fJ5fhjL5YbFDl8nVdXkJPLLW+Vf9mTD5Xe0wqIaDnLuL2U6cDNpTr+UQ+v2HWIBhzw==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.5.3) - postcss: 8.5.3 + icss-utils: 5.1.0(postcss@8.5.6) + postcss: 8.5.6 postcss-selector-parser: 7.1.0 postcss-value-parser: 4.2.0 dev: true - /postcss-modules-scope@3.2.1(postcss@8.5.3): + /postcss-modules-scope@3.2.1(postcss@8.5.6): resolution: {integrity: sha512-m9jZstCVaqGjTAuny8MdgE88scJnCiQSlSrOWcTQgM2t32UBe+MUmFSO5t7VMSfAf/FJKImAxBav8ooCHJXCJA==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - postcss: 8.5.3 + postcss: 8.5.6 postcss-selector-parser: 7.1.0 dev: true - /postcss-modules-values@4.0.0(postcss@8.5.3): + /postcss-modules-values@4.0.0(postcss@8.5.6): resolution: {integrity: sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==} engines: {node: ^10 || ^12 || >= 14} peerDependencies: postcss: ^8.1.0 dependencies: - icss-utils: 5.1.0(postcss@8.5.3) - postcss: 8.5.3 + icss-utils: 5.1.0(postcss@8.5.6) + postcss: 8.5.6 dev: true - /postcss-modules@6.0.1(postcss@8.5.3): + /postcss-modules@6.0.1(postcss@8.5.6): resolution: {integrity: sha512-zyo2sAkVvuZFFy0gc2+4O+xar5dYlaVy/ebO24KT0ftk/iJevSNyPyQellsBLlnccwh7f6V6Y4GvuKRYToNgpQ==} peerDependencies: postcss: ^8.0.0 dependencies: generic-names: 4.0.0 - icss-utils: 5.1.0(postcss@8.5.3) + icss-utils: 5.1.0(postcss@8.5.6) lodash.camelcase: 4.3.0 - postcss: 8.5.3 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.3) - postcss-modules-local-by-default: 4.2.0(postcss@8.5.3) - postcss-modules-scope: 3.2.1(postcss@8.5.3) - postcss-modules-values: 4.0.0(postcss@8.5.3) + postcss: 8.5.6 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.6) + postcss-modules-local-by-default: 4.2.0(postcss@8.5.6) + postcss-modules-scope: 3.2.1(postcss@8.5.6) + postcss-modules-values: 4.0.0(postcss@8.5.6) string-hash: 1.1.3 dev: true @@ -7566,11 +7781,11 @@ packages: resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} dev: true - /postcss@8.5.3: - resolution: {integrity: sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==} + /postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} engines: {node: ^10 || ^12 || >=14} dependencies: - nanoid: 3.3.8 + nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 dev: true @@ -7598,8 +7813,8 @@ packages: hasBin: true dev: true - /prettier@3.2.5: - resolution: {integrity: sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==} + /prettier@3.6.2: + resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} engines: {node: '>=14'} hasBin: true dev: true @@ -7627,11 +7842,6 @@ packages: resolution: {integrity: sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==} dev: true - /progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - dev: true - /promise-inflight@1.0.1: resolution: {integrity: sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==} peerDependencies: @@ -7658,7 +7868,7 @@ packages: engines: {node: '>= 8'} dependencies: agent-base: 6.0.2 - debug: 4.4.0 + debug: 4.4.1 http-proxy-agent: 4.0.1 https-proxy-agent: 5.0.1 lru-cache: 5.1.1 @@ -7676,14 +7886,14 @@ packages: /pump@2.0.1: resolution: {integrity: sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==} dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 dev: true - /pump@3.0.2: - resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} + /pump@3.0.3: + resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} dependencies: - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 once: 1.4.0 dev: true @@ -7731,6 +7941,11 @@ packages: unpipe: 1.0.0 dev: true + /react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + dev: true + /readable-stream@1.1.14: resolution: {integrity: sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==} dependencies: @@ -7784,7 +7999,7 @@ packages: dependencies: call-bind: 1.0.8 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-errors: 1.3.0 es-object-atoms: 1.1.1 get-intrinsic: 1.3.0 @@ -7807,16 +8022,6 @@ packages: resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} dev: true - /regenerator-runtime@0.14.1: - resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} - dev: true - - /regenerator-transform@0.15.2: - resolution: {integrity: sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==} - dependencies: - '@babel/runtime': 7.26.9 - dev: true - /regexp.prototype.flags@1.5.4: resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} engines: {node: '>= 0.4'} @@ -7829,11 +8034,6 @@ packages: set-function-name: 2.0.2 dev: true - /regexpp@3.2.0: - resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} - engines: {node: '>=8'} - dev: true - /regexpu-core@6.2.0: resolution: {integrity: sha512-H66BPQMrv+V16t8xtmq+UC0CBpiTBA60V8ibS1QVReIp8T1z8hwFxqcGzm9K6lgsN7sB5edVH8a+ze6Fqm4weA==} engines: {node: '>=4'} @@ -7988,41 +8188,46 @@ packages: estree-walker: 0.6.1 dev: true - /rollup@4.34.8: - resolution: {integrity: sha512-489gTVMzAYdiZHFVA/ig/iYFllCcWFHMvUHI1rpFmkoUtRlQxqh6/yiNqnYibjMZ2b/+FUQwldG+aLsEt6bglQ==} + /rollup@4.45.1: + resolution: {integrity: sha512-4iya7Jb76fVpQyLoiVpzUrsjQ12r3dM7fIVz+4NwoYvZOShknRmiv+iu9CClZml5ZLGb0XMcYLutK6w9tgxHDw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true dependencies: - '@types/estree': 1.0.6 + '@types/estree': 1.0.8 optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.34.8 - '@rollup/rollup-android-arm64': 4.34.8 - '@rollup/rollup-darwin-arm64': 4.34.8 - '@rollup/rollup-darwin-x64': 4.34.8 - '@rollup/rollup-freebsd-arm64': 4.34.8 - '@rollup/rollup-freebsd-x64': 4.34.8 - '@rollup/rollup-linux-arm-gnueabihf': 4.34.8 - '@rollup/rollup-linux-arm-musleabihf': 4.34.8 - '@rollup/rollup-linux-arm64-gnu': 4.34.8 - '@rollup/rollup-linux-arm64-musl': 4.34.8 - '@rollup/rollup-linux-loongarch64-gnu': 4.34.8 - '@rollup/rollup-linux-powerpc64le-gnu': 4.34.8 - '@rollup/rollup-linux-riscv64-gnu': 4.34.8 - '@rollup/rollup-linux-s390x-gnu': 4.34.8 - '@rollup/rollup-linux-x64-gnu': 4.34.8 - '@rollup/rollup-linux-x64-musl': 4.34.8 - '@rollup/rollup-win32-arm64-msvc': 4.34.8 - '@rollup/rollup-win32-ia32-msvc': 4.34.8 - '@rollup/rollup-win32-x64-msvc': 4.34.8 + '@rollup/rollup-android-arm-eabi': 4.45.1 + '@rollup/rollup-android-arm64': 4.45.1 + '@rollup/rollup-darwin-arm64': 4.45.1 + '@rollup/rollup-darwin-x64': 4.45.1 + '@rollup/rollup-freebsd-arm64': 4.45.1 + '@rollup/rollup-freebsd-x64': 4.45.1 + '@rollup/rollup-linux-arm-gnueabihf': 4.45.1 + '@rollup/rollup-linux-arm-musleabihf': 4.45.1 + '@rollup/rollup-linux-arm64-gnu': 4.45.1 + '@rollup/rollup-linux-arm64-musl': 4.45.1 + '@rollup/rollup-linux-loongarch64-gnu': 4.45.1 + '@rollup/rollup-linux-powerpc64le-gnu': 4.45.1 + '@rollup/rollup-linux-riscv64-gnu': 4.45.1 + '@rollup/rollup-linux-riscv64-musl': 4.45.1 + '@rollup/rollup-linux-s390x-gnu': 4.45.1 + '@rollup/rollup-linux-x64-gnu': 4.45.1 + '@rollup/rollup-linux-x64-musl': 4.45.1 + '@rollup/rollup-win32-arm64-msvc': 4.45.1 + '@rollup/rollup-win32-ia32-msvc': 4.45.1 + '@rollup/rollup-win32-x64-msvc': 4.45.1 fsevents: 2.3.3 dev: true - /rpc-websockets@7.11.2: - resolution: {integrity: sha512-pL9r5N6AVHlMN/vT98+fcO+5+/UcPLf/4tq+WUaid/PPUGS/ttJ3y8e9IqmaWKtShNAysMSjkczuEA49NuV7UQ==} + /rpc-websockets@9.1.1: + resolution: {integrity: sha512-1IXGM/TfPT6nfYMIXkJdzn+L4JEsmb0FL1O2OBjaH03V3yuUDdKFulGLMFG6ErV+8pZ5HVC0limve01RyO+saA==} dependencies: - eventemitter3: 4.0.7 + '@swc/helpers': 0.5.17 + '@types/uuid': 8.3.4 + '@types/ws': 8.18.1 + buffer: 6.0.3 + eventemitter3: 5.0.1 uuid: 8.3.2 - ws: 8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10) + ws: 8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10) optionalDependencies: bufferutil: 4.0.9 utf-8-validate: 5.0.10 @@ -8057,7 +8262,7 @@ packages: engines: {node: '>=0.4'} dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 isarray: 2.0.5 @@ -8083,7 +8288,7 @@ packages: resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 is-regex: 1.2.1 dev: true @@ -8102,8 +8307,16 @@ packages: hasBin: true dev: true - /semver@7.7.1: - resolution: {integrity: sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==} + /semver@7.3.8: + resolution: {integrity: sha512-NB1ctGL5rlHrPJtFDVIVzTyQylMLu9N9VICA6HSFJo8MCGVTMW6gfpicwKmmK/dAjTOrqu5l63JJOpDSrAis3A==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: true + + /semver@7.7.2: + resolution: {integrity: sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA==} engines: {node: '>=10'} hasBin: true dev: true @@ -8203,12 +8416,13 @@ packages: engines: {node: '>=8'} dev: true - /shiki@0.11.1: - resolution: {integrity: sha512-EugY9VASFuDqOexOgXR18ZV+TbFrQHeCpEYaXamO+SZlsnT/2LxuLBX25GGtIrwaEVFXUAbUQ601SWE2rMwWHA==} + /shiki@0.14.7: + resolution: {integrity: sha512-dNPAPrxSc87ua2sKJ3H5dQ/6ZaY8RNnaAqK+t0eG7p0Soi2ydiqbGOTaZCqaYvA/uZYfS1LJnemt3Q+mSfcPCg==} dependencies: + ansi-sequence-parser: 1.1.3 jsonc-parser: 3.3.1 vscode-oniguruma: 1.7.0 - vscode-textmate: 6.0.0 + vscode-textmate: 8.0.0 dev: true /side-channel-list@1.0.0: @@ -8223,7 +8437,7 @@ packages: resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 object-inspect: 1.13.4 @@ -8233,7 +8447,7 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 get-intrinsic: 1.3.0 object-inspect: 1.13.4 @@ -8288,14 +8502,14 @@ packages: engines: {node: '>= 6'} dependencies: agent-base: 6.0.2 - debug: 4.4.0 - socks: 2.8.4 + debug: 4.4.1 + socks: 2.8.6 transitivePeerDependencies: - supports-color dev: true - /socks@2.8.4: - resolution: {integrity: sha512-D3YaD0aRxR3mEcqnidIs7ReYJFVzWdd6fXJYUM8ixcQcJRGTka/b3saV0KflYhyVJXKhb947GndU35SxYNResQ==} + /socks@2.8.6: + resolution: {integrity: sha512-pe4Y2yzru68lXCb38aAqRf5gvN8YdjP1lok5o0J7BOHljkyCGKVz7H3vpVIXKD27rj2giOJ7DwVyk/GWrPHDWA==} engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} dependencies: ip-address: 9.0.5 @@ -8369,6 +8583,24 @@ packages: engines: {node: '>= 0.8'} dev: true + /stop-iteration-iterator@1.1.0: + resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} + engines: {node: '>= 0.4'} + dependencies: + es-errors: 1.3.0 + internal-slot: 1.1.0 + dev: true + + /stream-chain@2.2.5: + resolution: {integrity: sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==} + dev: true + + /stream-json@1.9.1: + resolution: {integrity: sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==} + dependencies: + stream-chain: 2.2.5 + dev: true + /stream-shift@1.0.3: resolution: {integrity: sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ==} dev: true @@ -8386,6 +8618,15 @@ packages: strip-ansi: 6.0.1 dev: true + /string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.1.0 + dev: true + /string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} @@ -8400,10 +8641,10 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.23.9 + es-abstract: 1.24.0 es-object-atoms: 1.1.1 has-property-descriptors: 1.0.2 dev: true @@ -8413,7 +8654,7 @@ packages: engines: {node: '>= 0.4'} dependencies: call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 define-properties: 1.2.1 es-object-atoms: 1.1.1 dev: true @@ -8490,8 +8731,9 @@ packages: inline-style-parser: 0.1.1 dev: true - /superstruct@0.14.2: - resolution: {integrity: sha512-nPewA6m9mR3d6k7WkZ8N8zpTWfenFH3q9pA2PkuiZxINr9DKB2+40wEQf0ixn8VaGuJ78AB6iWOtStI+/4FKZQ==} + /superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} dev: true /supertap@3.0.1: @@ -8516,12 +8758,12 @@ packages: engines: {node: '>= 0.4'} dev: true - /tar-fs@2.1.2: - resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} + /tar-fs@2.1.3: + resolution: {integrity: sha512-090nwYJDmlhwFwEW3QQl+vaNnxsO2yVsd45eTKRBzSzu+hlb1w2K9inVq5b0ngXuLVqQ4ApvsUHHnu/zQNkWAg==} dependencies: chownr: 1.1.4 mkdirp-classic: 0.5.3 - pump: 3.0.2 + pump: 3.0.3 tar-stream: 2.2.0 dev: true @@ -8530,7 +8772,7 @@ packages: engines: {node: '>=6'} dependencies: bl: 4.1.0 - end-of-stream: 1.4.4 + end-of-stream: 1.4.5 fs-constants: 1.0.0 inherits: 2.0.4 readable-stream: 3.6.2 @@ -8548,6 +8790,18 @@ packages: yallist: 4.0.0 dev: true + /tar@7.4.3: + resolution: {integrity: sha512-5S7Va8hKfV7W5U6g3aYxXmlPoZVAwUMy9AOKyF2fVuZa2UD3qZjg578OrLRt8PcNN1PleVaL/5/yYATNL0ICUw==} + engines: {node: '>=18'} + dependencies: + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.2 + minizlib: 3.0.2 + mkdirp: 3.0.1 + yallist: 5.0.0 + dev: true + /temp-dir@3.0.0: resolution: {integrity: sha512-nHc6S/bwIilKHNRgK/3jlhDoIHcp45YgyiwcAk46Tr0LfEqGBVpmiAyuiuxeVE44m3mXnEeVhaipLOEWmH+Njw==} engines: {node: '>=14.16'} @@ -8642,7 +8896,7 @@ packages: '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 '@types/node': 14.18.33 - acorn: 8.14.0 + acorn: 8.15.0 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 @@ -8683,14 +8937,14 @@ packages: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} dev: true - /tsutils@3.21.0(typescript@4.9.4): + /tsutils@3.21.0(typescript@4.9.5): resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} engines: {node: '>= 6'} peerDependencies: typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' dependencies: tslib: 1.14.1 - typescript: 4.9.4 + typescript: 4.9.5 dev: true /type-check@0.3.2: @@ -8734,7 +8988,7 @@ packages: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 es-errors: 1.3.0 is-typed-array: 1.1.15 dev: true @@ -8775,34 +9029,34 @@ packages: reflect.getprototypeof: 1.0.10 dev: true - /typedoc-plugin-expand-object-like-types@0.1.1(typedoc@0.23.16): - resolution: {integrity: sha512-h7iw2qugVqEevlqMK4VeAPHMegg63v6zRjvGMoRfsc4ygoCttFYDs05PyLQNwxjEbXZLvGK9TTzig/oHiXUOJg==} + /typedoc-plugin-expand-object-like-types@0.1.2(typedoc@0.23.28): + resolution: {integrity: sha512-RRMOCWMElQHBOVraWMWrh/0tDqCdS5oxYwaWMZBB3KlUUUUCxKllpvJPsRH/uFLO1nOuy28CbJxGVU1umv7LOQ==} peerDependencies: typedoc: 0.22.x || 0.23.x dependencies: - typedoc: 0.23.16(typescript@4.9.4) + typedoc: 0.23.28(typescript@4.9.5) dev: true - /typedoc-plugin-missing-exports@1.0.0(typedoc@0.23.16): + /typedoc-plugin-missing-exports@1.0.0(typedoc@0.23.28): resolution: {integrity: sha512-7s6znXnuAj1eD9KYPyzVzR1lBF5nwAY8IKccP5sdoO9crG4lpd16RoFpLsh2PccJM+I2NASpr0+/NMka6ThwVA==} peerDependencies: typedoc: 0.22.x || 0.23.x dependencies: - typedoc: 0.23.16(typescript@4.9.4) + typedoc: 0.23.28(typescript@4.9.5) dev: true - /typedoc@0.23.16(typescript@4.9.4): - resolution: {integrity: sha512-rumYsCeNRXlyuZVzefD7050n7ptL2uudsCJg50dY0v/stKniqIlRpvx/F/6expC0/Q6Dbab+g/JpZuB7Sw90FA==} + /typedoc@0.23.28(typescript@4.9.5): + resolution: {integrity: sha512-9x1+hZWTHEQcGoP7qFmlo4unUoVJLB0H/8vfO/7wqTnZxg4kPuji9y3uRzEu0ZKez63OJAUmiGhUrtukC6Uj3w==} engines: {node: '>= 14.14'} hasBin: true peerDependencies: - typescript: 4.6.x || 4.7.x || 4.8.x + typescript: 4.6.x || 4.7.x || 4.8.x || 4.9.x || 5.0.x dependencies: lunr: 2.3.9 marked: 4.3.0 - minimatch: 5.1.6 - shiki: 0.11.1 - typescript: 4.9.4 + minimatch: 7.4.6 + shiki: 0.14.7 + typescript: 4.9.5 dev: true /typescript@4.3.4: @@ -8811,28 +9065,28 @@ packages: hasBin: true dev: true - /typescript@4.9.4: - resolution: {integrity: sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg==} + /typescript@4.9.5: + resolution: {integrity: sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==} engines: {node: '>=4.2.0'} hasBin: true dev: true - /ufo@1.5.4: - resolution: {integrity: sha512-UsUk3byDzKd04EyoZ7U4DOlxQaD14JUKQl6/P7wiX4FNvUfm3XL246n9W5AmqwW5RSFJ27NAuM0iLscAOYUiGQ==} + /ufo@1.6.1: + resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} dev: true /unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 has-bigints: 1.1.0 has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 dev: true - /undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + /undici-types@7.8.0: + resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} dev: true /unicode-canonical-property-names-ecmascript@2.0.1: @@ -8958,13 +9212,13 @@ packages: engines: {node: '>= 0.8'} dev: true - /update-browserslist-db@1.1.3(browserslist@4.24.4): + /update-browserslist-db@1.1.3(browserslist@4.25.1): resolution: {integrity: sha512-UxhIZQ+QInVdunkDAaiazvvT/+fXL5Osr0JZlJulepYu6Jd7qJtDZjlur0emRlT71EN3ScPoE7gvsuIKKNavKw==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' dependencies: - browserslist: 4.24.4 + browserslist: 4.25.1 escalade: 3.2.0 picocolors: 1.1.1 dev: true @@ -8978,7 +9232,6 @@ packages: /utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} - requiresBuild: true dependencies: node-gyp-build: 4.8.4 dev: true @@ -9012,31 +9265,26 @@ packages: resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==} dev: true - /v8-compile-cache@2.4.0: - resolution: {integrity: sha512-ocyWc3bAHBB/guyqJQVI5o4BZkPhznPYUG2ea80Gond/BgNWpap8TOmLSeeQG7bnh2KMISxskdADG59j7zruhw==} - dev: true - /vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} dev: true - /vercel@28.16.0(@types/node@14.18.33): - resolution: {integrity: sha512-+YaWIhdShkEz6o36CPmMP0+vYUd+cBJi4rhYCYC6nm86uOCEK1eJDoW1bkCFxTIFDSTSuzbbSmI69jsYIkN3bg==} + /vercel@28.20.0(@types/node@24.0.14): + resolution: {integrity: sha512-U+ZDKVVgxJyUJ26l/B7o53EeocP4PnbCt7D6Qyt/bI/eJ9BXpBtsWtMJf1CvgH3Iv/QRXFYlCvjHQJLs1BC7qw==} engines: {node: '>= 14'} hasBin: true - requiresBuild: true - dependencies: - '@vercel/build-utils': 6.3.0 - '@vercel/go': 2.3.7 - '@vercel/hydrogen': 0.0.53 - '@vercel/next': 3.4.7 - '@vercel/node': 2.9.6 - '@vercel/python': 3.1.49 - '@vercel/redwood': 1.1.5 - '@vercel/remix': 1.3.3(@types/node@14.18.33) - '@vercel/ruby': 1.3.65 - '@vercel/static-build': 1.3.9 + dependencies: + '@vercel/build-utils': 6.7.1 + '@vercel/go': 2.5.0 + '@vercel/hydrogen': 0.0.63 + '@vercel/next': 3.7.5 + '@vercel/node': 2.12.0 + '@vercel/python': 3.1.59 + '@vercel/redwood': 1.1.14 + '@vercel/remix-builder': 1.8.5(@types/node@24.0.14) + '@vercel/ruby': 1.3.75 + '@vercel/static-build': 1.3.25 transitivePeerDependencies: - '@remix-run/serve' - '@swc/core' @@ -9054,6 +9302,7 @@ packages: - sugarss - supports-color - terser + - ts-node - utf-8-validate dev: true @@ -9073,16 +9322,16 @@ packages: vfile-message: 3.1.4 dev: true - /vite-node@1.6.1(@types/node@14.18.33): + /vite-node@1.6.1(@types/node@24.0.14): resolution: {integrity: sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true dependencies: cac: 6.7.14 - debug: 4.4.0 + debug: 4.4.1 pathe: 1.1.2 picocolors: 1.1.1 - vite: 5.4.14(@types/node@14.18.33) + vite: 5.4.19(@types/node@24.0.14) transitivePeerDependencies: - '@types/node' - less @@ -9095,8 +9344,8 @@ packages: - terser dev: true - /vite@5.4.14(@types/node@14.18.33): - resolution: {integrity: sha512-EK5cY7Q1D8JNhSaPKVK4pwBFvaTmZxEnoKXLG/U9gmdDcihQGNzFlgIvaxezFR4glP1LsuiedwMBqCXH3wZccA==} + /vite@5.4.19(@types/node@24.0.14): + resolution: {integrity: sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -9126,10 +9375,10 @@ packages: terser: optional: true dependencies: - '@types/node': 14.18.33 + '@types/node': 24.0.14 esbuild: 0.21.5 - postcss: 8.5.3 - rollup: 4.34.8 + postcss: 8.5.6 + rollup: 4.45.1 optionalDependencies: fsevents: 2.3.3 dev: true @@ -9140,7 +9389,7 @@ packages: deprecated: The library contains critical security issues and should not be used for production! The maintenance of the project has been discontinued. Consider migrating your code to isolated-vm. hasBin: true dependencies: - acorn: 8.14.0 + acorn: 8.15.0 acorn-walk: 8.3.4 dev: true @@ -9148,8 +9397,8 @@ packages: resolution: {integrity: sha512-L9WMGRfrjOhgHSdOYgCt/yRMsXzLDJSL7BPrOZt73gU0iWO4mpqzqQzOz5srxqTvMBaR0XZTSrVWo4j55Rc6cA==} dev: true - /vscode-textmate@6.0.0: - resolution: {integrity: sha512-gu73tuZfJgu+mvCSy4UZwd2JXykjK9zAZsfmDeut5dx/1a7FeTk0XwJsSuqQn+cuMCGVbIBfl+s53X4T19DnzQ==} + /vscode-textmate@8.0.0: + resolution: {integrity: sha512-AFbieoL7a5LMqcnOF04ji+rpXadgOXnZsxQr//r83kLPr7biP7am3g9zbaZIaBGwBRWeSvoMD4mgPdX3e4NWBg==} dev: true /wcwidth@1.0.1: @@ -9193,7 +9442,7 @@ packages: resolution: {integrity: sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==} engines: {node: '>= 0.4'} dependencies: - call-bound: 1.0.3 + call-bound: 1.0.4 function.prototype.name: 1.1.8 has-tostringtag: 1.0.2 is-async-function: 2.1.1 @@ -9205,7 +9454,7 @@ packages: isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.18 + which-typed-array: 1.1.19 dev: true /which-collection@1.0.2: @@ -9218,14 +9467,15 @@ packages: is-weakset: 2.0.4 dev: true - /which-typed-array@1.1.18: - resolution: {integrity: sha512-qEcY+KJYlWyLH9vNbsr6/5j59AXk5ni5aakf8ldzBvGde6Iz4sxZGkJyWSAueTG7QhOvNRYb1lDdFmL5Td0QKA==} + /which-typed-array@1.1.19: + resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} engines: {node: '>= 0.4'} dependencies: available-typed-arrays: 1.0.7 call-bind: 1.0.8 - call-bound: 1.0.3 + call-bound: 1.0.4 for-each: 0.3.5 + get-proto: 1.0.1 gopd: 1.2.0 has-tostringtag: 1.0.2 dev: true @@ -9267,13 +9517,22 @@ packages: strip-ansi: 6.0.1 dev: true + /wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + dependencies: + ansi-styles: 6.2.1 + string-width: 5.1.2 + strip-ansi: 7.1.0 + dev: true + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} dev: true - /write-file-atomic@5.0.1: - resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} - engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + /write-file-atomic@6.0.0: + resolution: {integrity: sha512-GmqrO8WJ1NuzJ2DrziEI2o57jKAVIQNf8a18W3nCYU3H7PNWqCCVTeH6/NQE93CIllIgQS98rrmVkYgTX9fFJQ==} + engines: {node: ^18.17.0 || >=20.5.0} dependencies: imurmurhash: 0.1.4 signal-exit: 4.1.0 @@ -9292,8 +9551,8 @@ packages: optional: true dev: true - /ws@8.18.1(bufferutil@4.0.9)(utf-8-validate@5.0.10): - resolution: {integrity: sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==} + /ws@8.18.3(bufferutil@4.0.9)(utf-8-validate@5.0.10): + resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -9360,9 +9619,14 @@ packages: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} dev: true - /yaml@2.7.0: - resolution: {integrity: sha512-+hSoy/QHluxmC9kCIJyL/uyFmLmc+e5CFR5Wa+bpIhIj85LVb9ZH2nVnqrHoSvKogwODv0ClqZkmiSSaIH5LTA==} - engines: {node: '>= 14'} + /yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + dev: true + + /yaml@2.8.0: + resolution: {integrity: sha512-4lLa/EcQCB0cJkyts+FpIRx5G/llPxfP6VQU5KByHEhLxY3IJCH0f0Hy1MHI8sClTvsIb8qwRJ6R/ZdlDJ/leQ==} + engines: {node: '>= 14.6'} hasBin: true dev: true diff --git a/clients/js/src/generated/accounts/groupV1.ts b/clients/js/src/generated/accounts/groupV1.ts new file mode 100644 index 00000000..4e38fceb --- /dev/null +++ b/clients/js/src/generated/accounts/groupV1.ts @@ -0,0 +1,122 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Account, + Context, + Pda, + PublicKey, + RpcAccount, + RpcGetAccountOptions, + RpcGetAccountsOptions, + assertAccountExists, + deserializeAccount, + gpaBuilder, + publicKey as toPublicKey, +} from '@metaplex-foundation/umi'; +import { + array, + publicKey as publicKeySerializer, + string, +} from '@metaplex-foundation/umi/serializers'; +import { + GroupV1AccountData, + getGroupV1AccountDataSerializer, +} from '../../hooked'; +import { Key, KeyArgs, getKeySerializer } from '../types'; + +export type GroupV1 = Account; + +export function deserializeGroupV1(rawAccount: RpcAccount): GroupV1 { + return deserializeAccount(rawAccount, getGroupV1AccountDataSerializer()); +} + +export async function fetchGroupV1( + context: Pick, + publicKey: PublicKey | Pda, + options?: RpcGetAccountOptions +): Promise { + const maybeAccount = await context.rpc.getAccount( + toPublicKey(publicKey, false), + options + ); + assertAccountExists(maybeAccount, 'GroupV1'); + return deserializeGroupV1(maybeAccount); +} + +export async function safeFetchGroupV1( + context: Pick, + publicKey: PublicKey | Pda, + options?: RpcGetAccountOptions +): Promise { + const maybeAccount = await context.rpc.getAccount( + toPublicKey(publicKey, false), + options + ); + return maybeAccount.exists ? deserializeGroupV1(maybeAccount) : null; +} + +export async function fetchAllGroupV1( + context: Pick, + publicKeys: Array, + options?: RpcGetAccountsOptions +): Promise { + const maybeAccounts = await context.rpc.getAccounts( + publicKeys.map((key) => toPublicKey(key, false)), + options + ); + return maybeAccounts.map((maybeAccount) => { + assertAccountExists(maybeAccount, 'GroupV1'); + return deserializeGroupV1(maybeAccount); + }); +} + +export async function safeFetchAllGroupV1( + context: Pick, + publicKeys: Array, + options?: RpcGetAccountsOptions +): Promise { + const maybeAccounts = await context.rpc.getAccounts( + publicKeys.map((key) => toPublicKey(key, false)), + options + ); + return maybeAccounts + .filter((maybeAccount) => maybeAccount.exists) + .map((maybeAccount) => deserializeGroupV1(maybeAccount as RpcAccount)); +} + +export function getGroupV1GpaBuilder( + context: Pick +) { + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + return gpaBuilder(context, programId) + .registerFields<{ + key: KeyArgs; + updateAuthority: PublicKey; + name: string; + uri: string; + collections: Array; + groups: Array; + parentGroups: Array; + assets: Array; + }>({ + key: [0, getKeySerializer()], + updateAuthority: [1, publicKeySerializer()], + name: [33, string()], + uri: [null, string()], + collections: [null, array(publicKeySerializer())], + groups: [null, array(publicKeySerializer())], + parentGroups: [null, array(publicKeySerializer())], + assets: [null, array(publicKeySerializer())], + }) + .deserializeUsing((account) => deserializeGroupV1(account)) + .whereField('key', Key.GroupV1); +} diff --git a/clients/js/src/generated/accounts/index.ts b/clients/js/src/generated/accounts/index.ts index aa39fc2a..f2b2868a 100644 --- a/clients/js/src/generated/accounts/index.ts +++ b/clients/js/src/generated/accounts/index.ts @@ -9,6 +9,7 @@ export * from './assetSigner'; export * from './assetV1'; export * from './collectionV1'; +export * from './groupV1'; export * from './hashedAssetV1'; export * from './pluginHeaderV1'; export * from './pluginRegistryV1'; diff --git a/clients/js/src/generated/errors/mplCore.ts b/clients/js/src/generated/errors/mplCore.ts index d65fab29..7ab06793 100644 --- a/clients/js/src/generated/errors/mplCore.ts +++ b/clients/js/src/generated/errors/mplCore.ts @@ -726,17 +726,115 @@ export class InvalidExecutePdaError extends ProgramError { codeToErrorMap.set(0x31, InvalidExecutePdaError); nameToErrorMap.set('InvalidExecutePda', InvalidExecutePdaError); +/** BlockedByBubblegumV2: Bubblegum V2 Plugin limits other plugins */ +export class BlockedByBubblegumV2Error extends ProgramError { + override readonly name: string = 'BlockedByBubblegumV2'; + + readonly code: number = 0x32; // 50 + + constructor(program: Program, cause?: Error) { + super('Bubblegum V2 Plugin limits other plugins', program, cause); + } +} +codeToErrorMap.set(0x32, BlockedByBubblegumV2Error); +nameToErrorMap.set('BlockedByBubblegumV2', BlockedByBubblegumV2Error); + +/** AgentIdentityMustSign: Agent Identity Program must sign */ +export class AgentIdentityMustSignError extends ProgramError { + override readonly name: string = 'AgentIdentityMustSign'; + + readonly code: number = 0x33; // 51 + + constructor(program: Program, cause?: Error) { + super('Agent Identity Program must sign', program, cause); + } +} +codeToErrorMap.set(0x33, AgentIdentityMustSignError); +nameToErrorMap.set('AgentIdentityMustSign', AgentIdentityMustSignError); + +/** GroupMustBeEmpty: Group must be empty to be closed */ +export class GroupMustBeEmptyError extends ProgramError { + override readonly name: string = 'GroupMustBeEmpty'; + + readonly code: number = 0x34; // 52 + + constructor(program: Program, cause?: Error) { + super('Group must be empty to be closed', program, cause); + } +} +codeToErrorMap.set(0x34, GroupMustBeEmptyError); +nameToErrorMap.set('GroupMustBeEmpty', GroupMustBeEmptyError); + +/** DuplicateEntry: Duplicate entry provided when adding relationships to a group */ +export class DuplicateEntryError extends ProgramError { + override readonly name: string = 'DuplicateEntry'; + + readonly code: number = 0x35; // 53 + + constructor(program: Program, cause?: Error) { + super( + 'Duplicate entry provided when adding relationships to a group', + program, + cause + ); + } +} +codeToErrorMap.set(0x35, DuplicateEntryError); +nameToErrorMap.set('DuplicateEntry', DuplicateEntryError); + +/** GroupVectorFull: Group vector is at maximum capacity */ +export class GroupVectorFullError extends ProgramError { + override readonly name: string = 'GroupVectorFull'; + + readonly code: number = 0x36; // 54 + + constructor(program: Program, cause?: Error) { + super('Group vector is at maximum capacity', program, cause); + } +} +codeToErrorMap.set(0x36, GroupVectorFullError); +nameToErrorMap.set('GroupVectorFull', GroupVectorFullError); + +/** GroupNestingDepthExceeded: Group nesting depth exceeded */ +export class GroupNestingDepthExceededError extends ProgramError { + override readonly name: string = 'GroupNestingDepthExceeded'; + + readonly code: number = 0x37; // 55 + + constructor(program: Program, cause?: Error) { + super('Group nesting depth exceeded', program, cause); + } +} +codeToErrorMap.set(0x37, GroupNestingDepthExceededError); +nameToErrorMap.set('GroupNestingDepthExceeded', GroupNestingDepthExceededError); + +/** InconsistentGroupRelationship: Bidirectional group relationship is inconsistent */ +export class InconsistentGroupRelationshipError extends ProgramError { + override readonly name: string = 'InconsistentGroupRelationship'; + + readonly code: number = 0x38; // 56 + + constructor(program: Program, cause?: Error) { + super('Bidirectional group relationship is inconsistent', program, cause); + } +} +codeToErrorMap.set(0x38, InconsistentGroupRelationshipError); +nameToErrorMap.set( + 'InconsistentGroupRelationship', + InconsistentGroupRelationshipError +); + /** PluginNotAllowedOnAsset: Plugin is not allowed to be added to an Asset */ export class PluginNotAllowedOnAssetError extends ProgramError { override readonly name: string = 'PluginNotAllowedOnAsset'; - readonly code: number = 0x32; // 50 + readonly code: number = 0x39; // 57 constructor(program: Program, cause?: Error) { super('Plugin is not allowed to be added to an Asset', program, cause); } } -codeToErrorMap.set(0x32, PluginNotAllowedOnAssetError); +codeToErrorMap.set(0x39, PluginNotAllowedOnAssetError); nameToErrorMap.set('PluginNotAllowedOnAsset', PluginNotAllowedOnAssetError); /** diff --git a/clients/js/src/generated/instructions/addAssetsToGroupV1.ts b/clients/js/src/generated/instructions/addAssetsToGroupV1.ts new file mode 100644 index 00000000..799f9445 --- /dev/null +++ b/clients/js/src/generated/instructions/addAssetsToGroupV1.ts @@ -0,0 +1,133 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + mapSerializer, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type AddAssetsToGroupV1InstructionAccounts = { + /** The address of the group to modify */ + group: PublicKey | Pda; + /** The account paying for storage fees */ + payer?: Signer; + /** The group update authority and asset update authority or delegate */ + authority?: Signer; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type AddAssetsToGroupV1InstructionData = { discriminator: number }; + +export type AddAssetsToGroupV1InstructionDataArgs = {}; + +export function getAddAssetsToGroupV1InstructionDataSerializer(): Serializer< + AddAssetsToGroupV1InstructionDataArgs, + AddAssetsToGroupV1InstructionData +> { + return mapSerializer< + AddAssetsToGroupV1InstructionDataArgs, + any, + AddAssetsToGroupV1InstructionData + >( + struct([['discriminator', u8()]], { + description: 'AddAssetsToGroupV1InstructionData', + }), + (value) => ({ ...value, discriminator: 35 }) + ) as Serializer< + AddAssetsToGroupV1InstructionDataArgs, + AddAssetsToGroupV1InstructionData + >; +} + +// Instruction. +export function addAssetsToGroupV1( + context: Pick, + input: AddAssetsToGroupV1InstructionAccounts +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + group: { + index: 0, + isWritable: true as boolean, + value: input.group ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + systemProgram: { + index: 3, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getAddAssetsToGroupV1InstructionDataSerializer().serialize({}); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/addCollectionsToGroupV1.ts b/clients/js/src/generated/instructions/addCollectionsToGroupV1.ts new file mode 100644 index 00000000..25245b55 --- /dev/null +++ b/clients/js/src/generated/instructions/addCollectionsToGroupV1.ts @@ -0,0 +1,135 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + mapSerializer, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type AddCollectionsToGroupV1InstructionAccounts = { + /** The address of the group to modify */ + group: PublicKey | Pda; + /** The account paying for storage fees */ + payer?: Signer; + /** The group update authority and collection update authority or delegate */ + authority?: Signer; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type AddCollectionsToGroupV1InstructionData = { discriminator: number }; + +export type AddCollectionsToGroupV1InstructionDataArgs = {}; + +export function getAddCollectionsToGroupV1InstructionDataSerializer(): Serializer< + AddCollectionsToGroupV1InstructionDataArgs, + AddCollectionsToGroupV1InstructionData +> { + return mapSerializer< + AddCollectionsToGroupV1InstructionDataArgs, + any, + AddCollectionsToGroupV1InstructionData + >( + struct([['discriminator', u8()]], { + description: 'AddCollectionsToGroupV1InstructionData', + }), + (value) => ({ ...value, discriminator: 33 }) + ) as Serializer< + AddCollectionsToGroupV1InstructionDataArgs, + AddCollectionsToGroupV1InstructionData + >; +} + +// Instruction. +export function addCollectionsToGroupV1( + context: Pick, + input: AddCollectionsToGroupV1InstructionAccounts +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + group: { + index: 0, + isWritable: true as boolean, + value: input.group ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + systemProgram: { + index: 3, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getAddCollectionsToGroupV1InstructionDataSerializer().serialize( + {} + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/addGroupsToGroupV1.ts b/clients/js/src/generated/instructions/addGroupsToGroupV1.ts new file mode 100644 index 00000000..52d7646b --- /dev/null +++ b/clients/js/src/generated/instructions/addGroupsToGroupV1.ts @@ -0,0 +1,154 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + array, + mapSerializer, + publicKey as publicKeySerializer, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type AddGroupsToGroupV1InstructionAccounts = { + /** The address of the parent group to modify */ + parentGroup: PublicKey | Pda; + /** The account paying for storage fees */ + payer?: Signer; + /** The update authority of the parent and child groups */ + authority?: Signer; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type AddGroupsToGroupV1InstructionData = { + discriminator: number; + groups: Array; +}; + +export type AddGroupsToGroupV1InstructionDataArgs = { + groups: Array; +}; + +export function getAddGroupsToGroupV1InstructionDataSerializer(): Serializer< + AddGroupsToGroupV1InstructionDataArgs, + AddGroupsToGroupV1InstructionData +> { + return mapSerializer< + AddGroupsToGroupV1InstructionDataArgs, + any, + AddGroupsToGroupV1InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['groups', array(publicKeySerializer())], + ], + { description: 'AddGroupsToGroupV1InstructionData' } + ), + (value) => ({ ...value, discriminator: 37 }) + ) as Serializer< + AddGroupsToGroupV1InstructionDataArgs, + AddGroupsToGroupV1InstructionData + >; +} + +// Args. +export type AddGroupsToGroupV1InstructionArgs = + AddGroupsToGroupV1InstructionDataArgs; + +// Instruction. +export function addGroupsToGroupV1( + context: Pick, + input: AddGroupsToGroupV1InstructionAccounts & + AddGroupsToGroupV1InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + parentGroup: { + index: 0, + isWritable: true as boolean, + value: input.parentGroup ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + systemProgram: { + index: 3, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: AddGroupsToGroupV1InstructionArgs = { ...input }; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getAddGroupsToGroupV1InstructionDataSerializer().serialize( + resolvedArgs as AddGroupsToGroupV1InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/closeGroupV1.ts b/clients/js/src/generated/instructions/closeGroupV1.ts new file mode 100644 index 00000000..4c31e24a --- /dev/null +++ b/clients/js/src/generated/instructions/closeGroupV1.ts @@ -0,0 +1,116 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + mapSerializer, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type CloseGroupV1InstructionAccounts = { + /** The address of the group to close */ + group: PublicKey | Pda; + /** The account receiving reclaimed lamports */ + payer?: Signer; + /** The update authority of the group */ + authority?: Signer; +}; + +// Data. +export type CloseGroupV1InstructionData = { discriminator: number }; + +export type CloseGroupV1InstructionDataArgs = {}; + +export function getCloseGroupV1InstructionDataSerializer(): Serializer< + CloseGroupV1InstructionDataArgs, + CloseGroupV1InstructionData +> { + return mapSerializer< + CloseGroupV1InstructionDataArgs, + any, + CloseGroupV1InstructionData + >( + struct([['discriminator', u8()]], { + description: 'CloseGroupV1InstructionData', + }), + (value) => ({ ...value, discriminator: 40 }) + ) as Serializer; +} + +// Instruction. +export function closeGroupV1( + context: Pick, + input: CloseGroupV1InstructionAccounts +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + group: { + index: 0, + isWritable: true as boolean, + value: input.group ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getCloseGroupV1InstructionDataSerializer().serialize({}); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/createGroupV1.ts b/clients/js/src/generated/instructions/createGroupV1.ts new file mode 100644 index 00000000..5de7c918 --- /dev/null +++ b/clients/js/src/generated/instructions/createGroupV1.ts @@ -0,0 +1,163 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + array, + mapSerializer, + string, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; +import { + RelationshipEntry, + RelationshipEntryArgs, + getRelationshipEntrySerializer, +} from '../types'; + +// Accounts. +export type CreateGroupV1InstructionAccounts = { + /** The address of the new group */ + group: Signer; + /** The authority of the new group */ + updateAuthority?: Signer; + /** The account paying for the storage fees */ + payer?: Signer; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type CreateGroupV1InstructionData = { + discriminator: number; + name: string; + uri: string; + relationships: Array; +}; + +export type CreateGroupV1InstructionDataArgs = { + name: string; + uri: string; + relationships: Array; +}; + +export function getCreateGroupV1InstructionDataSerializer(): Serializer< + CreateGroupV1InstructionDataArgs, + CreateGroupV1InstructionData +> { + return mapSerializer< + CreateGroupV1InstructionDataArgs, + any, + CreateGroupV1InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['name', string()], + ['uri', string()], + ['relationships', array(getRelationshipEntrySerializer())], + ], + { description: 'CreateGroupV1InstructionData' } + ), + (value) => ({ ...value, discriminator: 39 }) + ) as Serializer< + CreateGroupV1InstructionDataArgs, + CreateGroupV1InstructionData + >; +} + +// Args. +export type CreateGroupV1InstructionArgs = CreateGroupV1InstructionDataArgs; + +// Instruction. +export function createGroupV1( + context: Pick, + input: CreateGroupV1InstructionAccounts & CreateGroupV1InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + group: { + index: 0, + isWritable: true as boolean, + value: input.group ?? null, + }, + updateAuthority: { + index: 1, + isWritable: false as boolean, + value: input.updateAuthority ?? null, + }, + payer: { + index: 2, + isWritable: true as boolean, + value: input.payer ?? null, + }, + systemProgram: { + index: 3, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: CreateGroupV1InstructionArgs = { ...input }; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getCreateGroupV1InstructionDataSerializer().serialize( + resolvedArgs as CreateGroupV1InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/executeV1.ts b/clients/js/src/generated/instructions/executeV1.ts index 7340af6e..70fbacc9 100644 --- a/clients/js/src/generated/instructions/executeV1.ts +++ b/clients/js/src/generated/instructions/executeV1.ts @@ -39,7 +39,7 @@ export type ExecuteV1InstructionAccounts = { /** The signing PDA for the asset */ assetSigner?: PublicKey | Pda; /** The account paying for the storage fees */ - payer?: Signer; + payer?: PublicKey | Pda | Signer; /** The owner or delegate of the asset */ authority?: Signer; /** The system program */ diff --git a/clients/js/src/generated/instructions/index.ts b/clients/js/src/generated/instructions/index.ts index 858a827f..103c5574 100644 --- a/clients/js/src/generated/instructions/index.ts +++ b/clients/js/src/generated/instructions/index.ts @@ -6,33 +6,43 @@ * @see https://github.com/metaplex-foundation/kinobi */ +export * from './addAssetsToGroupV1'; export * from './addCollectionExternalPluginAdapterV1'; export * from './addCollectionPluginV1'; +export * from './addCollectionsToGroupV1'; export * from './addExternalPluginAdapterV1'; +export * from './addGroupsToGroupV1'; export * from './addPluginV1'; export * from './approveCollectionPluginAuthorityV1'; export * from './approvePluginAuthorityV1'; export * from './burnCollectionV1'; export * from './burnV1'; +export * from './closeGroupV1'; export * from './collect'; export * from './compressV1'; export * from './createCollectionV1'; export * from './createCollectionV2'; +export * from './createGroupV1'; export * from './createV1'; export * from './createV2'; export * from './decompressV1'; export * from './executeV1'; +export * from './removeAssetsFromGroupV1'; export * from './removeCollectionExternalPluginAdapterV1'; export * from './removeCollectionPluginV1'; +export * from './removeCollectionsFromGroupV1'; export * from './removeExternalPluginAdapterV1'; +export * from './removeGroupsFromGroupV1'; export * from './removePluginV1'; export * from './revokeCollectionPluginAuthorityV1'; export * from './revokePluginAuthorityV1'; export * from './transferV1'; export * from './updateCollectionExternalPluginAdapterV1'; +export * from './updateCollectionInfoV1'; export * from './updateCollectionPluginV1'; export * from './updateCollectionV1'; export * from './updateExternalPluginAdapterV1'; +export * from './updateGroupV1'; export * from './updatePluginV1'; export * from './updateV1'; export * from './updateV2'; diff --git a/clients/js/src/generated/instructions/removeAssetsFromGroupV1.ts b/clients/js/src/generated/instructions/removeAssetsFromGroupV1.ts new file mode 100644 index 00000000..e420c49b --- /dev/null +++ b/clients/js/src/generated/instructions/removeAssetsFromGroupV1.ts @@ -0,0 +1,154 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + array, + mapSerializer, + publicKey as publicKeySerializer, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type RemoveAssetsFromGroupV1InstructionAccounts = { + /** The address of the group to modify */ + group: PublicKey | Pda; + /** The account paying for storage fees */ + payer?: Signer; + /** The group update authority and asset update authority or delegate */ + authority?: Signer; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type RemoveAssetsFromGroupV1InstructionData = { + discriminator: number; + assets: Array; +}; + +export type RemoveAssetsFromGroupV1InstructionDataArgs = { + assets: Array; +}; + +export function getRemoveAssetsFromGroupV1InstructionDataSerializer(): Serializer< + RemoveAssetsFromGroupV1InstructionDataArgs, + RemoveAssetsFromGroupV1InstructionData +> { + return mapSerializer< + RemoveAssetsFromGroupV1InstructionDataArgs, + any, + RemoveAssetsFromGroupV1InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['assets', array(publicKeySerializer())], + ], + { description: 'RemoveAssetsFromGroupV1InstructionData' } + ), + (value) => ({ ...value, discriminator: 36 }) + ) as Serializer< + RemoveAssetsFromGroupV1InstructionDataArgs, + RemoveAssetsFromGroupV1InstructionData + >; +} + +// Args. +export type RemoveAssetsFromGroupV1InstructionArgs = + RemoveAssetsFromGroupV1InstructionDataArgs; + +// Instruction. +export function removeAssetsFromGroupV1( + context: Pick, + input: RemoveAssetsFromGroupV1InstructionAccounts & + RemoveAssetsFromGroupV1InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + group: { + index: 0, + isWritable: true as boolean, + value: input.group ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + systemProgram: { + index: 3, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: RemoveAssetsFromGroupV1InstructionArgs = { ...input }; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getRemoveAssetsFromGroupV1InstructionDataSerializer().serialize( + resolvedArgs as RemoveAssetsFromGroupV1InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/removeCollectionsFromGroupV1.ts b/clients/js/src/generated/instructions/removeCollectionsFromGroupV1.ts new file mode 100644 index 00000000..f57a2434 --- /dev/null +++ b/clients/js/src/generated/instructions/removeCollectionsFromGroupV1.ts @@ -0,0 +1,157 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + array, + mapSerializer, + publicKey as publicKeySerializer, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type RemoveCollectionsFromGroupV1InstructionAccounts = { + /** The address of the group to modify */ + group: PublicKey | Pda; + /** The account paying for storage fees */ + payer?: Signer; + /** The group update authority and collection update authority or delegate */ + authority?: Signer; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type RemoveCollectionsFromGroupV1InstructionData = { + discriminator: number; + collections: Array; +}; + +export type RemoveCollectionsFromGroupV1InstructionDataArgs = { + collections: Array; +}; + +export function getRemoveCollectionsFromGroupV1InstructionDataSerializer(): Serializer< + RemoveCollectionsFromGroupV1InstructionDataArgs, + RemoveCollectionsFromGroupV1InstructionData +> { + return mapSerializer< + RemoveCollectionsFromGroupV1InstructionDataArgs, + any, + RemoveCollectionsFromGroupV1InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['collections', array(publicKeySerializer())], + ], + { description: 'RemoveCollectionsFromGroupV1InstructionData' } + ), + (value) => ({ ...value, discriminator: 34 }) + ) as Serializer< + RemoveCollectionsFromGroupV1InstructionDataArgs, + RemoveCollectionsFromGroupV1InstructionData + >; +} + +// Args. +export type RemoveCollectionsFromGroupV1InstructionArgs = + RemoveCollectionsFromGroupV1InstructionDataArgs; + +// Instruction. +export function removeCollectionsFromGroupV1( + context: Pick, + input: RemoveCollectionsFromGroupV1InstructionAccounts & + RemoveCollectionsFromGroupV1InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + group: { + index: 0, + isWritable: true as boolean, + value: input.group ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + systemProgram: { + index: 3, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: RemoveCollectionsFromGroupV1InstructionArgs = { + ...input, + }; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = + getRemoveCollectionsFromGroupV1InstructionDataSerializer().serialize( + resolvedArgs as RemoveCollectionsFromGroupV1InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/removeGroupsFromGroupV1.ts b/clients/js/src/generated/instructions/removeGroupsFromGroupV1.ts new file mode 100644 index 00000000..21763da9 --- /dev/null +++ b/clients/js/src/generated/instructions/removeGroupsFromGroupV1.ts @@ -0,0 +1,154 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + array, + mapSerializer, + publicKey as publicKeySerializer, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type RemoveGroupsFromGroupV1InstructionAccounts = { + /** The address of the parent group to modify */ + parentGroup: PublicKey | Pda; + /** The account paying for storage fees */ + payer?: Signer; + /** The update authority of the parent and child groups */ + authority?: Signer; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type RemoveGroupsFromGroupV1InstructionData = { + discriminator: number; + groups: Array; +}; + +export type RemoveGroupsFromGroupV1InstructionDataArgs = { + groups: Array; +}; + +export function getRemoveGroupsFromGroupV1InstructionDataSerializer(): Serializer< + RemoveGroupsFromGroupV1InstructionDataArgs, + RemoveGroupsFromGroupV1InstructionData +> { + return mapSerializer< + RemoveGroupsFromGroupV1InstructionDataArgs, + any, + RemoveGroupsFromGroupV1InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['groups', array(publicKeySerializer())], + ], + { description: 'RemoveGroupsFromGroupV1InstructionData' } + ), + (value) => ({ ...value, discriminator: 38 }) + ) as Serializer< + RemoveGroupsFromGroupV1InstructionDataArgs, + RemoveGroupsFromGroupV1InstructionData + >; +} + +// Args. +export type RemoveGroupsFromGroupV1InstructionArgs = + RemoveGroupsFromGroupV1InstructionDataArgs; + +// Instruction. +export function removeGroupsFromGroupV1( + context: Pick, + input: RemoveGroupsFromGroupV1InstructionAccounts & + RemoveGroupsFromGroupV1InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + parentGroup: { + index: 0, + isWritable: true as boolean, + value: input.parentGroup ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + systemProgram: { + index: 3, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: RemoveGroupsFromGroupV1InstructionArgs = { ...input }; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getRemoveGroupsFromGroupV1InstructionDataSerializer().serialize( + resolvedArgs as RemoveGroupsFromGroupV1InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/updateCollectionInfoV1.ts b/clients/js/src/generated/instructions/updateCollectionInfoV1.ts new file mode 100644 index 00000000..515394a4 --- /dev/null +++ b/clients/js/src/generated/instructions/updateCollectionInfoV1.ts @@ -0,0 +1,131 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Pda, + PublicKey, + Signer, + TransactionBuilder, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + mapSerializer, + struct, + u32, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; +import { UpdateType, UpdateTypeArgs, getUpdateTypeSerializer } from '../types'; + +// Accounts. +export type UpdateCollectionInfoV1InstructionAccounts = { + /** The address of the asset */ + collection: PublicKey | Pda; + /** Bubblegum PDA signer */ + bubblegumSigner: Signer; +}; + +// Data. +export type UpdateCollectionInfoV1InstructionData = { + discriminator: number; + updateType: UpdateType; + amount: number; +}; + +export type UpdateCollectionInfoV1InstructionDataArgs = { + updateType: UpdateTypeArgs; + amount: number; +}; + +export function getUpdateCollectionInfoV1InstructionDataSerializer(): Serializer< + UpdateCollectionInfoV1InstructionDataArgs, + UpdateCollectionInfoV1InstructionData +> { + return mapSerializer< + UpdateCollectionInfoV1InstructionDataArgs, + any, + UpdateCollectionInfoV1InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['updateType', getUpdateTypeSerializer()], + ['amount', u32()], + ], + { description: 'UpdateCollectionInfoV1InstructionData' } + ), + (value) => ({ ...value, discriminator: 32 }) + ) as Serializer< + UpdateCollectionInfoV1InstructionDataArgs, + UpdateCollectionInfoV1InstructionData + >; +} + +// Args. +export type UpdateCollectionInfoV1InstructionArgs = + UpdateCollectionInfoV1InstructionDataArgs; + +// Instruction. +export function updateCollectionInfoV1( + context: Pick, + input: UpdateCollectionInfoV1InstructionAccounts & + UpdateCollectionInfoV1InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + collection: { + index: 0, + isWritable: true as boolean, + value: input.collection ?? null, + }, + bubblegumSigner: { + index: 1, + isWritable: false as boolean, + value: input.bubblegumSigner ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: UpdateCollectionInfoV1InstructionArgs = { ...input }; + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getUpdateCollectionInfoV1InstructionDataSerializer().serialize( + resolvedArgs as UpdateCollectionInfoV1InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/instructions/updateGroupV1.ts b/clients/js/src/generated/instructions/updateGroupV1.ts new file mode 100644 index 00000000..d7ba3273 --- /dev/null +++ b/clients/js/src/generated/instructions/updateGroupV1.ts @@ -0,0 +1,170 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Context, + Option, + OptionOrNullable, + Pda, + PublicKey, + Signer, + TransactionBuilder, + none, + transactionBuilder, +} from '@metaplex-foundation/umi'; +import { + Serializer, + mapSerializer, + option, + string, + struct, + u8, +} from '@metaplex-foundation/umi/serializers'; +import { + ResolvedAccount, + ResolvedAccountsWithIndices, + getAccountMetasAndSigners, +} from '../shared'; + +// Accounts. +export type UpdateGroupV1InstructionAccounts = { + /** The address of the group to update */ + group: PublicKey | Pda; + /** The account paying for the storage fees */ + payer?: Signer; + /** The update authority of the group */ + authority?: Signer; + /** The new update authority of the group */ + newUpdateAuthority?: PublicKey | Pda; + /** The system program */ + systemProgram?: PublicKey | Pda; +}; + +// Data. +export type UpdateGroupV1InstructionData = { + discriminator: number; + newName: Option; + newUri: Option; +}; + +export type UpdateGroupV1InstructionDataArgs = { + newName?: OptionOrNullable; + newUri?: OptionOrNullable; +}; + +export function getUpdateGroupV1InstructionDataSerializer(): Serializer< + UpdateGroupV1InstructionDataArgs, + UpdateGroupV1InstructionData +> { + return mapSerializer< + UpdateGroupV1InstructionDataArgs, + any, + UpdateGroupV1InstructionData + >( + struct( + [ + ['discriminator', u8()], + ['newName', option(string())], + ['newUri', option(string())], + ], + { description: 'UpdateGroupV1InstructionData' } + ), + (value) => ({ + ...value, + discriminator: 41, + newName: value.newName ?? none(), + newUri: value.newUri ?? none(), + }) + ) as Serializer< + UpdateGroupV1InstructionDataArgs, + UpdateGroupV1InstructionData + >; +} + +// Args. +export type UpdateGroupV1InstructionArgs = UpdateGroupV1InstructionDataArgs; + +// Instruction. +export function updateGroupV1( + context: Pick, + input: UpdateGroupV1InstructionAccounts & UpdateGroupV1InstructionArgs +): TransactionBuilder { + // Program ID. + const programId = context.programs.getPublicKey( + 'mplCore', + 'CoREENxT6tW1HoK8ypY1SxRMZTcVPm7R94rH4PZNhX7d' + ); + + // Accounts. + const resolvedAccounts = { + group: { + index: 0, + isWritable: true as boolean, + value: input.group ?? null, + }, + payer: { + index: 1, + isWritable: true as boolean, + value: input.payer ?? null, + }, + authority: { + index: 2, + isWritable: false as boolean, + value: input.authority ?? null, + }, + newUpdateAuthority: { + index: 3, + isWritable: false as boolean, + value: input.newUpdateAuthority ?? null, + }, + systemProgram: { + index: 4, + isWritable: false as boolean, + value: input.systemProgram ?? null, + }, + } satisfies ResolvedAccountsWithIndices; + + // Arguments. + const resolvedArgs: UpdateGroupV1InstructionArgs = { ...input }; + + // Default values. + if (!resolvedAccounts.payer.value) { + resolvedAccounts.payer.value = context.payer; + } + if (!resolvedAccounts.systemProgram.value) { + resolvedAccounts.systemProgram.value = context.programs.getPublicKey( + 'splSystem', + '11111111111111111111111111111111' + ); + resolvedAccounts.systemProgram.isWritable = false; + } + + // Accounts in order. + const orderedAccounts: ResolvedAccount[] = Object.values( + resolvedAccounts + ).sort((a, b) => a.index - b.index); + + // Keys and Signers. + const [keys, signers] = getAccountMetasAndSigners( + orderedAccounts, + 'programId', + programId + ); + + // Data. + const data = getUpdateGroupV1InstructionDataSerializer().serialize( + resolvedArgs as UpdateGroupV1InstructionDataArgs + ); + + // Bytes Created On Chain. + const bytesCreatedOnChain = 0; + + return transactionBuilder([ + { instruction: { keys, programId, data }, signers, bytesCreatedOnChain }, + ]); +} diff --git a/clients/js/src/generated/types/baseAgentIdentity.ts b/clients/js/src/generated/types/baseAgentIdentity.ts new file mode 100644 index 00000000..3e82b3fb --- /dev/null +++ b/clients/js/src/generated/types/baseAgentIdentity.ts @@ -0,0 +1,26 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { + Serializer, + string, + struct, +} from '@metaplex-foundation/umi/serializers'; + +export type BaseAgentIdentity = { uri: string }; + +export type BaseAgentIdentityArgs = BaseAgentIdentity; + +export function getBaseAgentIdentitySerializer(): Serializer< + BaseAgentIdentityArgs, + BaseAgentIdentity +> { + return struct([['uri', string()]], { + description: 'BaseAgentIdentity', + }) as Serializer; +} diff --git a/clients/js/src/generated/types/baseAgentIdentityInitInfo.ts b/clients/js/src/generated/types/baseAgentIdentityInitInfo.ts new file mode 100644 index 00000000..768a2f82 --- /dev/null +++ b/clients/js/src/generated/types/baseAgentIdentityInitInfo.ts @@ -0,0 +1,62 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Option, OptionOrNullable } from '@metaplex-foundation/umi'; +import { + Serializer, + array, + option, + string, + struct, + tuple, +} from '@metaplex-foundation/umi/serializers'; +import { + BasePluginAuthority, + BasePluginAuthorityArgs, + ExternalCheckResult, + ExternalCheckResultArgs, + HookableLifecycleEvent, + HookableLifecycleEventArgs, + getBasePluginAuthoritySerializer, + getExternalCheckResultSerializer, + getHookableLifecycleEventSerializer, +} from '.'; + +export type BaseAgentIdentityInitInfo = { + uri: string; + initPluginAuthority: Option; + lifecycleChecks: Array<[HookableLifecycleEvent, ExternalCheckResult]>; +}; + +export type BaseAgentIdentityInitInfoArgs = { + uri: string; + initPluginAuthority: OptionOrNullable; + lifecycleChecks: Array<[HookableLifecycleEventArgs, ExternalCheckResultArgs]>; +}; + +export function getBaseAgentIdentityInitInfoSerializer(): Serializer< + BaseAgentIdentityInitInfoArgs, + BaseAgentIdentityInitInfo +> { + return struct( + [ + ['uri', string()], + ['initPluginAuthority', option(getBasePluginAuthoritySerializer())], + [ + 'lifecycleChecks', + array( + tuple([ + getHookableLifecycleEventSerializer(), + getExternalCheckResultSerializer(), + ]) + ), + ], + ], + { description: 'BaseAgentIdentityInitInfo' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseAgentIdentityUpdateInfo.ts b/clients/js/src/generated/types/baseAgentIdentityUpdateInfo.ts new file mode 100644 index 00000000..e0e6a40c --- /dev/null +++ b/clients/js/src/generated/types/baseAgentIdentityUpdateInfo.ts @@ -0,0 +1,60 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Option, OptionOrNullable } from '@metaplex-foundation/umi'; +import { + Serializer, + array, + option, + string, + struct, + tuple, +} from '@metaplex-foundation/umi/serializers'; +import { + ExternalCheckResult, + ExternalCheckResultArgs, + HookableLifecycleEvent, + HookableLifecycleEventArgs, + getExternalCheckResultSerializer, + getHookableLifecycleEventSerializer, +} from '.'; + +export type BaseAgentIdentityUpdateInfo = { + uri: Option; + lifecycleChecks: Option>; +}; + +export type BaseAgentIdentityUpdateInfoArgs = { + uri: OptionOrNullable; + lifecycleChecks: OptionOrNullable< + Array<[HookableLifecycleEventArgs, ExternalCheckResultArgs]> + >; +}; + +export function getBaseAgentIdentityUpdateInfoSerializer(): Serializer< + BaseAgentIdentityUpdateInfoArgs, + BaseAgentIdentityUpdateInfo +> { + return struct( + [ + ['uri', option(string())], + [ + 'lifecycleChecks', + option( + array( + tuple([ + getHookableLifecycleEventSerializer(), + getExternalCheckResultSerializer(), + ]) + ) + ), + ], + ], + { description: 'BaseAgentIdentityUpdateInfo' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts b/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts index c65b82af..45b96162 100644 --- a/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts +++ b/clients/js/src/generated/types/baseExternalPluginAdapterInitInfo.ts @@ -15,6 +15,8 @@ import { tuple, } from '@metaplex-foundation/umi/serializers'; import { + BaseAgentIdentityInitInfo, + BaseAgentIdentityInitInfoArgs, BaseAppDataInitInfo, BaseAppDataInitInfoArgs, BaseDataSectionInitInfo, @@ -27,6 +29,7 @@ import { BaseLinkedLifecycleHookInitInfoArgs, BaseOracleInitInfo, BaseOracleInitInfoArgs, + getBaseAgentIdentityInitInfoSerializer, getBaseAppDataInitInfoSerializer, getBaseDataSectionInitInfoSerializer, getBaseLifecycleHookInitInfoSerializer, @@ -41,7 +44,8 @@ export type BaseExternalPluginAdapterInitInfo = | { __kind: 'AppData'; fields: [BaseAppDataInitInfo] } | { __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHookInitInfo] } | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataInitInfo] } - | { __kind: 'DataSection'; fields: [BaseDataSectionInitInfo] }; + | { __kind: 'DataSection'; fields: [BaseDataSectionInitInfo] } + | { __kind: 'AgentIdentity'; fields: [BaseAgentIdentityInitInfo] }; export type BaseExternalPluginAdapterInitInfoArgs = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookInitInfoArgs] } @@ -52,7 +56,8 @@ export type BaseExternalPluginAdapterInitInfoArgs = fields: [BaseLinkedLifecycleHookInitInfoArgs]; } | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataInitInfoArgs] } - | { __kind: 'DataSection'; fields: [BaseDataSectionInitInfoArgs] }; + | { __kind: 'DataSection'; fields: [BaseDataSectionInitInfoArgs] } + | { __kind: 'AgentIdentity'; fields: [BaseAgentIdentityInitInfoArgs] }; export function getBaseExternalPluginAdapterInitInfoSerializer(): Serializer< BaseExternalPluginAdapterInitInfoArgs, @@ -110,6 +115,15 @@ export function getBaseExternalPluginAdapterInitInfoSerializer(): Serializer< > >([['fields', tuple([getBaseDataSectionInitInfoSerializer()])]]), ], + [ + 'AgentIdentity', + struct< + GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfo, + 'AgentIdentity' + > + >([['fields', tuple([getBaseAgentIdentityInitInfoSerializer()])]]), + ], ], { description: 'BaseExternalPluginAdapterInitInfo' } ) as Serializer< @@ -164,6 +178,13 @@ export function baseExternalPluginAdapterInitInfo( 'DataSection' >['fields'] ): GetDataEnumKind; +export function baseExternalPluginAdapterInitInfo( + kind: 'AgentIdentity', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterInitInfoArgs, + 'AgentIdentity' + >['fields'] +): GetDataEnumKind; export function baseExternalPluginAdapterInitInfo< K extends BaseExternalPluginAdapterInitInfoArgs['__kind'], >( diff --git a/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts b/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts index 9aedf063..dd68b584 100644 --- a/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts +++ b/clients/js/src/generated/types/baseExternalPluginAdapterKey.ts @@ -15,6 +15,7 @@ import { publicKey as publicKeySerializer, struct, tuple, + unit, } from '@metaplex-foundation/umi/serializers'; import { BaseLinkedDataKey, @@ -31,7 +32,8 @@ export type BaseExternalPluginAdapterKey = | { __kind: 'AppData'; fields: [BasePluginAuthority] } | { __kind: 'LinkedLifecycleHook'; fields: [PublicKey] } | { __kind: 'LinkedAppData'; fields: [BasePluginAuthority] } - | { __kind: 'DataSection'; fields: [BaseLinkedDataKey] }; + | { __kind: 'DataSection'; fields: [BaseLinkedDataKey] } + | { __kind: 'AgentIdentity' }; export type BaseExternalPluginAdapterKeyArgs = | { __kind: 'LifecycleHook'; fields: [PublicKey] } @@ -39,7 +41,8 @@ export type BaseExternalPluginAdapterKeyArgs = | { __kind: 'AppData'; fields: [BasePluginAuthorityArgs] } | { __kind: 'LinkedLifecycleHook'; fields: [PublicKey] } | { __kind: 'LinkedAppData'; fields: [BasePluginAuthorityArgs] } - | { __kind: 'DataSection'; fields: [BaseLinkedDataKeyArgs] }; + | { __kind: 'DataSection'; fields: [BaseLinkedDataKeyArgs] } + | { __kind: 'AgentIdentity' }; export function getBaseExternalPluginAdapterKeySerializer(): Serializer< BaseExternalPluginAdapterKeyArgs, @@ -86,6 +89,7 @@ export function getBaseExternalPluginAdapterKeySerializer(): Serializer< GetDataEnumKindContent >([['fields', tuple([getBaseLinkedDataKeySerializer()])]]), ], + ['AgentIdentity', unit()], ], { description: 'BaseExternalPluginAdapterKey' } ) as Serializer< @@ -137,6 +141,9 @@ export function baseExternalPluginAdapterKey( 'DataSection' >['fields'] ): GetDataEnumKind; +export function baseExternalPluginAdapterKey( + kind: 'AgentIdentity' +): GetDataEnumKind; export function baseExternalPluginAdapterKey< K extends BaseExternalPluginAdapterKeyArgs['__kind'], >( diff --git a/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts b/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts index 99ee7553..92a07c0e 100644 --- a/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts +++ b/clients/js/src/generated/types/baseExternalPluginAdapterUpdateInfo.ts @@ -15,6 +15,8 @@ import { tuple, } from '@metaplex-foundation/umi/serializers'; import { + BaseAgentIdentityUpdateInfo, + BaseAgentIdentityUpdateInfoArgs, BaseAppDataUpdateInfo, BaseAppDataUpdateInfoArgs, BaseLifecycleHookUpdateInfo, @@ -25,6 +27,7 @@ import { BaseLinkedLifecycleHookUpdateInfoArgs, BaseOracleUpdateInfo, BaseOracleUpdateInfoArgs, + getBaseAgentIdentityUpdateInfoSerializer, getBaseAppDataUpdateInfoSerializer, getBaseLifecycleHookUpdateInfoSerializer, getBaseLinkedAppDataUpdateInfoSerializer, @@ -40,7 +43,8 @@ export type BaseExternalPluginAdapterUpdateInfo = __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHookUpdateInfo]; } - | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataUpdateInfo] }; + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataUpdateInfo] } + | { __kind: 'AgentIdentity'; fields: [BaseAgentIdentityUpdateInfo] }; export type BaseExternalPluginAdapterUpdateInfoArgs = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookUpdateInfoArgs] } @@ -50,7 +54,8 @@ export type BaseExternalPluginAdapterUpdateInfoArgs = __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHookUpdateInfoArgs]; } - | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataUpdateInfoArgs] }; + | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataUpdateInfoArgs] } + | { __kind: 'AgentIdentity'; fields: [BaseAgentIdentityUpdateInfoArgs] }; export function getBaseExternalPluginAdapterUpdateInfoSerializer(): Serializer< BaseExternalPluginAdapterUpdateInfoArgs, @@ -99,6 +104,15 @@ export function getBaseExternalPluginAdapterUpdateInfoSerializer(): Serializer< > >([['fields', tuple([getBaseLinkedAppDataUpdateInfoSerializer()])]]), ], + [ + 'AgentIdentity', + struct< + GetDataEnumKindContent< + BaseExternalPluginAdapterUpdateInfo, + 'AgentIdentity' + > + >([['fields', tuple([getBaseAgentIdentityUpdateInfoSerializer()])]]), + ], ], { description: 'BaseExternalPluginAdapterUpdateInfo' } ) as Serializer< @@ -146,6 +160,13 @@ export function baseExternalPluginAdapterUpdateInfo( 'LinkedAppData' >['fields'] ): GetDataEnumKind; +export function baseExternalPluginAdapterUpdateInfo( + kind: 'AgentIdentity', + data: GetDataEnumKindContent< + BaseExternalPluginAdapterUpdateInfoArgs, + 'AgentIdentity' + >['fields'] +): GetDataEnumKind; export function baseExternalPluginAdapterUpdateInfo< K extends BaseExternalPluginAdapterUpdateInfoArgs['__kind'], >( diff --git a/clients/js/src/generated/types/bubblegumV2.ts b/clients/js/src/generated/types/bubblegumV2.ts new file mode 100644 index 00000000..e6d9a5b7 --- /dev/null +++ b/clients/js/src/generated/types/bubblegumV2.ts @@ -0,0 +1,23 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, struct } from '@metaplex-foundation/umi/serializers'; + +export type BubblegumV2 = {}; + +export type BubblegumV2Args = BubblegumV2; + +export function getBubblegumV2Serializer(): Serializer< + BubblegumV2Args, + BubblegumV2 +> { + return struct([], { description: 'BubblegumV2' }) as Serializer< + BubblegumV2Args, + BubblegumV2 + >; +} diff --git a/clients/js/src/generated/types/externalPluginAdapter.ts b/clients/js/src/generated/types/externalPluginAdapter.ts index 260f2e09..b2a4c276 100644 --- a/clients/js/src/generated/types/externalPluginAdapter.ts +++ b/clients/js/src/generated/types/externalPluginAdapter.ts @@ -15,6 +15,8 @@ import { tuple, } from '@metaplex-foundation/umi/serializers'; import { + BaseAgentIdentity, + BaseAgentIdentityArgs, BaseAppData, BaseAppDataArgs, BaseDataSection, @@ -27,6 +29,7 @@ import { BaseLinkedLifecycleHookArgs, BaseOracle, BaseOracleArgs, + getBaseAgentIdentitySerializer, getBaseAppDataSerializer, getBaseDataSectionSerializer, getBaseLifecycleHookSerializer, @@ -41,7 +44,8 @@ export type ExternalPluginAdapter = | { __kind: 'AppData'; fields: [BaseAppData] } | { __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHook] } | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppData] } - | { __kind: 'DataSection'; fields: [BaseDataSection] }; + | { __kind: 'DataSection'; fields: [BaseDataSection] } + | { __kind: 'AgentIdentity'; fields: [BaseAgentIdentity] }; export type ExternalPluginAdapterArgs = | { __kind: 'LifecycleHook'; fields: [BaseLifecycleHookArgs] } @@ -49,7 +53,8 @@ export type ExternalPluginAdapterArgs = | { __kind: 'AppData'; fields: [BaseAppDataArgs] } | { __kind: 'LinkedLifecycleHook'; fields: [BaseLinkedLifecycleHookArgs] } | { __kind: 'LinkedAppData'; fields: [BaseLinkedAppDataArgs] } - | { __kind: 'DataSection'; fields: [BaseDataSectionArgs] }; + | { __kind: 'DataSection'; fields: [BaseDataSectionArgs] } + | { __kind: 'AgentIdentity'; fields: [BaseAgentIdentityArgs] }; export function getExternalPluginAdapterSerializer(): Serializer< ExternalPluginAdapterArgs, @@ -93,6 +98,12 @@ export function getExternalPluginAdapterSerializer(): Serializer< ['fields', tuple([getBaseDataSectionSerializer()])], ]), ], + [ + 'AgentIdentity', + struct>([ + ['fields', tuple([getBaseAgentIdentitySerializer()])], + ]), + ], ], { description: 'ExternalPluginAdapter' } ) as Serializer; @@ -135,6 +146,13 @@ export function externalPluginAdapter( 'DataSection' >['fields'] ): GetDataEnumKind; +export function externalPluginAdapter( + kind: 'AgentIdentity', + data: GetDataEnumKindContent< + ExternalPluginAdapterArgs, + 'AgentIdentity' + >['fields'] +): GetDataEnumKind; export function externalPluginAdapter< K extends ExternalPluginAdapterArgs['__kind'], >(kind: K, data?: any): Extract { diff --git a/clients/js/src/generated/types/externalPluginAdapterType.ts b/clients/js/src/generated/types/externalPluginAdapterType.ts index dd992d55..07787656 100644 --- a/clients/js/src/generated/types/externalPluginAdapterType.ts +++ b/clients/js/src/generated/types/externalPluginAdapterType.ts @@ -15,6 +15,7 @@ export enum ExternalPluginAdapterType { LinkedLifecycleHook, LinkedAppData, DataSection, + AgentIdentity, } export type ExternalPluginAdapterTypeArgs = ExternalPluginAdapterType; diff --git a/clients/js/src/generated/types/freezeExecute.ts b/clients/js/src/generated/types/freezeExecute.ts new file mode 100644 index 00000000..64941806 --- /dev/null +++ b/clients/js/src/generated/types/freezeExecute.ts @@ -0,0 +1,22 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, bool, struct } from '@metaplex-foundation/umi/serializers'; + +export type FreezeExecute = { frozen: boolean }; + +export type FreezeExecuteArgs = FreezeExecute; + +export function getFreezeExecuteSerializer(): Serializer< + FreezeExecuteArgs, + FreezeExecute +> { + return struct([['frozen', bool()]], { + description: 'FreezeExecute', + }) as Serializer; +} diff --git a/clients/js/src/generated/types/groupV1AccountData.ts b/clients/js/src/generated/types/groupV1AccountData.ts new file mode 100644 index 00000000..075e7ece --- /dev/null +++ b/clients/js/src/generated/types/groupV1AccountData.ts @@ -0,0 +1,61 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { PublicKey } from '@metaplex-foundation/umi'; +import { + Serializer, + array, + mapSerializer, + publicKey as publicKeySerializer, + string, + struct, +} from '@metaplex-foundation/umi/serializers'; +import { Key, getKeySerializer } from '.'; + +export type GroupV1AccountData = { + key: Key; + updateAuthority: PublicKey; + name: string; + uri: string; + collections: Array; + groups: Array; + parentGroups: Array; + assets: Array; +}; + +export type GroupV1AccountDataArgs = { + updateAuthority: PublicKey; + name: string; + uri: string; + collections: Array; + groups: Array; + parentGroups: Array; + assets: Array; +}; + +export function getGroupV1AccountDataSerializer(): Serializer< + GroupV1AccountDataArgs, + GroupV1AccountData +> { + return mapSerializer( + struct( + [ + ['key', getKeySerializer()], + ['updateAuthority', publicKeySerializer()], + ['name', string()], + ['uri', string()], + ['collections', array(publicKeySerializer())], + ['groups', array(publicKeySerializer())], + ['parentGroups', array(publicKeySerializer())], + ['assets', array(publicKeySerializer())], + ], + { description: 'GroupV1AccountData' } + ), + (value) => ({ ...value, key: Key.GroupV1 }) + ) as Serializer; +} diff --git a/clients/js/src/generated/types/groups.ts b/clients/js/src/generated/types/groups.ts new file mode 100644 index 00000000..ccd4ad06 --- /dev/null +++ b/clients/js/src/generated/types/groups.ts @@ -0,0 +1,25 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { PublicKey } from '@metaplex-foundation/umi'; +import { + Serializer, + array, + publicKey as publicKeySerializer, + struct, +} from '@metaplex-foundation/umi/serializers'; + +export type Groups = { groups: Array }; + +export type GroupsArgs = Groups; + +export function getGroupsSerializer(): Serializer { + return struct([['groups', array(publicKeySerializer())]], { + description: 'Groups', + }) as Serializer; +} diff --git a/clients/js/src/generated/types/hookableLifecycleEvent.ts b/clients/js/src/generated/types/hookableLifecycleEvent.ts index fcf73d79..f89ddee3 100644 --- a/clients/js/src/generated/types/hookableLifecycleEvent.ts +++ b/clients/js/src/generated/types/hookableLifecycleEvent.ts @@ -13,6 +13,7 @@ export enum HookableLifecycleEvent { Transfer, Burn, Update, + Execute, } export type HookableLifecycleEventArgs = HookableLifecycleEvent; diff --git a/clients/js/src/generated/types/index.ts b/clients/js/src/generated/types/index.ts index 86c9b374..aaa2fb65 100644 --- a/clients/js/src/generated/types/index.ts +++ b/clients/js/src/generated/types/index.ts @@ -11,6 +11,9 @@ export * from './attribute'; export * from './attributes'; export * from './autograph'; export * from './autographSignature'; +export * from './baseAgentIdentity'; +export * from './baseAgentIdentityInitInfo'; +export * from './baseAgentIdentityUpdateInfo'; export * from './baseAppData'; export * from './baseAppDataInitInfo'; export * from './baseAppDataUpdateInfo'; @@ -41,6 +44,7 @@ export * from './baseRuleSet'; export * from './baseSeed'; export * from './baseUpdateAuthority'; export * from './baseValidationResultsOffset'; +export * from './bubblegumV2'; export * from './burnDelegate'; export * from './compressionProof'; export * from './creator'; @@ -53,6 +57,8 @@ export * from './externalPluginAdapterType'; export * from './externalRegistryRecord'; export * from './externalValidationResult'; export * from './freezeDelegate'; +export * from './freezeExecute'; +export * from './groups'; export * from './hashablePluginSchema'; export * from './hashedAssetSchema'; export * from './hookableLifecycleEvent'; @@ -61,13 +67,17 @@ export * from './key'; export * from './oracleValidation'; export * from './permanentBurnDelegate'; export * from './permanentFreezeDelegate'; +export * from './permanentFreezeExecute'; export * from './permanentTransferDelegate'; export * from './plugin'; export * from './pluginAuthorityPair'; export * from './pluginType'; export * from './registryRecord'; +export * from './relationshipEntry'; +export * from './relationshipKind'; export * from './transferDelegate'; export * from './updateDelegate'; +export * from './updateType'; export * from './validationResult'; export * from './verifiedCreators'; export * from './verifiedCreatorsSignature'; diff --git a/clients/js/src/generated/types/key.ts b/clients/js/src/generated/types/key.ts index 8bebbc41..85098f9c 100644 --- a/clients/js/src/generated/types/key.ts +++ b/clients/js/src/generated/types/key.ts @@ -15,6 +15,7 @@ export enum Key { PluginHeaderV1, PluginRegistryV1, CollectionV1, + GroupV1, } export type KeyArgs = Key; diff --git a/clients/js/src/generated/types/permanentFreezeExecute.ts b/clients/js/src/generated/types/permanentFreezeExecute.ts new file mode 100644 index 00000000..fd46a615 --- /dev/null +++ b/clients/js/src/generated/types/permanentFreezeExecute.ts @@ -0,0 +1,22 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, bool, struct } from '@metaplex-foundation/umi/serializers'; + +export type PermanentFreezeExecute = { frozen: boolean }; + +export type PermanentFreezeExecuteArgs = PermanentFreezeExecute; + +export function getPermanentFreezeExecuteSerializer(): Serializer< + PermanentFreezeExecuteArgs, + PermanentFreezeExecute +> { + return struct([['frozen', bool()]], { + description: 'PermanentFreezeExecute', + }) as Serializer; +} diff --git a/clients/js/src/generated/types/plugin.ts b/clients/js/src/generated/types/plugin.ts index b5e2a9bb..e6bed57e 100644 --- a/clients/js/src/generated/types/plugin.ts +++ b/clients/js/src/generated/types/plugin.ts @@ -25,18 +25,26 @@ import { BaseMasterEditionArgs, BaseRoyalties, BaseRoyaltiesArgs, + BubblegumV2, + BubblegumV2Args, BurnDelegate, BurnDelegateArgs, Edition, EditionArgs, FreezeDelegate, FreezeDelegateArgs, + FreezeExecute, + FreezeExecuteArgs, + Groups, + GroupsArgs, ImmutableMetadata, ImmutableMetadataArgs, PermanentBurnDelegate, PermanentBurnDelegateArgs, PermanentFreezeDelegate, PermanentFreezeDelegateArgs, + PermanentFreezeExecute, + PermanentFreezeExecuteArgs, PermanentTransferDelegate, PermanentTransferDelegateArgs, TransferDelegate, @@ -50,12 +58,16 @@ import { getAutographSerializer, getBaseMasterEditionSerializer, getBaseRoyaltiesSerializer, + getBubblegumV2Serializer, getBurnDelegateSerializer, getEditionSerializer, getFreezeDelegateSerializer, + getFreezeExecuteSerializer, + getGroupsSerializer, getImmutableMetadataSerializer, getPermanentBurnDelegateSerializer, getPermanentFreezeDelegateSerializer, + getPermanentFreezeExecuteSerializer, getPermanentTransferDelegateSerializer, getTransferDelegateSerializer, getUpdateDelegateSerializer, @@ -77,7 +89,11 @@ export type Plugin = | { __kind: 'AddBlocker'; fields: [AddBlocker] } | { __kind: 'ImmutableMetadata'; fields: [ImmutableMetadata] } | { __kind: 'VerifiedCreators'; fields: [VerifiedCreators] } - | { __kind: 'Autograph'; fields: [Autograph] }; + | { __kind: 'Autograph'; fields: [Autograph] } + | { __kind: 'BubblegumV2'; fields: [BubblegumV2] } + | { __kind: 'FreezeExecute'; fields: [FreezeExecute] } + | { __kind: 'PermanentFreezeExecute'; fields: [PermanentFreezeExecute] } + | { __kind: 'Groups'; fields: [Groups] }; export type PluginArgs = | { __kind: 'Royalties'; fields: [BaseRoyaltiesArgs] } @@ -97,7 +113,11 @@ export type PluginArgs = | { __kind: 'AddBlocker'; fields: [AddBlockerArgs] } | { __kind: 'ImmutableMetadata'; fields: [ImmutableMetadataArgs] } | { __kind: 'VerifiedCreators'; fields: [VerifiedCreatorsArgs] } - | { __kind: 'Autograph'; fields: [AutographArgs] }; + | { __kind: 'Autograph'; fields: [AutographArgs] } + | { __kind: 'BubblegumV2'; fields: [BubblegumV2Args] } + | { __kind: 'FreezeExecute'; fields: [FreezeExecuteArgs] } + | { __kind: 'PermanentFreezeExecute'; fields: [PermanentFreezeExecuteArgs] } + | { __kind: 'Groups'; fields: [GroupsArgs] }; export function getPluginSerializer(): Serializer { return dataEnum( @@ -192,6 +212,30 @@ export function getPluginSerializer(): Serializer { ['fields', tuple([getAutographSerializer()])], ]), ], + [ + 'BubblegumV2', + struct>([ + ['fields', tuple([getBubblegumV2Serializer()])], + ]), + ], + [ + 'FreezeExecute', + struct>([ + ['fields', tuple([getFreezeExecuteSerializer()])], + ]), + ], + [ + 'PermanentFreezeExecute', + struct>([ + ['fields', tuple([getPermanentFreezeExecuteSerializer()])], + ]), + ], + [ + 'Groups', + struct>([ + ['fields', tuple([getGroupsSerializer()])], + ]), + ], ], { description: 'Plugin' } ) as Serializer; @@ -261,6 +305,22 @@ export function plugin( kind: 'Autograph', data: GetDataEnumKindContent['fields'] ): GetDataEnumKind; +export function plugin( + kind: 'BubblegumV2', + data: GetDataEnumKindContent['fields'] +): GetDataEnumKind; +export function plugin( + kind: 'FreezeExecute', + data: GetDataEnumKindContent['fields'] +): GetDataEnumKind; +export function plugin( + kind: 'PermanentFreezeExecute', + data: GetDataEnumKindContent['fields'] +): GetDataEnumKind; +export function plugin( + kind: 'Groups', + data: GetDataEnumKindContent['fields'] +): GetDataEnumKind; export function plugin( kind: K, data?: any diff --git a/clients/js/src/generated/types/pluginType.ts b/clients/js/src/generated/types/pluginType.ts index a001175d..448157eb 100644 --- a/clients/js/src/generated/types/pluginType.ts +++ b/clients/js/src/generated/types/pluginType.ts @@ -24,6 +24,10 @@ export enum PluginType { ImmutableMetadata, VerifiedCreators, Autograph, + BubblegumV2, + FreezeExecute, + PermanentFreezeExecute, + Groups, } export type PluginTypeArgs = PluginType; diff --git a/clients/js/src/generated/types/relationshipEntry.ts b/clients/js/src/generated/types/relationshipEntry.ts new file mode 100644 index 00000000..5dac465e --- /dev/null +++ b/clients/js/src/generated/types/relationshipEntry.ts @@ -0,0 +1,39 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { PublicKey } from '@metaplex-foundation/umi'; +import { + Serializer, + publicKey as publicKeySerializer, + struct, +} from '@metaplex-foundation/umi/serializers'; +import { + RelationshipKind, + RelationshipKindArgs, + getRelationshipKindSerializer, +} from '.'; + +export type RelationshipEntry = { kind: RelationshipKind; key: PublicKey }; + +export type RelationshipEntryArgs = { + kind: RelationshipKindArgs; + key: PublicKey; +}; + +export function getRelationshipEntrySerializer(): Serializer< + RelationshipEntryArgs, + RelationshipEntry +> { + return struct( + [ + ['kind', getRelationshipKindSerializer()], + ['key', publicKeySerializer()], + ], + { description: 'RelationshipEntry' } + ) as Serializer; +} diff --git a/clients/js/src/generated/types/relationshipKind.ts b/clients/js/src/generated/types/relationshipKind.ts new file mode 100644 index 00000000..1795b2a9 --- /dev/null +++ b/clients/js/src/generated/types/relationshipKind.ts @@ -0,0 +1,27 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, scalarEnum } from '@metaplex-foundation/umi/serializers'; + +export enum RelationshipKind { + Collection, + ChildGroup, + ParentGroup, + Asset, +} + +export type RelationshipKindArgs = RelationshipKind; + +export function getRelationshipKindSerializer(): Serializer< + RelationshipKindArgs, + RelationshipKind +> { + return scalarEnum(RelationshipKind, { + description: 'RelationshipKind', + }) as Serializer; +} diff --git a/clients/js/src/generated/types/updateType.ts b/clients/js/src/generated/types/updateType.ts new file mode 100644 index 00000000..daa50d1f --- /dev/null +++ b/clients/js/src/generated/types/updateType.ts @@ -0,0 +1,26 @@ +/** + * This code was AUTOGENERATED using the kinobi library. + * Please DO NOT EDIT THIS FILE, instead use visitors + * to add features, then rerun kinobi to update it. + * + * @see https://github.com/metaplex-foundation/kinobi + */ + +import { Serializer, scalarEnum } from '@metaplex-foundation/umi/serializers'; + +export enum UpdateType { + Mint, + Add, + Remove, +} + +export type UpdateTypeArgs = UpdateType; + +export function getUpdateTypeSerializer(): Serializer< + UpdateTypeArgs, + UpdateType +> { + return scalarEnum(UpdateType, { + description: 'UpdateType', + }) as Serializer; +} diff --git a/clients/js/src/helpers/state.ts b/clients/js/src/helpers/state.ts index fce68fe5..33f6c6bf 100644 --- a/clients/js/src/helpers/state.ts +++ b/clients/js/src/helpers/state.ts @@ -12,6 +12,7 @@ import { AppDataPlugin } from '../plugins/appData'; import { LifecycleHookPlugin } from '../plugins/lifecycleHook'; import { DataSectionPlugin } from '../plugins/dataSection'; import { LinkedAppDataPlugin } from '../plugins/linkedAppData'; +import { AgentIdentityPlugin } from '../plugins/agentIdentity'; /** * Find the collection address for the given asset if it is part of a collection. @@ -32,6 +33,7 @@ const externalPluginAdapterKeys: (keyof ExternalPluginAdaptersList)[] = [ 'lifecycleHooks', 'dataSections', 'linkedAppDatas', + 'agentIdentities', ]; export const getExternalPluginAdapterKeyAsString = ( plugin: @@ -41,6 +43,7 @@ export const getExternalPluginAdapterKeyAsString = ( | Pick | Pick | Pick + | Pick ): string => { switch (plugin.type) { case 'Oracle': @@ -57,6 +60,8 @@ export const getExternalPluginAdapterKeyAsString = ( }`; case 'DataSection': return `${plugin.type}-${getExternalPluginAdapterKeyAsString(plugin.parentKey)}`; + case 'AgentIdentity': + return plugin.type; default: throw new Error('Unknown ExternalPluginAdapter type'); } diff --git a/clients/js/src/hooked/groupAccountData.ts b/clients/js/src/hooked/groupAccountData.ts new file mode 100644 index 00000000..73775cdf --- /dev/null +++ b/clients/js/src/hooked/groupAccountData.ts @@ -0,0 +1,123 @@ +import { Serializer } from '@metaplex-foundation/umi/serializers'; + +import { + Key, + PluginHeaderV1, + PluginHeaderV1AccountData, + getPluginHeaderV1AccountDataSerializer, +} from '../generated'; + +import { + GroupV1AccountData as GenGroupV1AccountData, + GroupV1AccountDataArgs as GenGroupV1AccountDataArgs, + getGroupV1AccountDataSerializer as genGetGroupV1AccountDataSerializer, +} from '../generated/types/groupV1AccountData'; + +import { + ExternalPluginAdaptersList, + GroupPluginsList, + registryRecordsToPluginsList, +} from '../plugins'; +import { externalRegistryRecordsToExternalPluginAdapterList } from '../plugins/externalPluginAdapters'; +import { + PluginRegistryV1AccountData, + getPluginRegistryV1AccountDataSerializer, +} from './pluginRegistryV1Data'; + +export type GroupV1AccountData = GenGroupV1AccountData & + GroupPluginsList & + ExternalPluginAdaptersList & { + pluginHeader?: Omit; + }; + +export type GroupV1AccountDataArgs = GenGroupV1AccountDataArgs & { + pluginHeader?: Omit; +}; + +export const getGroupV1AccountDataSerializer = (): Serializer< + GroupV1AccountDataArgs, + GroupV1AccountData +> => ({ + description: 'GroupAccountData', + fixedSize: null, + maxSize: null, + serialize: () => { + throw new Error('Operation not supported.'); + }, + deserialize: ( + buffer: Uint8Array, + offset = 0 + ): [GroupV1AccountData, number] => { + const pluginHeaderSerializer = getPluginHeaderV1AccountDataSerializer(); + const pluginHeaderSize = pluginHeaderSerializer.fixedSize; + if (pluginHeaderSize === null) { + throw new Error('Invalid plugin header serializer configuration.'); + } + + // Deserialize base group data + const [group, groupOffset] = + genGetGroupV1AccountDataSerializer().deserialize(buffer, offset); + + if (group.key !== Key.GroupV1) { + throw new Error(`Expected a Group account, got key: ${group.key}`); + } + + let pluginHeader: PluginHeaderV1AccountData | undefined; + let pluginRegistry: PluginRegistryV1AccountData | undefined; + let pluginsList: GroupPluginsList | undefined; + let externalPluginAdaptersList: ExternalPluginAdaptersList | undefined; + let finalOffset = groupOffset; + + const hasTrailingData = buffer.length > groupOffset; + if (hasTrailingData && buffer.length < groupOffset + pluginHeaderSize) { + throw new Error('Invalid Group account data: truncated plugin header.'); + } + + if (buffer.length >= groupOffset + pluginHeaderSize) { + [pluginHeader] = pluginHeaderSerializer.deserialize(buffer, groupOffset); + + const pluginRegistryOffset = Number(pluginHeader.pluginRegistryOffset); + if ( + !Number.isSafeInteger(pluginRegistryOffset) || + pluginRegistryOffset < groupOffset + pluginHeaderSize || + pluginRegistryOffset >= buffer.length + ) { + throw new Error( + 'Invalid Group account data: plugin registry offset is out of bounds.' + ); + } + + [pluginRegistry, finalOffset] = + getPluginRegistryV1AccountDataSerializer().deserialize( + buffer, + pluginRegistryOffset + ); + if (finalOffset > buffer.length) { + throw new Error( + 'Invalid Group account data: plugin registry exceeds buffer length.' + ); + } + + pluginsList = registryRecordsToPluginsList( + pluginRegistry.registry, + buffer + ); + + externalPluginAdaptersList = + externalRegistryRecordsToExternalPluginAdapterList( + pluginRegistry.externalRegistry, + buffer + ); + } + + return [ + { + pluginHeader, + ...group, + ...pluginsList, + ...externalPluginAdaptersList, + }, + finalOffset, + ]; + }, +}); diff --git a/clients/js/src/hooked/index.ts b/clients/js/src/hooked/index.ts index cb0aeb61..af77509d 100644 --- a/clients/js/src/hooked/index.ts +++ b/clients/js/src/hooked/index.ts @@ -1,3 +1,4 @@ export * from './assetAccountData'; export * from './collectionAccountData'; +export * from './groupAccountData'; export * from './pluginRegistryV1Data'; diff --git a/clients/js/src/instructions/approvePluginAuthority.ts b/clients/js/src/instructions/approvePluginAuthority.ts index 51d1e35c..ba8396e5 100644 --- a/clients/js/src/instructions/approvePluginAuthority.ts +++ b/clients/js/src/instructions/approvePluginAuthority.ts @@ -3,7 +3,7 @@ import { approvePluginAuthorityV1, PluginType } from '../generated'; import { PluginAuthority, pluginAuthorityToBase } from '../plugins'; export type ApprovePluginAuthorityArgsPlugin = { - type: keyof typeof PluginType; + type: Exclude; }; export type ApprovePluginAuthorityArgs = Omit< @@ -17,9 +17,17 @@ export type ApprovePluginAuthorityArgs = Omit< export const approvePluginAuthority = ( context: Pick, { plugin, newAuthority, ...args }: ApprovePluginAuthorityArgs -) => - approvePluginAuthorityV1(context, { +) => { + const pluginType = plugin.type as keyof typeof PluginType; + if (pluginType === 'Groups') { + throw new Error( + 'PluginType.Groups must be managed via group-specific instructions.' + ); + } + + return approvePluginAuthorityV1(context, { ...args, - pluginType: PluginType[plugin.type as keyof typeof PluginType], + pluginType: PluginType[pluginType], newAuthority: pluginAuthorityToBase(newAuthority), }); +}; diff --git a/clients/js/src/instructions/collection/approveCollectionPluginAuthority.ts b/clients/js/src/instructions/collection/approveCollectionPluginAuthority.ts index 0786773d..0c2ce743 100644 --- a/clients/js/src/instructions/collection/approveCollectionPluginAuthority.ts +++ b/clients/js/src/instructions/collection/approveCollectionPluginAuthority.ts @@ -10,7 +10,7 @@ export type ApproveCollectionPluginAuthorityArgs = Omit< 'pluginType' | 'newAuthority' > & { plugin: { - type: keyof typeof PluginType; + type: Exclude; }; newAuthority: PluginAuthority; }; @@ -18,9 +18,17 @@ export type ApproveCollectionPluginAuthorityArgs = Omit< export const approveCollectionPluginAuthority = ( context: Pick, { plugin, newAuthority, ...args }: ApproveCollectionPluginAuthorityArgs -) => - approveCollectionPluginAuthorityV1(context, { +) => { + const pluginType = plugin.type as keyof typeof PluginType; + if (pluginType === 'Groups') { + throw new Error( + 'PluginType.Groups must be managed via group-specific instructions.' + ); + } + + return approveCollectionPluginAuthorityV1(context, { ...args, - pluginType: PluginType[plugin.type as keyof typeof PluginType], + pluginType: PluginType[pluginType], newAuthority: pluginAuthorityToBase(newAuthority), }); +}; diff --git a/clients/js/src/instructions/collection/index.ts b/clients/js/src/instructions/collection/index.ts index fbca7eba..608b9d8a 100644 --- a/clients/js/src/instructions/collection/index.ts +++ b/clients/js/src/instructions/collection/index.ts @@ -6,3 +6,4 @@ export * from './removeCollectionPlugin'; export * from './revokeCollectionPluginAuthority'; export * from './updateCollection'; export * from './updateCollectionPlugin'; +export * from './writeCollectionData'; diff --git a/clients/js/src/instructions/collection/removeCollectionPlugin.ts b/clients/js/src/instructions/collection/removeCollectionPlugin.ts index 11a07561..d907b739 100644 --- a/clients/js/src/instructions/collection/removeCollectionPlugin.ts +++ b/clients/js/src/instructions/collection/removeCollectionPlugin.ts @@ -13,7 +13,7 @@ import { isExternalPluginAdapterType } from '../../plugins/externalPluginAdapter export type RemoveCollectionPluginArgsPlugin = | { - type: Exclude; + type: Exclude; } | ExternalPluginAdapterKey; @@ -35,8 +35,15 @@ export const removeCollectionPlugin = ( }); } + const pluginType = plugin.type as keyof typeof PluginType; + if (pluginType === 'Groups') { + throw new Error( + 'PluginType.Groups must be managed via group-specific instructions.' + ); + } + return removeCollectionPluginV1(context, { ...args, - pluginType: PluginType[plugin.type as keyof typeof PluginType], + pluginType: PluginType[pluginType], }); }; diff --git a/clients/js/src/instructions/collection/revokeCollectionPluginAuthority.ts b/clients/js/src/instructions/collection/revokeCollectionPluginAuthority.ts index d4da63aa..2c88921d 100644 --- a/clients/js/src/instructions/collection/revokeCollectionPluginAuthority.ts +++ b/clients/js/src/instructions/collection/revokeCollectionPluginAuthority.ts @@ -6,15 +6,23 @@ export type RevokeCollectionPluginAuthorityArgs = Omit< 'pluginType' > & { plugin: { - type: keyof typeof PluginType; + type: Exclude; }; }; export const revokeCollectionPluginAuthority = ( context: Pick, { plugin, ...args }: RevokeCollectionPluginAuthorityArgs -) => - revokeCollectionPluginAuthorityV1(context, { +) => { + const pluginType = plugin.type as keyof typeof PluginType; + if (pluginType === 'Groups') { + throw new Error( + 'PluginType.Groups must be managed via group-specific instructions.' + ); + } + + return revokeCollectionPluginAuthorityV1(context, { ...args, - pluginType: PluginType[plugin.type as keyof typeof PluginType], + pluginType: PluginType[pluginType], }); +}; diff --git a/clients/js/src/instructions/collection/writeCollectionData.ts b/clients/js/src/instructions/collection/writeCollectionData.ts new file mode 100644 index 00000000..2a5a1184 --- /dev/null +++ b/clients/js/src/instructions/collection/writeCollectionData.ts @@ -0,0 +1,29 @@ +import { Context } from '@metaplex-foundation/umi'; +import { + writeCollectionExternalPluginAdapterDataV1, + WriteCollectionExternalPluginAdapterDataV1InstructionAccounts, + WriteCollectionExternalPluginAdapterDataV1InstructionArgs, +} from '../../generated'; +import { + ExternalPluginAdapterKey, + externalPluginAdapterKeyToBase, +} from '../../plugins'; + +export type WriteCollectionDataArgs = Omit< + WriteCollectionExternalPluginAdapterDataV1InstructionArgs, + 'key' +> & { + key: ExternalPluginAdapterKey; +}; + +export const writeCollectionData = ( + context: Pick, + args: WriteCollectionDataArgs & + WriteCollectionExternalPluginAdapterDataV1InstructionAccounts +) => { + const { key, ...rest } = args; + return writeCollectionExternalPluginAdapterDataV1(context, { + ...rest, + key: externalPluginAdapterKeyToBase(key), + }); +}; diff --git a/clients/js/src/instructions/execute.ts b/clients/js/src/instructions/execute.ts index da104b26..ca96d769 100644 --- a/clients/js/src/instructions/execute.ts +++ b/clients/js/src/instructions/execute.ts @@ -1,6 +1,9 @@ import { Context, Instruction, + Pda, + publicKey, + PublicKey, Signer, TransactionBuilder, } from '@metaplex-foundation/umi'; @@ -22,6 +25,8 @@ export type ExecuteArgs = Omit< collection?: Pick; instructions: ExecuteInput; signers?: Signer[]; + /** Optional execution delegate record account to pass as the first remaining account. */ + executionDelegateRecord?: PublicKey | Pda; }; export const execute = ( @@ -35,23 +40,27 @@ const executeCommon = ( ) => { // Create a new builder to store the translated Execute instructions. let executeBuilder = new TransactionBuilder(); - // We want to track the signers from the original IXes so they can be added to the Execute instructions. - const signers: Signer[] = []; + // Caller-level signers provided via args.signers (used for Instruction[] path). + const callerSigners: Signer[] = [...(args.signers || [])]; let builder: TransactionBuilder = new TransactionBuilder(); - if (args.instructions instanceof TransactionBuilder) { + // Duck-type check instead of instanceof to avoid cross-realm/bundler breakage + // when multiple copies of the umi package are resolved. + if ('getInstructions' in args.instructions) { builder = args.instructions; - } else if (args.instructions) { - args.instructions.forEach((instruction) => { + } else if (Array.isArray(args.instructions)) { + args.instructions.forEach((instruction: Instruction) => { const ixSigners: Signer[] = []; - instruction.keys.forEach((key) => { - const signer = signers.find( - (signerKey) => signerKey.publicKey === key.pubkey - ); - if (signer) { - ixSigners.push(signer); - } - }); + instruction.keys + .filter((key) => key.isSigner) + .forEach((key) => { + const signer = callerSigners.find( + (signerKey) => signerKey.publicKey === key.pubkey + ); + if (signer) { + ixSigners.push(signer); + } + }); builder = builder.add({ instruction, signers: ixSigners, @@ -67,7 +76,7 @@ const executeCommon = ( const [assetSigner] = findAssetSignerPda(context, { asset: args.asset.publicKey, }); - const baseBuilder = executeV1(context, { + let baseBuilder = executeV1(context, { ...args, asset: args.asset.publicKey, collection: args.collection?.publicKey, @@ -78,6 +87,18 @@ const executeCommon = ( instructionData: ix.instruction.data, }); + // If an executionDelegateRecord is provided, prepend it as the first + // remaining account so the on-chain program can read it during validation. + if (args.executionDelegateRecord) { + baseBuilder = baseBuilder.addRemainingAccounts([ + { + pubkey: publicKey(args.executionDelegateRecord), + isSigner: false, + isWritable: false, + }, + ]); + } + executeBuilder = executeBuilder.add( baseBuilder // Add the instruction keys as remaining accounts. @@ -99,10 +120,12 @@ const executeCommon = ( // Capture the builder items so they can be modified. const executeBuilderItems = executeBuilder.items; - // Add the signers to the Execute instruction. - executeBuilderItems[0].signers.push( - // Add the signers to the Execute instruction, filtering out the asset signer. - ...signers.filter((signer) => signer.publicKey !== assetSigner) + // Merge caller-level signers with this item's signers, filtering out the asset signer. + const itemSigners = [...callerSigners, ...ix.signers].filter( + (signer) => signer.publicKey !== assetSigner + ); + executeBuilderItems[executeBuilderItems.length - 1].signers.push( + ...itemSigners ); // Set the modified builder items. executeBuilder = executeBuilder.setItems(executeBuilderItems); diff --git a/clients/js/src/instructions/group/addAssetsToGroup.ts b/clients/js/src/instructions/group/addAssetsToGroup.ts new file mode 100644 index 00000000..6c65c426 --- /dev/null +++ b/clients/js/src/instructions/group/addAssetsToGroup.ts @@ -0,0 +1,9 @@ +import { Context } from '@metaplex-foundation/umi'; +import { addAssetsToGroupV1 } from '../../generated'; + +export type AddAssetsToGroupArgs = Parameters[1]; + +export const addAssetsToGroup = ( + context: Pick, + args: AddAssetsToGroupArgs +) => addAssetsToGroupV1(context, args); diff --git a/clients/js/src/instructions/group/addCollectionsToGroup.ts b/clients/js/src/instructions/group/addCollectionsToGroup.ts new file mode 100644 index 00000000..d7b7d639 --- /dev/null +++ b/clients/js/src/instructions/group/addCollectionsToGroup.ts @@ -0,0 +1,11 @@ +import { Context } from '@metaplex-foundation/umi'; +import { addCollectionsToGroupV1 } from '../../generated'; + +export type AddCollectionsToGroupArgs = Parameters< + typeof addCollectionsToGroupV1 +>[1]; + +export const addCollectionsToGroup = ( + context: Pick, + args: AddCollectionsToGroupArgs +) => addCollectionsToGroupV1(context, args); diff --git a/clients/js/src/instructions/group/addGroupsToGroup.ts b/clients/js/src/instructions/group/addGroupsToGroup.ts new file mode 100644 index 00000000..5952dccc --- /dev/null +++ b/clients/js/src/instructions/group/addGroupsToGroup.ts @@ -0,0 +1,9 @@ +import { Context } from '@metaplex-foundation/umi'; +import { addGroupsToGroupV1 } from '../../generated'; + +export type AddGroupsToGroupArgs = Parameters[1]; + +export const addGroupsToGroup = ( + context: Pick, + args: AddGroupsToGroupArgs +) => addGroupsToGroupV1(context, args); diff --git a/clients/js/src/instructions/group/closeGroup.ts b/clients/js/src/instructions/group/closeGroup.ts new file mode 100644 index 00000000..8b226234 --- /dev/null +++ b/clients/js/src/instructions/group/closeGroup.ts @@ -0,0 +1,9 @@ +import { Context } from '@metaplex-foundation/umi'; +import { closeGroupV1 } from '../../generated'; + +export type CloseGroupArgs = Parameters[1]; + +export const closeGroup = ( + context: Pick, + args: CloseGroupArgs +) => closeGroupV1(context, args); diff --git a/clients/js/src/instructions/group/createGroup.ts b/clients/js/src/instructions/group/createGroup.ts new file mode 100644 index 00000000..2202d188 --- /dev/null +++ b/clients/js/src/instructions/group/createGroup.ts @@ -0,0 +1,9 @@ +import { Context } from '@metaplex-foundation/umi'; +import { createGroupV1 } from '../../generated'; + +export type CreateGroupArgs = Parameters[1]; + +export const createGroup = ( + context: Pick, + args: CreateGroupArgs +) => createGroupV1(context, args); diff --git a/clients/js/src/instructions/group/index.ts b/clients/js/src/instructions/group/index.ts new file mode 100644 index 00000000..6837312c --- /dev/null +++ b/clients/js/src/instructions/group/index.ts @@ -0,0 +1,9 @@ +export * from './addAssetsToGroup'; +export * from './addCollectionsToGroup'; +export * from './addGroupsToGroup'; +export * from './closeGroup'; +export * from './createGroup'; +export * from './removeAssetsFromGroup'; +export * from './removeCollectionsFromGroup'; +export * from './removeGroupsFromGroup'; +export * from './updateGroup'; diff --git a/clients/js/src/instructions/group/removeAssetsFromGroup.ts b/clients/js/src/instructions/group/removeAssetsFromGroup.ts new file mode 100644 index 00000000..6a88efdc --- /dev/null +++ b/clients/js/src/instructions/group/removeAssetsFromGroup.ts @@ -0,0 +1,11 @@ +import { Context } from '@metaplex-foundation/umi'; +import { removeAssetsFromGroupV1 } from '../../generated'; + +export type RemoveAssetsFromGroupArgs = Parameters< + typeof removeAssetsFromGroupV1 +>[1]; + +export const removeAssetsFromGroup = ( + context: Pick, + args: RemoveAssetsFromGroupArgs +) => removeAssetsFromGroupV1(context, args); diff --git a/clients/js/src/instructions/group/removeCollectionsFromGroup.ts b/clients/js/src/instructions/group/removeCollectionsFromGroup.ts new file mode 100644 index 00000000..26d9c5b4 --- /dev/null +++ b/clients/js/src/instructions/group/removeCollectionsFromGroup.ts @@ -0,0 +1,11 @@ +import { Context } from '@metaplex-foundation/umi'; +import { removeCollectionsFromGroupV1 } from '../../generated'; + +export type RemoveCollectionsFromGroupArgs = Parameters< + typeof removeCollectionsFromGroupV1 +>[1]; + +export const removeCollectionsFromGroup = ( + context: Pick, + args: RemoveCollectionsFromGroupArgs +) => removeCollectionsFromGroupV1(context, args); diff --git a/clients/js/src/instructions/group/removeGroupsFromGroup.ts b/clients/js/src/instructions/group/removeGroupsFromGroup.ts new file mode 100644 index 00000000..a0362131 --- /dev/null +++ b/clients/js/src/instructions/group/removeGroupsFromGroup.ts @@ -0,0 +1,11 @@ +import { Context } from '@metaplex-foundation/umi'; +import { removeGroupsFromGroupV1 } from '../../generated'; + +export type RemoveGroupsFromGroupArgs = Parameters< + typeof removeGroupsFromGroupV1 +>[1]; + +export const removeGroupsFromGroup = ( + context: Pick, + args: RemoveGroupsFromGroupArgs +) => removeGroupsFromGroupV1(context, args); diff --git a/clients/js/src/instructions/group/updateGroup.ts b/clients/js/src/instructions/group/updateGroup.ts new file mode 100644 index 00000000..aac7b635 --- /dev/null +++ b/clients/js/src/instructions/group/updateGroup.ts @@ -0,0 +1,9 @@ +import { Context } from '@metaplex-foundation/umi'; +import { updateGroupV1 } from '../../generated'; + +export type UpdateGroupArgs = Parameters[1]; + +export const updateGroup = ( + context: Pick, + args: UpdateGroupArgs +) => updateGroupV1(context, args); diff --git a/clients/js/src/instructions/index.ts b/clients/js/src/instructions/index.ts index 51c2e928..9d7a5896 100644 --- a/clients/js/src/instructions/index.ts +++ b/clients/js/src/instructions/index.ts @@ -1,15 +1,16 @@ +export * from './addPlugin'; +export * from './approvePluginAuthority'; +export * from './burn'; +export * from './collection'; +export * from './create'; +export * from './execute'; +export * from './freeze'; +export * from './group'; export * from './legacyDelegate'; export * from './legacyRevoke'; -export * from './freeze'; -export * from './create'; -export * from './update'; -export * from './transfer'; -export * from './burn'; -export * from './addPlugin'; export * from './removePlugin'; -export * from './updatePlugin'; -export * from './approvePluginAuthority'; export * from './revokePluginAuthority'; -export * from './collection'; +export * from './transfer'; +export * from './update'; +export * from './updatePlugin'; export * from './writeData'; -export * from './execute'; diff --git a/clients/js/src/instructions/legacyDelegate.ts b/clients/js/src/instructions/legacyDelegate.ts index c64b83c3..5500b8bf 100644 --- a/clients/js/src/instructions/legacyDelegate.ts +++ b/clients/js/src/instructions/legacyDelegate.ts @@ -5,11 +5,7 @@ import { } from '@metaplex-foundation/umi'; import { ERR_CANNOT_DELEGATE } from './errors'; import { addPluginV1, AssetV1 } from '../generated'; -import { - AssetPluginsList, - createPlugin, - pluginKeyToPluginType, -} from '../plugins'; +import { createPlugin } from '../plugins'; import { addressPluginAuthority } from '../authority'; import { approvePluginAuthority } from './approvePluginAuthority'; @@ -47,10 +43,15 @@ export function legacyDelegate( let txBuilder = transactionBuilder(); const definedPluginsKeys = Object.keys(definedPlugins); + const pluginTypeByKey = { + freezeDelegate: 'FreezeDelegate', + transferDelegate: 'TransferDelegate', + burnDelegate: 'BurnDelegate', + } as const; // Change the plugin authority of the defined plugins. definedPluginsKeys.forEach((pluginKey) => { - const plugType = pluginKeyToPluginType(pluginKey as keyof AssetPluginsList); + const plugType = pluginTypeByKey[pluginKey as keyof typeof pluginTypeByKey]; txBuilder = txBuilder.add( approvePluginAuthority(context, { diff --git a/clients/js/src/instructions/removePlugin.ts b/clients/js/src/instructions/removePlugin.ts index 8b29e4f9..ac2f3162 100644 --- a/clients/js/src/instructions/removePlugin.ts +++ b/clients/js/src/instructions/removePlugin.ts @@ -12,7 +12,7 @@ import { export type RemovePluginArgsPlugin = | { - type: Exclude; + type: Exclude; } | ExternalPluginAdapterKey; @@ -34,8 +34,15 @@ export const removePlugin = ( }); } + const pluginType = plugin.type as keyof typeof PluginType; + if (pluginType === 'Groups') { + throw new Error( + 'PluginType.Groups must be managed via group-specific instructions.' + ); + } + return removePluginV1(context, { ...args, - pluginType: PluginType[plugin.type as keyof typeof PluginType], + pluginType: PluginType[pluginType], }); }; diff --git a/clients/js/src/instructions/revokePluginAuthority.ts b/clients/js/src/instructions/revokePluginAuthority.ts index e83e29e8..18fed594 100644 --- a/clients/js/src/instructions/revokePluginAuthority.ts +++ b/clients/js/src/instructions/revokePluginAuthority.ts @@ -2,7 +2,7 @@ import { Context } from '@metaplex-foundation/umi'; import { revokePluginAuthorityV1, PluginType } from '../generated'; export type RevokePluginAuthorityArgsPlugin = { - type: keyof typeof PluginType; + type: Exclude; }; export type RevokePluginAuthorityArgs = Omit< @@ -15,8 +15,16 @@ export type RevokePluginAuthorityArgs = Omit< export const revokePluginAuthority = ( context: Pick, { plugin, ...args }: RevokePluginAuthorityArgs -) => - revokePluginAuthorityV1(context, { +) => { + const pluginType = plugin.type as keyof typeof PluginType; + if (pluginType === 'Groups') { + throw new Error( + 'PluginType.Groups must be managed via group-specific instructions.' + ); + } + + return revokePluginAuthorityV1(context, { ...args, - pluginType: PluginType[plugin.type as keyof typeof PluginType], + pluginType: PluginType[pluginType], }); +}; diff --git a/clients/js/src/plugins/agentIdentity.ts b/clients/js/src/plugins/agentIdentity.ts new file mode 100644 index 00000000..5d7b0427 --- /dev/null +++ b/clients/js/src/plugins/agentIdentity.ts @@ -0,0 +1,83 @@ +import { + BaseAgentIdentity, + BaseAgentIdentityInitInfoArgs, + BaseAgentIdentityUpdateInfoArgs, + ExternalRegistryRecord, +} from '../generated'; +import { LifecycleChecks, lifecycleChecksToBase } from './lifecycleChecks'; +import { PluginAuthority, pluginAuthorityToBase } from './pluginAuthority'; +import { ExternalPluginAdapterManifest } from './externalPluginAdapterManifest'; +import { BaseExternalPluginAdapter } from './externalPluginAdapters'; +import { ExternalPluginAdapterKey } from './externalPluginAdapterKey'; + +export type AgentIdentity = BaseAgentIdentity; + +export type AgentIdentityPlugin = BaseExternalPluginAdapter & + BaseAgentIdentity & { + type: 'AgentIdentity'; + }; + +export type AgentIdentityInitInfoArgs = Omit< + BaseAgentIdentityInitInfoArgs, + 'initPluginAuthority' | 'lifecycleChecks' +> & { + type: 'AgentIdentity'; + initPluginAuthority?: PluginAuthority; + lifecycleChecks: LifecycleChecks; +}; + +export type AgentIdentityUpdateInfoArgs = Omit< + BaseAgentIdentityUpdateInfoArgs, + 'uri' | 'lifecycleChecks' +> & { + key: ExternalPluginAdapterKey; + uri?: string; + lifecycleChecks?: LifecycleChecks; +}; + +export function agentIdentityInitInfoArgsToBase( + a: AgentIdentityInitInfoArgs +): BaseAgentIdentityInitInfoArgs { + return { + uri: a.uri, + lifecycleChecks: lifecycleChecksToBase(a.lifecycleChecks), + initPluginAuthority: a.initPluginAuthority + ? pluginAuthorityToBase(a.initPluginAuthority) + : null, + }; +} + +export function agentIdentityUpdateInfoArgsToBase( + a: AgentIdentityUpdateInfoArgs +): BaseAgentIdentityUpdateInfoArgs { + return { + uri: a.uri ?? null, + lifecycleChecks: a.lifecycleChecks + ? lifecycleChecksToBase(a.lifecycleChecks) + : null, + }; +} + +export function agentIdentityFromBase( + s: BaseAgentIdentity, + r: ExternalRegistryRecord, + account: Uint8Array +): AgentIdentity { + return { + ...s, + }; +} + +export const agentIdentityManifest: ExternalPluginAdapterManifest< + AgentIdentity, + BaseAgentIdentity, + AgentIdentityInitInfoArgs, + BaseAgentIdentityInitInfoArgs, + AgentIdentityUpdateInfoArgs, + BaseAgentIdentityUpdateInfoArgs +> = { + type: 'AgentIdentity', + fromBase: agentIdentityFromBase, + initToBase: agentIdentityInitInfoArgsToBase, + updateToBase: agentIdentityUpdateInfoArgsToBase, +}; diff --git a/clients/js/src/plugins/externalPluginAdapterKey.ts b/clients/js/src/plugins/externalPluginAdapterKey.ts index 8b89113b..fac380f8 100644 --- a/clients/js/src/plugins/externalPluginAdapterKey.ts +++ b/clients/js/src/plugins/externalPluginAdapterKey.ts @@ -24,7 +24,8 @@ export type ExternalPluginAdapterKey = type: 'LinkedAppData'; dataAuthority: PluginAuthority; } - | { type: 'DataSection'; parentKey: LinkedDataKey }; + | { type: 'DataSection'; parentKey: LinkedDataKey } + | { type: 'AgentIdentity' }; export function externalPluginAdapterKeyToBase( e: ExternalPluginAdapterKey @@ -51,6 +52,10 @@ export function externalPluginAdapterKeyToBase( __kind: e.type, fields: [linkedDataKeyToBase(e.parentKey)], }; + case 'AgentIdentity': + return { + __kind: e.type, + }; default: throw new Error('Unknown ExternalPluginAdapterKey type'); } diff --git a/clients/js/src/plugins/externalPluginAdapters.ts b/clients/js/src/plugins/externalPluginAdapters.ts index 11d957b0..743b641d 100644 --- a/clients/js/src/plugins/externalPluginAdapters.ts +++ b/clients/js/src/plugins/externalPluginAdapters.ts @@ -60,6 +60,13 @@ import { linkedLifecycleHookFromBase, linkedLifecycleHookManifest, } from './linkedLifecycleHook'; +import { + AgentIdentityInitInfoArgs, + AgentIdentityPlugin, + AgentIdentityUpdateInfoArgs, + agentIdentityFromBase, + agentIdentityManifest, +} from './agentIdentity'; export type ExternalPluginAdapterTypeString = BaseExternalPluginAdapterKey['__kind']; @@ -74,7 +81,8 @@ export type ExternalPluginAdapters = | AppDataPlugin | LinkedLifecycleHookPlugin | LinkedAppDataPlugin - | DataSectionPlugin; + | DataSectionPlugin + | AgentIdentityPlugin; export type ExternalPluginAdaptersList = { lifecycleHooks?: LifecycleHookPlugin[]; @@ -83,6 +91,7 @@ export type ExternalPluginAdaptersList = { linkedLifecycleHooks?: LinkedLifecycleHookPlugin[]; linkedAppDatas?: LinkedAppDataPlugin[]; dataSections?: DataSectionPlugin[]; + agentIdentities?: AgentIdentityPlugin[]; }; export type ExternalPluginAdapterInitInfoArgs = @@ -103,7 +112,10 @@ export type ExternalPluginAdapterInitInfoArgs = } & LinkedAppDataInitInfoArgs) | ({ type: 'DataSection'; - } & AppDataInitInfoArgs); + } & AppDataInitInfoArgs) + | ({ + type: 'AgentIdentity'; + } & AgentIdentityInitInfoArgs); export type ExternalPluginAdapterUpdateInfoArgs = | ({ @@ -120,7 +132,10 @@ export type ExternalPluginAdapterUpdateInfoArgs = } & LinkedLifecycleHookUpdateInfoArgs) | ({ type: 'LinkedAppData'; - } & LinkedAppDataUpdateInfoArgs); + } & LinkedAppDataUpdateInfoArgs) + | ({ + type: 'AgentIdentity'; + } & AgentIdentityUpdateInfoArgs); export const externalPluginAdapterManifests = { LifecycleHook: lifecycleHookManifest, @@ -129,6 +144,7 @@ export const externalPluginAdapterManifests = { LinkedLifecycleHook: linkedLifecycleHookManifest, LinkedAppData: linkedAppDataManifest, DataSection: dataSectionManifest, + AgentIdentity: agentIdentityManifest, }; export type ExternalPluginAdapterData = { @@ -240,6 +256,19 @@ export function externalRegistryRecordsToExternalPluginAdapterList( accountData ), }); + } else if (deserializedPlugin.__kind === 'AgentIdentity') { + if (!result.agentIdentities) { + result.agentIdentities = []; + } + result.agentIdentities.push({ + type: 'AgentIdentity', + ...mappedPlugin, + ...agentIdentityFromBase( + deserializedPlugin.fields[0], + record, + accountData + ), + }); } }); @@ -253,7 +282,8 @@ export const isExternalPluginAdapterType = (plugin: { type: string }) => { plugin.type === 'AppData' || plugin.type === 'LinkedLifecycleHook' || plugin.type === 'DataSection' || - plugin.type === 'LinkedAppData' + plugin.type === 'LinkedAppData' || + plugin.type === 'AgentIdentity' ) { return true; } diff --git a/clients/js/src/plugins/index.ts b/clients/js/src/plugins/index.ts index 29777a81..dcdd2c4d 100644 --- a/clients/js/src/plugins/index.ts +++ b/clients/js/src/plugins/index.ts @@ -18,3 +18,4 @@ export * from './linkedAppData'; export * from './dataSection'; export * from './linkedDataKey'; export * from './masterEdition'; +export * from './agentIdentity'; diff --git a/clients/js/src/plugins/lib.ts b/clients/js/src/plugins/lib.ts index b91e9541..a10102af 100644 --- a/clients/js/src/plugins/lib.ts +++ b/clients/js/src/plugins/lib.ts @@ -2,31 +2,31 @@ import { isSome, none, Option, some } from '@metaplex-foundation/umi'; import { decode } from '@msgpack/msgpack'; import { - Key, - PluginHeaderV1, Plugin as BasePlugin, + ExternalPluginAdapterSchema, getPluginSerializer, - RegistryRecord, + Key, PluginAuthorityPair, + PluginHeaderV1, PluginType, - ExternalPluginAdapterSchema, + RegistryRecord, } from '../generated'; import { toWords } from '../utils'; -import { - CreatePluginArgs, - AssetAllPluginArgsV2, - PluginAuthorityPairHelperArgs, - AssetPluginAuthorityPairArgsV2, - PluginsList, -} from './types'; +import { masterEditionFromBase, masterEditionToBase } from './masterEdition'; import { PluginAuthority, pluginAuthorityFromBase, pluginAuthorityToBase, } from './pluginAuthority'; import { royaltiesFromBase, royaltiesToBase } from './royalties'; -import { masterEditionFromBase, masterEditionToBase } from './masterEdition'; +import { + AssetAllPluginArgsV2, + AssetPluginAuthorityPairArgsV2, + CreatePluginArgs, + PluginAuthorityPairHelperArgs, + PluginsList, +} from './types'; export function formPluginHeaderV1( pluginRegistryOffset: bigint diff --git a/clients/js/src/plugins/lifecycleChecks.ts b/clients/js/src/plugins/lifecycleChecks.ts index 7539a6c7..f63eddf7 100644 --- a/clients/js/src/plugins/lifecycleChecks.ts +++ b/clients/js/src/plugins/lifecycleChecks.ts @@ -2,7 +2,12 @@ import { ExternalCheckResult, HookableLifecycleEvent } from '../generated'; import { capitalizeFirstLetter } from '../utils'; -export type LifecycleEvent = 'create' | 'update' | 'transfer' | 'burn'; +export type LifecycleEvent = + | 'create' + | 'update' + | 'transfer' + | 'burn' + | 'execute'; // ExternalCheckResult is a bit array export enum CheckResult { diff --git a/clients/js/src/plugins/types.ts b/clients/js/src/plugins/types.ts index bc5d4a1f..2b148800 100644 --- a/clients/js/src/plugins/types.ts +++ b/clients/js/src/plugins/types.ts @@ -1,37 +1,44 @@ import { + AddBlocker, + Attributes, + AttributesArgs, + Autograph, + AutographArgs, + BaseMasterEditionArgs, + BasePluginAuthority, + BaseRoyaltiesArgs, + BubblegumV2, BurnDelegate, + Edition, + EditionArgs, FreezeDelegate, + FreezeDelegateArgs, + FreezeExecute, + FreezeExecuteArgs, + Groups, + GroupsArgs, + ImmutableMetadata, + PermanentBurnDelegate, PermanentFreezeDelegate, - TransferDelegate, - UpdateDelegate, - Attributes, + PermanentFreezeDelegateArgs, + PermanentFreezeExecute, + PermanentFreezeExecuteArgs, PermanentTransferDelegate, - PermanentBurnDelegate, - Edition, basePluginAuthority as pluginAuthority, - baseUpdateAuthority as updateAuthority, baseRuleSet as ruleSet, - FreezeDelegateArgs, + TransferDelegate, + baseUpdateAuthority as updateAuthority, + UpdateDelegate, UpdateDelegateArgs, - AttributesArgs, - PermanentFreezeDelegateArgs, - EditionArgs, - BasePluginAuthority, - BaseRoyaltiesArgs, - BaseMasterEditionArgs, - AddBlocker, - ImmutableMetadata, - AutographArgs, - VerifiedCreatorsArgs, - Autograph, VerifiedCreators, + VerifiedCreatorsArgs, } from '../generated'; -import { RoyaltiesArgs, RoyaltiesPlugin } from './royalties'; -import { PluginAuthority } from './pluginAuthority'; import { MasterEdition, MasterEditionArgs } from './masterEdition'; +import { PluginAuthority } from './pluginAuthority'; +import { RoyaltiesArgs, RoyaltiesPlugin } from './royalties'; // for backwards compatibility -export { pluginAuthority, updateAuthority, ruleSet }; +export { pluginAuthority, ruleSet, updateAuthority }; export type BasePlugin = { authority: PluginAuthority; @@ -88,6 +95,21 @@ export type CreatePluginArgs = } | { type: 'AddBlocker'; + } + | { + type: 'BubblegumV2'; + } + | { + type: 'FreezeExecute'; + data: FreezeExecuteArgs; + } + | { + type: 'Groups'; + data: GroupsArgs; + } + | { + type: 'PermanentFreezeExecute'; + data: PermanentFreezeExecuteArgs; }; export type AuthorityArgsV2 = { @@ -106,7 +128,13 @@ export type CreateOnlyPluginArgsV2 = } | ({ type: 'Edition'; - } & EditionArgs); + } & EditionArgs) + | { + type: 'BubblegumV2'; + } + | ({ + type: 'PermanentFreezeExecute'; + } & PermanentFreezeExecuteArgs); export type OwnerManagedPluginArgsV2 = | ({ @@ -120,7 +148,10 @@ export type OwnerManagedPluginArgsV2 = } | ({ type: 'Autograph'; - } & AutographArgs); + } & AutographArgs) + | ({ + type: 'FreezeExecute'; + } & FreezeExecuteArgs); export type AuthorityManagedPluginArgsV2 = | ({ @@ -132,6 +163,9 @@ export type AuthorityManagedPluginArgsV2 = | ({ type: 'Attributes'; } & AttributesArgs) + | ({ + type: 'Groups'; + } & GroupsArgs) | ({ type: 'MasterEdition'; } & MasterEditionArgs) @@ -181,9 +215,14 @@ export type AddBlockerPlugin = BasePlugin & AddBlocker; export type ImmutableMetadataPlugin = BasePlugin & ImmutableMetadata; export type VerifiedCreatorsPlugin = BasePlugin & VerifiedCreators; export type AutographPlugin = BasePlugin & Autograph; +export type BubblegumV2Plugin = BasePlugin & BubblegumV2; +export type FreezeExecutePlugin = BasePlugin & FreezeExecute; +export type GroupsPlugin = BasePlugin & Groups; +export type PermanentFreezeExecutePlugin = BasePlugin & PermanentFreezeExecute; export type CommonPluginsList = { attributes?: AttributesPlugin; + groups?: GroupsPlugin; royalties?: RoyaltiesPlugin; updateDelegate?: UpdateDelegatePlugin; permanentFreezeDelegate?: PermanentFreezeDelegatePlugin; @@ -193,6 +232,8 @@ export type CommonPluginsList = { immutableMetadata?: ImmutableMetadataPlugin; autograph?: AutographPlugin; verifiedCreators?: VerifiedCreatorsPlugin; + freezeExecute?: FreezeExecutePlugin; + permanentFreezeExecute?: PermanentFreezeExecutePlugin; }; export type AssetPluginsList = { @@ -204,6 +245,13 @@ export type AssetPluginsList = { export type CollectionPluginsList = { masterEdition?: MasterEditionPlugin; + bubblegumV2?: BubblegumV2Plugin; } & CommonPluginsList; export type PluginsList = AssetPluginsList & CollectionPluginsList; + +export type GroupPluginsList = { + attributes?: AttributesPlugin; + autograph?: AutographPlugin; + verifiedCreators?: VerifiedCreatorsPlugin; +}; diff --git a/clients/js/test/_setupRaw.ts b/clients/js/test/_setupRaw.ts index bc2f696e..9bfbe5b3 100644 --- a/clients/js/test/_setupRaw.ts +++ b/clients/js/test/_setupRaw.ts @@ -1,31 +1,38 @@ /* eslint-disable import/no-extraneous-dependencies */ -import { createUmi as basecreateUmi } from '@metaplex-foundation/umi-bundle-tests'; -import { Assertions } from 'ava'; import { - PublicKey, - Signer, - Umi, assertAccountExists, + deserializeAccount, generateSigner, + isSigner, + PublicKey, publicKey, + Signer, + Umi, } from '@metaplex-foundation/umi'; +import { createUmi as basecreateUmi } from '@metaplex-foundation/umi-bundle-tests'; +import { Assertions } from 'ava'; import { - DataState, - Key, + AssetPluginsList, + AssetV1, + createCollectionV1 as baseCreateCollection, + CollectionPluginsList, + CollectionV1, + createGroupV1, createV1, + DataState, + ExternalPluginAdaptersList, + fetchAsset, fetchAssetV1, fetchCollectionV1, + fetchGroupV1, + GroupPluginsList, + GroupV1, + Key, mplCore, - createCollectionV1 as baseCreateCollection, - CollectionV1, - AssetV1, PluginAuthorityPairArgs, UpdateAuthority, - ExternalPluginAdaptersList, - AssetPluginsList, - CollectionPluginsList, - fetchAsset, } from '../src'; +import { getGroupV1AccountDataSerializer } from '../src/hooked'; export const createUmi = async () => (await basecreateUmi()).use(mplCore()); @@ -52,6 +59,11 @@ export const DEFAULT_COLLECTION = { uri: 'https://example.com/collection', }; +export const DEFAULT_GROUP = { + name: 'Test Group', + uri: 'https://example.com/group', +}; + export const createAsset = async ( umi: Umi, input: CreateAssetHelperArgs = {} @@ -107,6 +119,65 @@ export const createCollection = async ( return fetchCollectionV1(umi, publicKey(collection)); }; +export const createGroup = async ( + umi: Umi, + input: { + name?: string; + uri?: string; + payer?: Signer; + group?: Signer; + updateAuthority?: PublicKey | Signer; + } = {} +) => { + const payer = input.payer || umi.identity; + const group = input.group || generateSigner(umi); + + // Determine if the provided updateAuthority is a signer or just a public key. + const providedUpdateAuth = input.updateAuthority; + + let updateAuthoritySigner: Signer | undefined; + let updateAuthorityPubkey: PublicKey | undefined; + + if (providedUpdateAuth) { + if (isSigner(providedUpdateAuth)) { + updateAuthoritySigner = providedUpdateAuth; + updateAuthorityPubkey = updateAuthoritySigner.publicKey; + } else { + updateAuthorityPubkey = publicKey(providedUpdateAuth); + } + } + + // Step 1: create the group. If we have a signer for the update authority, pass it now. + const createGroupArgs: Parameters[1] = { + name: input.name || DEFAULT_GROUP.name, + uri: input.uri || DEFAULT_GROUP.uri, + group, + payer, + relationships: [], + }; + if (updateAuthoritySigner) { + createGroupArgs.updateAuthority = updateAuthoritySigner; + } + + await createGroupV1(umi, createGroupArgs).sendAndConfirm(umi); + + // Step 2: If the desired update authority was provided as a public key (non-signer), + // update the group to set that new update authority. + if (updateAuthorityPubkey && !updateAuthoritySigner) { + const { updateGroup } = await import('../src'); + await updateGroup(umi, { + group: group.publicKey, + payer, + authority: payer, + newUpdateAuthority: updateAuthorityPubkey, + newName: null, + newUri: null, + }).sendAndConfirm(umi); + } + + return fetchGroupV1(umi, publicKey(group)); +}; + export const createAssetWithCollection: ( umi: Umi, assetInput: CreateAssetHelperArgs & { collection?: PublicKey | Signer }, @@ -123,9 +194,22 @@ export const createAssetWithCollection: ( ...collectionInput, }); + const { + updateAuthority: _assetUpdateAuthority, + collection: _assetCollection, + ...assetArgs + } = assetInput; + + const collectionAuthority = + assetInput.authority || + (assetInput.updateAuthority && isSigner(assetInput.updateAuthority) + ? assetInput.updateAuthority + : undefined); + const asset = await createAsset(umi, { - ...assetInput, + ...assetArgs, collection: collection.publicKey, + authority: collectionAuthority, }); return { @@ -212,6 +296,52 @@ export const assertCollection = async ( t.like(collectionWithPlugins, testObj); }; +export const assertGroup = async ( + t: Assertions, + umi: Umi, + input: { + group: PublicKey | Signer; + updateAuthority?: PublicKey | Signer; + name?: string | RegExp; + uri?: string | RegExp; + assets?: PublicKey[]; + collections?: PublicKey[]; + groups?: PublicKey[]; + parentGroups?: PublicKey[]; + } & GroupPluginsList & + ExternalPluginAdaptersList +) => { + const { group, name, uri, updateAuthority, ...rest } = input; + + const groupAddress = publicKey(group); + const maybeGroupAccount = await umi.rpc.getAccount(groupAddress); + assertAccountExists(maybeGroupAccount, 'GroupV1'); + const groupWithPlugins = deserializeAccount( + maybeGroupAccount, + getGroupV1AccountDataSerializer() + ); + + // Name. + if (typeof name === 'string') t.is(groupWithPlugins.name, name); + else if (name !== undefined) t.regex(groupWithPlugins.name, name); + + // Uri. + if (typeof uri === 'string') t.is(groupWithPlugins.uri, uri); + else if (uri !== undefined) t.regex(groupWithPlugins.uri, uri); + + const testObj = { + key: Key.GroupV1, + publicKey: groupAddress, + ...rest, + }; + + if (updateAuthority) { + testObj.updateAuthority = publicKey(updateAuthority); + } + + t.like(groupWithPlugins, testObj); +}; + export const assertBurned = async ( t: Assertions, umi: Umi, diff --git a/clients/js/test/accountOwnership.test.ts b/clients/js/test/accountOwnership.test.ts new file mode 100644 index 00000000..53bb7a57 --- /dev/null +++ b/clients/js/test/accountOwnership.test.ts @@ -0,0 +1,914 @@ +/** + * Account Ownership Tests + * + * This test suite proves that account ownership confusion was never exploitable + * in mpl-core, and that the newly added explicit owner checks in + * SolanaAccount::load are purely a defense-in-depth measure. + * + * BACKGROUND: + * The PR adds `account.owner != &crate::ID` checks to both the on-chain program + * and the Rust client's SolanaAccount::load method. These tests demonstrate that: + * + * 1. The Solana runtime already prevents other programs from writing mpl-core + * discriminator keys into accounts they own. + * 2. The existing discriminator key check (load_key) rejects accounts with + * non-matching first bytes, which is the case for any account not initialized + * by mpl-core. + * 3. The explicit owner check adds a belt-and-suspenders layer for safety. + */ + +import { generateSigner, publicKey, sol } from '@metaplex-foundation/umi'; +import test from 'ava'; +import { createAccount } from '@metaplex-foundation/mpl-toolbox'; +import { + addPluginV1, + burnCollectionV1, + burnV1, + createPlugin, + pluginAuthorityPair, + transferV1, + updateCollectionV1, + updateV1, +} from '../src'; +import { + assertAsset, + assertCollection, + createAsset, + createAssetWithCollection, + createCollection, + createUmi, + DEFAULT_ASSET, +} from './_setupRaw'; + +// ============================================================================ +// SECTION 1: Baseline - Normal operations succeed with correctly-owned accounts +// +// These tests confirm the program works correctly under normal conditions. +// All accounts are owned by the mpl-core program as expected. +// ============================================================================ + +test('baseline: transfer succeeds with correctly program-owned asset', async (t) => { + const umi = await createUmi(); + const newOwner = generateSigner(umi); + + const asset = await createAsset(umi); + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + await transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: newOwner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); +}); + +test('baseline: transfer succeeds with correctly program-owned asset and collection', async (t) => { + const umi = await createUmi(); + const newOwner = generateSigner(umi); + + const { asset, collection } = await createAssetWithCollection(umi, {}); + + await transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + collection: collection.publicKey, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: newOwner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); +}); + +test('baseline: burn succeeds with correctly program-owned asset', async (t) => { + const umi = await createUmi(); + + const asset = await createAsset(umi); + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + await burnV1(umi, { + asset: asset.publicKey, + }).sendAndConfirm(umi); + + const afterAccount = await umi.rpc.getAccount(asset.publicKey); + t.true(afterAccount.exists); +}); + +test('baseline: update succeeds with correctly program-owned asset', async (t) => { + const umi = await createUmi(); + + const asset = await createAsset(umi); + + await updateV1(umi, { + asset: asset.publicKey, + newName: 'Updated Name', + newUri: 'https://example.com/updated', + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + name: 'Updated Name', + uri: 'https://example.com/updated', + }); +}); + +test('baseline: add plugin succeeds with correctly program-owned asset', async (t) => { + const umi = await createUmi(); + + const asset = await createAsset(umi); + + await addPluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ type: 'FreezeDelegate', data: { frozen: false } }), + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + freezeDelegate: { + authority: { type: 'Owner' }, + frozen: false, + }, + }); +}); + +test('baseline: burn collection succeeds with correctly program-owned collection', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi); + + await burnCollectionV1(umi, { + collection: collection.publicKey, + compressionProof: null, + }).sendAndConfirm(umi); + + const afterAccount = await umi.rpc.getAccount(collection.publicKey); + t.true(afterAccount.exists); +}); + +test('baseline: update collection succeeds with correctly program-owned collection', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi); + + await updateCollectionV1(umi, { + collection: collection.publicKey, + newName: 'Updated Collection', + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + name: 'Updated Collection', + }); +}); + +// ============================================================================ +// SECTION 2: Discriminator key check rejects uninitialized/wrong-key accounts +// +// These tests prove that even before the owner check was added, the load_key +// discriminator check in SolanaAccount::load prevented deserialization of +// accounts with incorrect first bytes. Any account not initialized by mpl-core +// will have a 0x00 (Uninitialized) first byte, which fails the key check. +// ============================================================================ + +test('discriminator: transfer rejects account with uninitialized key owned by mpl-core', async (t) => { + // Create an account owned by mpl-core but with zeroed data (no valid discriminator). + // This simulates an account that was allocated but never properly initialized + // by the program. The transfer handler does an explicit load_key + match BEFORE + // SolanaAccount::load, so Key::Uninitialized hits the catch-all arm → IncorrectAccount. + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + const newOwner = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + const result = transferV1(umi, { + asset: fakeAsset.publicKey, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'IncorrectAccount' }); +}); + +test('discriminator: burn rejects account with uninitialized key owned by mpl-core', async (t) => { + // The burn handler also does an explicit load_key + match BEFORE + // SolanaAccount::load, so Key::Uninitialized → IncorrectAccount. + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + const result = burnV1(umi, { + asset: fakeAsset.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'IncorrectAccount' }); +}); + +test('discriminator: update rejects account with uninitialized key owned by mpl-core', async (t) => { + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + const result = updateV1(umi, { + asset: fakeAsset.publicKey, + newName: 'Hacked', + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +test('discriminator: add plugin rejects account with uninitialized key owned by mpl-core', async (t) => { + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + const result = addPluginV1(umi, { + asset: fakeAsset.publicKey, + plugin: createPlugin({ type: 'FreezeDelegate', data: { frozen: true } }), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +test('discriminator: transfer rejects fake collection with uninitialized key', async (t) => { + // Even before the owner check, passing a fake collection fails because: + // 1. The fake collection has Key::Uninitialized, failing the discriminator check. + // 2. Even if deserialization somehow passed, the asset's update_authority + // stores the real collection address which would not match the fake. + const umi = await createUmi(); + const newOwner = generateSigner(umi); + const fakeCollection = generateSigner(umi); + + const { asset } = await createAssetWithCollection(umi, {}); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + // Pass the fake collection - fails because the asset's update_authority + // stores a different collection address. + const result = transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + collection: fakeCollection.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); +}); + +test('discriminator: burn rejects fake collection with uninitialized key', async (t) => { + const umi = await createUmi(); + const fakeCollection = generateSigner(umi); + + const { asset } = await createAssetWithCollection(umi, {}); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + const result = burnV1(umi, { + asset: asset.publicKey, + collection: fakeCollection.publicKey, + }).sendAndConfirm(umi); + + // Fails because the burn handler loads the collection first via + // CollectionV1::load, and the zeroed data has Key::Uninitialized. + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +// ============================================================================ +// SECTION 3: Accounts owned by the wrong program are rejected +// +// These tests create accounts owned by programs OTHER than mpl-core and +// attempt to use them in mpl-core instructions. The Solana runtime restricts +// which programs can modify which accounts: +// - Only the owning program can modify account data. +// - For writable accounts in an instruction, the runtime checks ownership. +// +// Combined with the discriminator key check (and now the explicit owner check), +// these accounts are completely unusable by mpl-core. +// ============================================================================ + +test('wrong owner: transfer rejects asset account owned by system program', async (t) => { + // An account owned by the system program has zeroed data, so the first byte + // is 0x00 (Key::Uninitialized). The discriminator check catches this. + // The new owner check provides an additional layer of defense. + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + const newOwner = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = transferV1(umi, { + asset: fakeAsset.publicKey, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + // Rejected: zeroed data has Key::Uninitialized, caught by explicit load_key check. + await t.throwsAsync(result, { name: 'IncorrectAccount' }); +}); + +test('wrong owner: burn rejects asset account owned by system program', async (t) => { + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = burnV1(umi, { + asset: fakeAsset.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'IncorrectAccount' }); +}); + +test('wrong owner: update rejects asset account owned by system program', async (t) => { + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = updateV1(umi, { + asset: fakeAsset.publicKey, + newName: 'Hacked', + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +test('wrong owner: add plugin rejects asset account owned by system program', async (t) => { + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = addPluginV1(umi, { + asset: fakeAsset.publicKey, + plugin: createPlugin({ type: 'FreezeDelegate', data: { frozen: true } }), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +test('wrong owner: transfer rejects collection account owned by system program', async (t) => { + const umi = await createUmi(); + const newOwner = generateSigner(umi); + const fakeCollection = generateSigner(umi); + + const { asset } = await createAssetWithCollection(umi, {}); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + collection: fakeCollection.publicKey, + }).sendAndConfirm(umi); + + // Rejected because the fake collection address doesn't match what's stored + // in the asset's update_authority (address check in validate_asset_permissions). + await t.throwsAsync(result, { name: 'InvalidCollection' }); +}); + +test('wrong owner: burn rejects collection account owned by system program', async (t) => { + const umi = await createUmi(); + const fakeCollection = generateSigner(umi); + + const { asset } = await createAssetWithCollection(umi, {}); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = burnV1(umi, { + asset: asset.publicKey, + collection: fakeCollection.publicKey, + }).sendAndConfirm(umi); + + // Burn loads the collection via CollectionV1::load BEFORE the address check, + // so the zeroed data (Key::Uninitialized) fails the key check first. + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +// ============================================================================ +// SECTION 4: Address-based validation provides additional protection +// +// Even if an attacker could somehow craft an account with the correct +// discriminator key, the program validates that account addresses match +// expected values. For example, the collection address passed to transfer +// must match the address stored in the asset's update_authority field. +// ============================================================================ + +test('address validation: transfer rejects a real collection that does not match the asset', async (t) => { + // This test uses a REAL collection (correctly owned by mpl-core, with valid + // discriminator) but it's the WRONG collection for this asset. The program's + // address validation catches this regardless of the owner check. + const umi = await createUmi(); + const newOwner = generateSigner(umi); + + const { asset, collection } = await createAssetWithCollection(umi, {}); + const wrongCollection = await createCollection(umi); + + const result = transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + collection: wrongCollection.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); + + // Verify the asset was not modified. + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); +}); + +test('address validation: burn rejects a real collection that does not match the asset', async (t) => { + const umi = await createUmi(); + + const { asset, collection } = await createAssetWithCollection(umi, {}); + const wrongCollection = await createCollection(umi); + + const result = burnV1(umi, { + asset: asset.publicKey, + collection: wrongCollection.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); +}); + +test('address validation: update rejects a real collection that does not match the asset', async (t) => { + const umi = await createUmi(); + + const { asset, collection } = await createAssetWithCollection(umi, {}); + const wrongCollection = await createCollection(umi); + + const result = updateV1(umi, { + asset: asset.publicKey, + collection: wrongCollection.publicKey, + newName: 'Hacked', + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); +}); + +test('address validation: transfer rejects a collection specified for a standalone asset', async (t) => { + // A standalone asset (update_authority = Address) should not accept any + // collection account. The program returns InvalidCollection. + const umi = await createUmi(); + const newOwner = generateSigner(umi); + + const asset = await createAsset(umi); + const collection = await createCollection(umi); + + const result = transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + collection: collection.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); +}); + +// ============================================================================ +// SECTION 5: Authority checks prevent unauthorized operations +// +// Even with correctly-owned accounts, the program enforces strict authority +// checks. An attacker cannot perform operations on assets they don't own +// or have delegation for. These checks are independent of (and complementary +// to) the account ownership check. +// ============================================================================ + +test('authority: transfer rejects non-owner even with correct program-owned accounts', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + const newOwner = generateSigner(umi); + + const asset = await createAsset(umi); + + const result = transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + authority: attacker, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); +}); + +test('authority: burn rejects non-owner even with correct program-owned accounts', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const asset = await createAsset(umi); + + const result = burnV1(umi, { + asset: asset.publicKey, + authority: attacker, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); +}); + +test('authority: update rejects non-authority even with correct program-owned accounts', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const asset = await createAsset(umi); + + const result = updateV1(umi, { + asset: asset.publicKey, + newName: 'Hacked', + authority: attacker, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); +}); + +// ============================================================================ +// SECTION 6: Combined defense layers demonstration +// +// These tests demonstrate that multiple independent security layers work +// together. Even when one layer alone might theoretically be circumventable, +// the combination makes exploitation impossible. +// ============================================================================ + +test('combined defense: a completely random pubkey as asset fails immediately', async (t) => { + // A random pubkey that doesn't correspond to any on-chain account will + // fail even before any program logic executes. + const umi = await createUmi(); + const randomPubkey = generateSigner(umi); + const newOwner = generateSigner(umi); + + const result = transferV1(umi, { + asset: randomPubkey.publicKey, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result); +}); + +test('combined defense: an account owned by a random program as asset is rejected', async (t) => { + // Create an account with a random program as owner. This demonstrates that + // even a totally unknown program's accounts cannot be confused with mpl-core + // accounts. Multiple checks fail: wrong owner, wrong discriminator. + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + const randomProgram = generateSigner(umi); + const newOwner = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: randomProgram.publicKey, + }).sendAndConfirm(umi); + + const result = transferV1(umi, { + asset: fakeAsset.publicKey, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'IncorrectAccount' }); +}); + +test('combined defense: transfer with wrong-program collection and mismatched address fails', async (t) => { + // This test combines multiple attack vectors: + // 1. Collection account owned by wrong program (system program). + // 2. Collection address doesn't match asset's update_authority. + // The program rejects this through layered checks. + const umi = await createUmi(); + const newOwner = generateSigner(umi); + const fakeCollection = generateSigner(umi); + + const { asset, collection } = await createAssetWithCollection(umi, {}); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + collection: fakeCollection.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidCollection' }); + + // Verify the asset remains unchanged. + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + }); +}); + +test('combined defense: burn with wrong-program asset does not drain lamports', async (t) => { + // Ensure that passing a non-mpl-core account to burn cannot be used to + // drain lamports from the account to the payer. + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.5), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = burnV1(umi, { + asset: fakeAsset.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'IncorrectAccount' }); + + // Verify the fake asset still has its lamports (not drained). + const account = await umi.rpc.getAccount(fakeAsset.publicKey); + t.true(account.exists); +}); + +test('combined defense: update with wrong-program asset cannot modify data', async (t) => { + // Ensure that passing a non-mpl-core account to update cannot modify + // the account's data. + const umi = await createUmi(); + const fakeAsset = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeAsset, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = updateV1(umi, { + asset: fakeAsset.publicKey, + newName: 'Hacked', + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +// ============================================================================ +// SECTION 7: Collection-level operations with wrong ownership +// +// These tests specifically target collection-level instruction handlers where +// the collection account is the primary account being operated on. +// ============================================================================ + +test('wrong owner: burn collection rejects non-program-owned collection', async (t) => { + const umi = await createUmi(); + const fakeCollection = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = burnCollectionV1(umi, { + collection: fakeCollection.publicKey, + compressionProof: null, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +test('wrong owner: update collection rejects non-program-owned collection', async (t) => { + const umi = await createUmi(); + const fakeCollection = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: publicKey('11111111111111111111111111111111'), + }).sendAndConfirm(umi); + + const result = updateCollectionV1(umi, { + collection: fakeCollection.publicKey, + newName: 'Hacked Collection', + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +test('discriminator: burn collection rejects uninitialized account owned by mpl-core', async (t) => { + const umi = await createUmi(); + const fakeCollection = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + const result = burnCollectionV1(umi, { + collection: fakeCollection.publicKey, + compressionProof: null, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +test('discriminator: update collection rejects uninitialized account owned by mpl-core', async (t) => { + const umi = await createUmi(); + const fakeCollection = generateSigner(umi); + + await createAccount(umi, { + newAccount: fakeCollection, + lamports: sol(0.1), + space: 200, + programId: umi.programs.get('mplCore').publicKey, + }).sendAndConfirm(umi); + + const result = updateCollectionV1(umi, { + collection: fakeCollection.publicKey, + newName: 'Hacked Collection', + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'DeserializationError' }); +}); + +// ============================================================================ +// SECTION 8: Frozen asset protection with ownership confusion +// +// These tests verify that the freeze mechanism works correctly and cannot be +// bypassed using accounts from wrong programs. +// ============================================================================ + +test('frozen: transfer rejects even with correct ownership when asset is frozen', async (t) => { + const umi = await createUmi(); + const newOwner = generateSigner(umi); + + const asset = await createAsset(umi, { + plugins: [ + pluginAuthorityPair({ + type: 'FreezeDelegate', + data: { frozen: true }, + }), + ], + }); + + const result = transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + freezeDelegate: { + authority: { type: 'Owner' }, + frozen: true, + }, + }); +}); + +test('frozen: burn rejects even with correct ownership when asset is frozen', async (t) => { + const umi = await createUmi(); + + const asset = await createAsset(umi, { + plugins: [ + pluginAuthorityPair({ + type: 'FreezeDelegate', + data: { frozen: true }, + }), + ], + }); + + const result = burnV1(umi, { + asset: asset.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); diff --git a/clients/js/test/burn.test.ts b/clients/js/test/burn.test.ts index 0af4fd21..34dcd71a 100644 --- a/clients/js/test/burn.test.ts +++ b/clients/js/test/burn.test.ts @@ -2,7 +2,14 @@ import { generateSigner, sol } from '@metaplex-foundation/umi'; import test from 'ava'; import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests'; -import { burnV1, pluginAuthorityPair } from '../src'; +import { + addAssetsToGroup, + addCollectionsToGroup, + burn, + burnV1, + pluginAuthorityPair, + removeAssetsFromGroup, +} from '../src'; import { DEFAULT_ASSET, DEFAULT_COLLECTION, @@ -12,6 +19,7 @@ import { createAsset, createAssetWithCollection, createCollection, + createGroup, createUmi, } from './_setupRaw'; @@ -301,3 +309,81 @@ test('it can burn asset with different payer', async (t) => { t.true(lamportsAfter.basisPoints > lamportsBefore.basisPoints); }); + +test('it rejects burning an asset that belongs to a group', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const asset = await createAsset(umi); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + groups: { + authority: { type: 'UpdateAuthority' }, + groups: [group.publicKey], + }, + }); + + await t.throwsAsync(burn(umi, { asset }).sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); + +test('it allows burning an asset after removing it from all groups', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const asset = await createAsset(umi); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi); + + await removeAssetsFromGroup(umi, { + group: group.publicKey, + authority: umi.identity, + assets: [asset.publicKey], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi); + + await burn(umi, { asset }).sendAndConfirm(umi); + + await assertBurned(t, umi, asset.publicKey); +}); + +test('it rejects burning an asset in a collection that belongs to a group', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const { asset, collection } = await createAssetWithCollection(umi, {}); + + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await t.throwsAsync(burn(umi, { asset, collection }).sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); diff --git a/clients/js/test/burnCollection.test.ts b/clients/js/test/burnCollection.test.ts index abafbe0e..9c3ca6ae 100644 --- a/clients/js/test/burnCollection.test.ts +++ b/clients/js/test/burnCollection.test.ts @@ -2,13 +2,18 @@ import { generateSigner, sol } from '@metaplex-foundation/umi'; import test from 'ava'; import { generateSignerWithSol } from '@metaplex-foundation/umi-bundle-tests'; -import { burnCollection } from '../src'; +import { + addCollectionsToGroup, + burnCollection, + removeCollectionsFromGroup, +} from '../src'; import { DEFAULT_COLLECTION, assertBurned, assertCollection, createAssetWithCollection, createCollection, + createGroup, createUmi, } from './_setupRaw'; @@ -128,3 +133,68 @@ test('it cannot use an invalid noop program for collections', async (t) => { await t.throwsAsync(result, { name: 'InvalidLogWrapperProgram' }); }); + +test('it rejects burning a collection that belongs to a group', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const collection = await createCollection(umi); + + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + groups: { + authority: { type: 'UpdateAuthority' }, + groups: [group.publicKey], + }, + }); + + await t.throwsAsync( + burnCollection(umi, { + collection: collection.publicKey, + compressionProof: null, + }).sendAndConfirm(umi), + { name: 'InvalidAuthority' } + ); +}); + +test('it allows burning a collection after removing it from all groups', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const collection = await createCollection(umi); + + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await removeCollectionsFromGroup(umi, { + group: group.publicKey, + authority: umi.identity, + collections: [collection.publicKey], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await burnCollection(umi, { + collection: collection.publicKey, + compressionProof: null, + }).sendAndConfirm(umi); + + await assertBurned(t, umi, collection.publicKey); +}); diff --git a/clients/js/test/closeGroup.test.ts b/clients/js/test/closeGroup.test.ts new file mode 100644 index 00000000..63ffe52f --- /dev/null +++ b/clients/js/test/closeGroup.test.ts @@ -0,0 +1,119 @@ +import test from 'ava'; +import { + addAssetsToGroup, + addCollectionsToGroup, + addGroupsToGroup, + closeGroup, +} from '../src'; +import { + assertBurned, + createAsset, + createCollection, + createGroup, + createUmi, +} from './_setupRaw'; + +test('it can close a group', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + + await closeGroup(umi, { + group: group.publicKey, + }).sendAndConfirm(umi); + + await assertBurned(t, umi, group.publicKey); +}); + +test('it cannot close a group with child assets', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const asset = await createAsset(umi, {}); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { + isSigner: false, + isWritable: true, + pubkey: asset.publicKey, + }, + ]) + .sendAndConfirm(umi); + + await t.throwsAsync( + closeGroup(umi, { + group: group.publicKey, + }).sendAndConfirm(umi), + { name: 'GroupMustBeEmpty' } + ); +}); + +test('it rejects closing a group that still has child collections', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const collection = await createCollection(umi); + + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await t.throwsAsync( + closeGroup(umi, { + group: group.publicKey, + }).sendAndConfirm(umi), + { name: 'GroupMustBeEmpty' } + ); +}); + +test('it rejects closing a group that still has child groups', async (t) => { + const umi = await createUmi(); + const parent = await createGroup(umi, { name: 'parent' }); + const child = await createGroup(umi, { name: 'child' }); + + await addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi); + + await t.throwsAsync( + closeGroup(umi, { + group: parent.publicKey, + }).sendAndConfirm(umi), + { name: 'GroupMustBeEmpty' } + ); +}); + +test('it rejects closing a group that still has parent groups', async (t) => { + const umi = await createUmi(); + const parent = await createGroup(umi, { name: 'parent' }); + const child = await createGroup(umi, { name: 'child' }); + + await addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi); + + await t.throwsAsync( + closeGroup(umi, { + group: child.publicKey, + }).sendAndConfirm(umi), + { name: 'GroupMustBeEmpty' } + ); +}); diff --git a/clients/js/test/compute.test.ts b/clients/js/test/compute.test.ts new file mode 100644 index 00000000..2a11aa0f --- /dev/null +++ b/clients/js/test/compute.test.ts @@ -0,0 +1,96 @@ +import test from 'ava'; +import { addAssetsToGroup, removeAssetsFromGroup } from '../src'; +import { createAsset, createGroup, createUmi } from './_setupRaw'; + +const MAX_COMPUTE_UNITS = 1_400_000; +const STRESS_ADD_ASSET_COUNT = 20; +const STRESS_REMOVE_ASSET_COUNT = 10; + +/** + * Utility to fetch compute units consumed by a confirmed transaction signature. + */ +async function getComputeUnits( + umi: Awaited>, + signature: Uint8Array +) { + const txInfo = await umi.rpc.getTransaction(signature); + const computeUnitsConsumed = txInfo?.meta?.computeUnitsConsumed; + if (computeUnitsConsumed == null) { + throw new Error( + 'Unable to read compute units for the confirmed transaction' + ); + } + + return Number(computeUnitsConsumed); +} + +const toWritableRemainingAccounts = ( + assets: Awaited>[] +) => + assets.map((asset) => ({ + isSigner: false, + isWritable: true, + pubkey: asset.publicKey, + })); + +test.serial( + `compute units: adding ${STRESS_ADD_ASSET_COUNT} assets to a group stays below the 1.4M limit`, + async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + + const assets = await Promise.all( + Array.from({ length: STRESS_ADD_ASSET_COUNT }).map(() => createAsset(umi)) + ); + + const addTx = await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts(toWritableRemainingAccounts(assets)) + .sendAndConfirm(umi); + + const computeUnits = await getComputeUnits(umi, addTx.signature); + + t.true( + computeUnits <= MAX_COMPUTE_UNITS, + `Adding ${STRESS_ADD_ASSET_COUNT} assets used ${computeUnits} CUs which exceeds the 1.4M limit.` + ); + } +); + +test.serial( + `compute units: removing ${STRESS_REMOVE_ASSET_COUNT} assets from a group stays below the 1.4M limit`, + async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + + const assets = await Promise.all( + Array.from({ length: STRESS_REMOVE_ASSET_COUNT }).map(() => + createAsset(umi) + ) + ); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts(toWritableRemainingAccounts(assets)) + .sendAndConfirm(umi); + + const removeTx = await removeAssetsFromGroup(umi, { + group: group.publicKey, + assets: assets.map((a) => a.publicKey), + authority: umi.identity, + }) + .addRemainingAccounts(toWritableRemainingAccounts(assets)) + .sendAndConfirm(umi); + + const computeUnits = await getComputeUnits(umi, removeTx.signature); + + t.true( + computeUnits <= MAX_COMPUTE_UNITS, + `Removing ${STRESS_REMOVE_ASSET_COUNT} assets used ${computeUnits} CUs which exceeds the 1.4M limit.` + ); + } +); diff --git a/clients/js/test/createGroup.test.ts b/clients/js/test/createGroup.test.ts new file mode 100644 index 00000000..fd163ba0 --- /dev/null +++ b/clients/js/test/createGroup.test.ts @@ -0,0 +1,261 @@ +import test from 'ava'; +import { generateSigner } from '@metaplex-foundation/umi'; +import { addGroupsToGroup, createGroupV1, RelationshipKind } from '../src'; +import { + assertAsset, + assertCollection, + assertGroup, + createAsset, + createAssetWithCollection, + createCollection, + createGroup, + createUmi, + DEFAULT_ASSET, + DEFAULT_COLLECTION, + DEFAULT_GROUP, +} from './_setupRaw'; + +test('it can create a new group', async (t: any) => { + const umi = await createUmi(); + const group = await createGroup(umi, { + name: 'My Group', + }); + + await assertGroup(t, umi, { + ...DEFAULT_GROUP, + name: 'My Group', + group: group.publicKey, + updateAuthority: umi.identity.publicKey, + }); +}); + +test('it rejects creating a group with itself as a child relationship', async (t: any) => { + const umi = await createUmi(); + const group = generateSigner(umi); + + await t.throwsAsync( + createGroupV1(umi, { + name: 'Self Child Group', + uri: DEFAULT_GROUP.uri, + group, + payer: umi.identity, + relationships: [ + { kind: RelationshipKind.ChildGroup, key: group.publicKey }, + ], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: group.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'IncorrectAccount' } + ); +}); + +test('it rejects creating a group with itself as a parent relationship', async (t: any) => { + const umi = await createUmi(); + const group = generateSigner(umi); + + await t.throwsAsync( + createGroupV1(umi, { + name: 'Self Parent Group', + uri: DEFAULT_GROUP.uri, + group, + payer: umi.identity, + relationships: [ + { kind: RelationshipKind.ParentGroup, key: group.publicKey }, + ], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: group.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'IncorrectAccount' } + ); +}); + +test('it can createGroupV1 with all four relationship kinds in one call', async (t) => { + const umi = await createUmi(); + const group = generateSigner(umi); + const collection = await createCollection(umi); + const child = await createGroup(umi, { name: 'child' }); + const parent = await createGroup(umi, { name: 'parent' }); + const asset = await createAsset(umi); + + await createGroupV1(umi, { + name: 'all-relationships', + uri: 'https://example.com/all-relationships', + group, + payer: umi.identity, + relationships: [ + { kind: RelationshipKind.Collection, key: collection.publicKey }, + { kind: RelationshipKind.ChildGroup, key: child.publicKey }, + { kind: RelationshipKind.ParentGroup, key: parent.publicKey }, + { kind: RelationshipKind.Asset, key: asset.publicKey }, + ], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + { isSigner: false, isWritable: true, pubkey: parent.publicKey }, + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertGroup(t, umi, { + group: group.publicKey, + updateAuthority: umi.identity.publicKey, + name: 'all-relationships', + uri: 'https://example.com/all-relationships', + collections: [collection.publicKey], + groups: [child.publicKey], + parentGroups: [parent.publicKey], + assets: [asset.publicKey], + }); + + await assertGroup(t, umi, { + group: child.publicKey, + updateAuthority: umi.identity.publicKey, + parentGroups: [group.publicKey], + }); + + await assertGroup(t, umi, { + group: parent.publicKey, + updateAuthority: umi.identity.publicKey, + groups: [group.publicKey], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + groups: { + authority: { type: 'UpdateAuthority' }, + groups: [group.publicKey], + }, + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Address', + address: umi.identity.publicKey, + }, + groups: { + authority: { type: 'UpdateAuthority' }, + groups: [group.publicKey], + }, + }); +}); + +test('it allows collection authority to link collection-managed assets in createGroupV1', async (t) => { + const umi = await createUmi(); + const sharedAuthority = generateSigner(umi); + const group = generateSigner(umi); + const { asset, collection } = await createAssetWithCollection(umi, { + updateAuthority: sharedAuthority, + }); + + await createGroupV1(umi, { + name: 'collection-managed-asset-group', + uri: 'https://example.com/collection-managed-asset-group', + group, + payer: umi.identity, + updateAuthority: sharedAuthority, + relationships: [{ kind: RelationshipKind.Asset, key: asset.publicKey }], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + // Supplemental collection account used for collection-authority resolution. + { isSigner: false, isWritable: false, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertGroup(t, umi, { + group: group.publicKey, + updateAuthority: sharedAuthority.publicKey, + name: 'collection-managed-asset-group', + uri: 'https://example.com/collection-managed-asset-group', + assets: [asset.publicKey], + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { + type: 'Collection', + address: collection.publicKey, + }, + groups: { + authority: { type: 'UpdateAuthority' }, + groups: [group.publicKey], + }, + }); +}); + +test('it rejects createGroupV1 when parent relationships exceed nesting depth', async (t) => { + const umi = await createUmi(); + const group = generateSigner(umi); + + const tooManyParentRelationships = Array.from({ length: 9 }, () => ({ + kind: RelationshipKind.ParentGroup, + key: generateSigner(umi).publicKey, + })); + + const error = await t.throwsAsync( + createGroupV1(umi, { + name: 'too-many-parents', + uri: 'https://example.com/too-many-parents', + group, + payer: umi.identity, + relationships: tooManyParentRelationships, + }).sendAndConfirm(umi) + ); + + t.truthy(error); + t.regex((error as Error).message, /Group nesting depth exceeded/); +}); + +test.serial( + 'it rejects createGroupV1 when linking a child group that is already at max nesting depth', + async (t) => { + const umi = await createUmi(); + const child = await createGroup(umi, { name: 'max-depth-child' }); + + const maxDepth = 8; + for (let i = 0; i < maxDepth; i += 1) { + const parent = await createGroup(umi, { name: `depth-parent-${i}` }); + await addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi); + } + + const newGroup = generateSigner(umi); + const error = await t.throwsAsync( + createGroupV1(umi, { + name: 'would-exceed-child-depth', + uri: 'https://example.com/would-exceed-child-depth', + group: newGroup, + payer: umi.identity, + relationships: [ + { kind: RelationshipKind.ChildGroup, key: child.publicKey }, + ], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi) + ); + + t.truthy(error); + t.regex((error as Error).message, /Group nesting depth exceeded/); + } +); diff --git a/clients/js/test/execute.test.ts b/clients/js/test/execute.test.ts index 0cdee288..428dcbe7 100644 --- a/clients/js/test/execute.test.ts +++ b/clients/js/test/execute.test.ts @@ -9,7 +9,7 @@ import { import test from 'ava'; import { transferSol } from '@metaplex-foundation/mpl-toolbox'; -import { execute, findAssetSignerPda } from '../src'; +import { create, execute, fetchAssetV1, findAssetSignerPda } from '../src'; import { assertAsset, createAsset, createUmi } from './_setupRaw'; import { createAssetWithCollection, createCollection } from './_setupSdk'; @@ -374,6 +374,140 @@ test('it cannot transfer asset in collection with the wrong collection', async ( await t.throwsAsync(result, { name: 'InvalidCollection' }); }); +test('it can execute so the asset signer PDA pays the fee', async (t) => { + const umi = await createUmi(); + const recipient = generateSigner(umi); + + const asset = await createAsset(umi); + const assetSigner = findAssetSignerPda(umi, { asset: asset.publicKey }); + await umi.rpc.airdrop(publicKey(assetSigner), sol(1)); + + const beforeAssetSignerBalance = await umi.rpc.getBalance( + publicKey(assetSigner) + ); + const beforePayerBalance = await umi.rpc.getBalance(umi.identity.publicKey); + + t.deepEqual(beforeAssetSignerBalance, sol(1)); + + await execute(umi, { + asset, + authority: umi.identity, + payer: assetSigner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSigner)), + destination: recipient.publicKey, + amount: sol(0.5), + }), + }).sendAndConfirm(umi); + + const afterAssetSignerBalance = await umi.rpc.getBalance( + publicKey(assetSigner) + ); + const afterRecipientBalance = await umi.rpc.getBalance(publicKey(recipient)); + const afterPayerBalance = await umi.rpc.getBalance(umi.identity.publicKey); + const afterAssetBalance = await umi.rpc.getBalance( + publicKey(asset.publicKey) + ); + + // The asset signer PDA should have lost 0.5 SOL (transfer) + the execute fee. + // 1 SOL - 0.5 SOL transfer - 48720 lamports fee = 0.5 SOL - 48720 lamports + t.deepEqual(afterAssetSignerBalance, lamports(sol(0.5).basisPoints - 48720n)); + t.deepEqual(afterRecipientBalance, sol(0.5)); + // The asset account should have gained the execute fee. + t.deepEqual(afterAssetBalance, addAmounts(sol(0.00315648), lamports(48720))); + // The payer's balance should only decrease by the transaction fee, NOT the + // execute fee (since the wallet paid it). + const payerDiff = + BigInt(beforePayerBalance.basisPoints.toString()) - + BigInt(afterPayerBalance.basisPoints.toString()); + // The payer only paid the transaction fee (5000 lamports), not the execute fee. + t.true(payerDiff < 10000n); +}); + +test('it can execute for an asset in a collection so the asset signer PDA pays the fee', async (t) => { + const umi = await createUmi(); + const recipient = generateSigner(umi); + + const { asset, collection } = await createAssetWithCollection(umi, {}); + const assetSigner = findAssetSignerPda(umi, { asset: asset.publicKey }); + await umi.rpc.airdrop(publicKey(assetSigner), sol(1)); + + const beforeAssetSignerBalance = await umi.rpc.getBalance( + publicKey(assetSigner) + ); + + t.deepEqual(beforeAssetSignerBalance, sol(1)); + + await execute(umi, { + asset, + collection, + authority: umi.identity, + payer: assetSigner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSigner)), + destination: recipient.publicKey, + amount: sol(0.5), + }), + }).sendAndConfirm(umi); + + const afterAssetSignerBalance = await umi.rpc.getBalance( + publicKey(assetSigner) + ); + const afterRecipientBalance = await umi.rpc.getBalance(publicKey(recipient)); + const afterAssetBalance = await umi.rpc.getBalance( + publicKey(asset.publicKey) + ); + + t.deepEqual(afterAssetSignerBalance, lamports(sol(0.5).basisPoints - 48720n)); + t.deepEqual(afterRecipientBalance, sol(0.5)); + t.deepEqual(afterAssetBalance, addAmounts(sol(0.00315648), lamports(48720))); +}); + +test('it can execute multiple instructions so the asset signer PDA pays the fee', async (t) => { + const umi = await createUmi(); + const recipient = generateSigner(umi); + + const asset = await createAsset(umi); + const assetSigner = findAssetSignerPda(umi, { asset: asset.publicKey }); + await umi.rpc.airdrop(publicKey(assetSigner), sol(1)); + + await execute(umi, { + asset, + authority: umi.identity, + payer: assetSigner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSigner)), + destination: recipient.publicKey, + amount: sol(0.25), + }).add( + transferSol(umi, { + source: createNoopSigner(publicKey(assetSigner)), + destination: recipient.publicKey, + amount: sol(0.25), + }) + ), + }).sendAndConfirm(umi); + + const afterAssetSignerBalance = await umi.rpc.getBalance( + publicKey(assetSigner) + ); + const afterRecipientBalance = await umi.rpc.getBalance(publicKey(recipient)); + const afterAssetBalance = await umi.rpc.getBalance( + publicKey(asset.publicKey) + ); + + // Two execute calls, each with a fee of 48720 lamports. + t.deepEqual( + afterAssetSignerBalance, + lamports(sol(0.5).basisPoints - 48720n * 2n) + ); + t.deepEqual(afterRecipientBalance, sol(0.5)); + t.deepEqual( + afterAssetBalance, + addAmounts(sol(0.00315648), lamports(48720 * 2)) + ); +}); + test('it cannot use an invalid system program', async (t) => { // Given a Umi instance and a new signer. const umi = await createUmi(); @@ -401,3 +535,118 @@ test('it cannot use an invalid system program', async (t) => { await t.throwsAsync(result, { name: 'InvalidSystemProgram' }); }); + +test('it can execute a create instruction via the asset signer PDA', async (t) => { + const umi = await createUmi(); + + // Create an asset whose assetSigner PDA will be used to create a new asset. + const asset = await createAsset(umi); + const assetSigner = findAssetSignerPda(umi, { asset: asset.publicKey }); + await umi.rpc.airdrop(publicKey(assetSigner), sol(1)); + + // Build a create instruction for a brand new asset. + // The assetSigner PDA pays for the new asset, and the newAsset keypair + // must sign the transaction. The execute wrapper should preserve + // the newAsset signer, but currently drops it. + const newAsset = generateSigner(umi); + const createBuilder = create(umi, { + asset: newAsset, + name: 'Execute Created Asset', + uri: 'https://example.com/execute-created', + owner: umi.identity.publicKey, + updateAuthority: umi.identity.publicKey, + payer: createNoopSigner(publicKey(assetSigner)), + }); + + await execute(umi, { + asset, + instructions: createBuilder, + }).sendAndConfirm(umi); + + // If the signer was preserved, the new asset should exist on-chain. + const createdAsset = await fetchAssetV1(umi, newAsset.publicKey); + t.is(createdAsset.owner, umi.identity.publicKey); + t.is(createdAsset.name, 'Execute Created Asset'); + t.is(createdAsset.uri, 'https://example.com/execute-created'); +}); + +test('it can execute multiple create instructions with distinct signers via a TransactionBuilder', async (t) => { + const umi = await createUmi(); + + // Create an asset whose assetSigner PDA will pay for the new assets. + const asset = await createAsset(umi); + const assetSigner = findAssetSignerPda(umi, { asset: asset.publicKey }); + await umi.rpc.airdrop(publicKey(assetSigner), sol(2)); + + // Build two create instructions, each with its own distinct mint signer. + // The execute wrapper must preserve per-item signers so that each + // execute instruction carries only its own mint signer. + const newAssetA = generateSigner(umi); + const newAssetB = generateSigner(umi); + + const multiCreateBuilder = create(umi, { + asset: newAssetA, + name: 'Asset A', + uri: 'https://example.com/a', + owner: umi.identity.publicKey, + updateAuthority: umi.identity.publicKey, + payer: createNoopSigner(publicKey(assetSigner)), + }).add( + create(umi, { + asset: newAssetB, + name: 'Asset B', + uri: 'https://example.com/b', + owner: umi.identity.publicKey, + updateAuthority: umi.identity.publicKey, + payer: createNoopSigner(publicKey(assetSigner)), + }) + ); + + await execute(umi, { + asset, + instructions: multiCreateBuilder, + }).sendAndConfirm(umi); + + // Both assets should exist on-chain with the correct data. + const createdA = await fetchAssetV1(umi, newAssetA.publicKey); + t.is(createdA.owner, umi.identity.publicKey); + t.is(createdA.name, 'Asset A'); + t.is(createdA.uri, 'https://example.com/a'); + + const createdB = await fetchAssetV1(umi, newAssetB.publicKey); + t.is(createdB.owner, umi.identity.publicKey); + t.is(createdB.name, 'Asset B'); + t.is(createdB.uri, 'https://example.com/b'); +}); + +test('it can execute a create Instruction[] with explicit signers', async (t) => { + const umi = await createUmi(); + + const asset = await createAsset(umi); + const assetSigner = findAssetSignerPda(umi, { asset: asset.publicKey }); + await umi.rpc.airdrop(publicKey(assetSigner), sol(1)); + + // Build a create instruction, then extract raw Instruction[] from it. + // Raw instructions don't carry Signer objects, so the newAsset signer + // must be passed explicitly via args.signers. + const newAsset = generateSigner(umi); + const instructions = create(umi, { + asset: newAsset, + name: 'Instruction Array Asset', + uri: 'https://example.com/ix-array', + owner: umi.identity.publicKey, + updateAuthority: umi.identity.publicKey, + payer: createNoopSigner(publicKey(assetSigner)), + }).getInstructions(); + + await execute(umi, { + asset, + instructions, + signers: [newAsset], + }).sendAndConfirm(umi); + + const createdAsset = await fetchAssetV1(umi, newAsset.publicKey); + t.is(createdAsset.owner, umi.identity.publicKey); + t.is(createdAsset.name, 'Instruction Array Asset'); + t.is(createdAsset.uri, 'https://example.com/ix-array'); +}); diff --git a/clients/js/test/externalPlugins/oracle.test.ts b/clients/js/test/externalPlugins/oracle.test.ts index 51d7bb32..2c6114eb 100644 --- a/clients/js/test/externalPlugins/oracle.test.ts +++ b/clients/js/test/externalPlugins/oracle.test.ts @@ -2976,6 +2976,243 @@ test('it can update oracle to larger registry record', async (t) => { t.is(afterLength - beforeLength, 15); }); +test('it can shrink a leading oracle without corrupting trailing oracle metadata', async (t) => { + const umi = await createUmi(); + const firstOracleSigner = generateSigner(umi); + const secondOracleSigner = generateSigner(umi); + + await fixedAccountInit(umi, { + signer: umi.identity, + account: firstOracleSigner, + args: { + oracleData: { + __kind: 'V1', + create: ExternalValidationResult.Pass, + transfer: ExternalValidationResult.Pass, + burn: ExternalValidationResult.Pass, + update: ExternalValidationResult.Pass, + }, + }, + }).sendAndConfirm(umi); + + await fixedAccountInit(umi, { + signer: umi.identity, + account: secondOracleSigner, + args: { + oracleData: { + __kind: 'V1', + create: ExternalValidationResult.Pass, + transfer: ExternalValidationResult.Pass, + burn: ExternalValidationResult.Pass, + update: ExternalValidationResult.Pass, + }, + }, + }).sendAndConfirm(umi); + + const asset = generateSigner(umi); + await create(umi, { + asset, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'Oracle', + resultsOffset: { + type: 'Custom', + offset: 48n, + }, + lifecycleChecks: { + transfer: [CheckResult.CAN_REJECT], + }, + baseAddress: firstOracleSigner.publicKey, + }, + { + type: 'Oracle', + resultsOffset: { + type: 'Anchor', + }, + lifecycleChecks: { + burn: [CheckResult.CAN_REJECT], + }, + baseAddress: secondOracleSigner.publicKey, + }, + ], + }).sendAndConfirm(umi); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + key: { + type: 'Oracle', + baseAddress: firstOracleSigner.publicKey, + }, + type: 'Oracle', + resultsOffset: { + type: 'Anchor', + }, + lifecycleChecks: { + transfer: [CheckResult.CAN_REJECT], + }, + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + oracles: [ + { + authority: { + type: 'UpdateAuthority', + }, + type: 'Oracle', + resultsOffset: { + type: 'Anchor', + }, + lifecycleChecks: { + transfer: [CheckResult.CAN_REJECT], + }, + baseAddress: firstOracleSigner.publicKey, + baseAddressConfig: undefined, + }, + { + authority: { + type: 'UpdateAuthority', + }, + type: 'Oracle', + resultsOffset: { + type: 'Anchor', + }, + lifecycleChecks: { + burn: [CheckResult.CAN_REJECT], + }, + baseAddress: secondOracleSigner.publicKey, + baseAddressConfig: undefined, + }, + ], + }); +}); + +test('it can grow a leading oracle without corrupting trailing oracle metadata', async (t) => { + const umi = await createUmi(); + const firstOracleSigner = generateSigner(umi); + const secondOracleSigner = generateSigner(umi); + + await fixedAccountInit(umi, { + signer: umi.identity, + account: firstOracleSigner, + args: { + oracleData: { + __kind: 'V1', + create: ExternalValidationResult.Pass, + transfer: ExternalValidationResult.Pass, + burn: ExternalValidationResult.Pass, + update: ExternalValidationResult.Pass, + }, + }, + }).sendAndConfirm(umi); + + await fixedAccountInit(umi, { + signer: umi.identity, + account: secondOracleSigner, + args: { + oracleData: { + __kind: 'V1', + create: ExternalValidationResult.Pass, + transfer: ExternalValidationResult.Pass, + burn: ExternalValidationResult.Pass, + update: ExternalValidationResult.Pass, + }, + }, + }).sendAndConfirm(umi); + + const asset = generateSigner(umi); + await create(umi, { + asset, + name: 'Test name', + uri: 'https://example.com', + plugins: [ + { + type: 'Oracle', + resultsOffset: { + type: 'Anchor', + }, + lifecycleChecks: { + transfer: [CheckResult.CAN_REJECT], + }, + baseAddress: firstOracleSigner.publicKey, + }, + { + type: 'Oracle', + resultsOffset: { + type: 'Anchor', + }, + lifecycleChecks: { + burn: [CheckResult.CAN_REJECT], + }, + baseAddress: secondOracleSigner.publicKey, + }, + ], + }).sendAndConfirm(umi); + + await updatePlugin(umi, { + asset: asset.publicKey, + plugin: { + key: { + type: 'Oracle', + baseAddress: firstOracleSigner.publicKey, + }, + type: 'Oracle', + resultsOffset: { + type: 'Custom', + offset: 48n, + }, + lifecycleChecks: { + transfer: [CheckResult.CAN_REJECT], + }, + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + uri: 'https://example.com', + name: 'Test name', + owner: umi.identity.publicKey, + asset: asset.publicKey, + oracles: [ + { + authority: { + type: 'UpdateAuthority', + }, + type: 'Oracle', + resultsOffset: { + type: 'Custom', + offset: 48n, + }, + lifecycleChecks: { + transfer: [CheckResult.CAN_REJECT], + }, + baseAddress: firstOracleSigner.publicKey, + baseAddressConfig: undefined, + }, + { + authority: { + type: 'UpdateAuthority', + }, + type: 'Oracle', + resultsOffset: { + type: 'Anchor', + }, + lifecycleChecks: { + burn: [CheckResult.CAN_REJECT], + }, + baseAddress: secondOracleSigner.publicKey, + baseAddressConfig: undefined, + }, + ], + }); +}); + test('it create fails but does not panic when oracle account does not exist', async (t) => { const umi = await createUmi(); const oracleSigner = generateSigner(umi); diff --git a/clients/js/test/group.test.ts b/clients/js/test/group.test.ts new file mode 100644 index 00000000..8251a404 --- /dev/null +++ b/clients/js/test/group.test.ts @@ -0,0 +1,434 @@ +import { generateSigner, PublicKey } from '@metaplex-foundation/umi'; +import test from 'ava'; +import { + addAssetsToGroup, + addCollectionsToGroup, + getGroupV1GpaBuilder, + Key, + removeAssetsFromGroup, + removeCollectionsFromGroup, +} from '../src'; +import { + assertGroup, + createAsset, + createAssetWithCollection, + createCollection, + createGroup, + createUmi, +} from './_setupRaw'; + +test('it can gpa fetch groups by updateAuthority', async (t) => { + // Given a Umi instance and a new signer. + const umi = await createUmi(); + const updateAuthority = generateSigner(umi); + + await createGroup(umi, { + name: 'group1', + updateAuthority: updateAuthority.publicKey, + }); + await createGroup(umi, { + name: 'group2', + updateAuthority: updateAuthority.publicKey, + }); + await createGroup(umi, { name: 'group3' }); + + const groups = await getGroupV1GpaBuilder(umi) + .whereField('updateAuthority', updateAuthority.publicKey) + .whereField('key', Key.GroupV1) + .getDeserialized(); + const names = ['group1', 'group2']; + + t.is(groups.length, 2); + t.assert(groups.every((g) => names.includes(g.name))); + t.assert( + groups.every((g) => g.updateAuthority === updateAuthority.publicKey) + ); +}); + +test('it rejects addAssetsToGroup when signer is not group authority', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const group = await createGroup(umi); + const asset = await createAsset(umi); + + const builder = addAssetsToGroup(umi, { + group: group.publicKey, + authority: attacker, + }).addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]); + + await t.throwsAsync(builder.sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); + +test('it rejects removeAssetsFromGroup when signer is not group authority', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const group = await createGroup(umi); + const asset = await createAsset(umi); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi); + + const builder = removeAssetsFromGroup(umi, { + group: group.publicKey, + authority: attacker, + assets: [asset.publicKey], + }).addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]); + + await t.throwsAsync(builder.sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); + +test('it allows collection update authority to add collection-managed assets to a group', async (t) => { + const umi = await createUmi(); + const sharedAuthority = generateSigner(umi); + + const group = await createGroup(umi, { updateAuthority: sharedAuthority }); + const { asset, collection } = await createAssetWithCollection(umi, { + updateAuthority: sharedAuthority, + }); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: sharedAuthority, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + // Supplemental collection account used for collection-authority resolution. + { isSigner: false, isWritable: false, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertGroup(t, umi, { + group: group.publicKey, + updateAuthority: sharedAuthority.publicKey, + assets: [asset.publicKey], + }); +}); + +test('it allows collection update authority to remove collection-managed assets from a group', async (t) => { + const umi = await createUmi(); + const sharedAuthority = generateSigner(umi); + + const group = await createGroup(umi, { updateAuthority: sharedAuthority }); + const { asset, collection } = await createAssetWithCollection(umi, { + updateAuthority: sharedAuthority, + }); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: sharedAuthority, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + { isSigner: false, isWritable: false, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await removeAssetsFromGroup(umi, { + group: group.publicKey, + authority: sharedAuthority, + assets: [asset.publicKey], + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + { isSigner: false, isWritable: false, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertGroup(t, umi, { + group: group.publicKey, + updateAuthority: sharedAuthority.publicKey, + assets: [], + }); +}); + +test('it rejects addCollectionsToGroup when signer is not group authority', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const group = await createGroup(umi); + const collection = await createCollection(umi); + + const builder = addCollectionsToGroup(umi, { + group: group.publicKey, + authority: attacker, + }).addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]); + + await t.throwsAsync(builder.sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); + +test('it rejects removeCollectionsFromGroup when signer is not group authority', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const group = await createGroup(umi); + const collection = await createCollection(umi); + + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + const builder = removeCollectionsFromGroup(umi, { + group: group.publicKey, + authority: attacker, + collections: [collection.publicKey], + }).addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]); + + await t.throwsAsync(builder.sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); + +test('it rejects adding an already-member asset (duplicate entry)', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const asset = await createAsset(umi); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi); + + await t.throwsAsync( + addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'DuplicateEntry' } + ); +}); + +test('it rejects adding an already-member collection (duplicate entry)', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const collection = await createCollection(umi); + + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await t.throwsAsync( + addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'DuplicateEntry' } + ); +}); + +test('it rejects duplicate asset in remaining accounts for addAssetsToGroup', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const asset = await createAsset(umi); + + await t.throwsAsync( + addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'DuplicateEntry' } + ); +}); + +test('it rejects duplicate collection in remaining accounts for addCollectionsToGroup', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + const collection = await createCollection(umi); + + await t.throwsAsync( + addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'DuplicateEntry' } + ); +}); + +test.serial( + 'it rejects addAssetsToGroup when the group asset vector is already at max size', + async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + + const maxGroupVectorSize = 256; + const batchSize = 8; + let batch: PublicKey[] = []; + + for (let i = 0; i < maxGroupVectorSize; i += 1) { + const asset = await createAsset(umi); + batch.push(asset.publicKey); + + if (batch.length === batchSize) { + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts( + batch.map((pubkey) => ({ + isSigner: false, + isWritable: true, + pubkey, + })) + ) + .sendAndConfirm(umi); + + batch = []; + } + } + + if (batch.length > 0) { + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts( + batch.map((pubkey) => ({ + isSigner: false, + isWritable: true, + pubkey, + })) + ) + .sendAndConfirm(umi); + } + + const overflowAsset = await createAsset(umi); + const error = await t.throwsAsync( + addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { + isSigner: false, + isWritable: true, + pubkey: overflowAsset.publicKey, + }, + ]) + .sendAndConfirm(umi) + ); + + t.truthy(error); + t.regex((error as Error).message, /Group vector is at maximum capacity/); + } +); + +test.serial( + 'it rejects addCollectionsToGroup when the group collection vector is already at max size', + async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + + const maxGroupVectorSize = 256; + const batchSize = 8; + let batch: PublicKey[] = []; + + for (let i = 0; i < maxGroupVectorSize; i += 1) { + const collection = await createCollection(umi); + batch.push(collection.publicKey); + + if (batch.length === batchSize) { + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts( + batch.map((pubkey) => ({ + isSigner: false, + isWritable: true, + pubkey, + })) + ) + .sendAndConfirm(umi); + + batch = []; + } + } + + if (batch.length > 0) { + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts( + batch.map((pubkey) => ({ + isSigner: false, + isWritable: true, + pubkey, + })) + ) + .sendAndConfirm(umi); + } + + const overflowCollection = await createCollection(umi); + const error = await t.throwsAsync( + addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { + isSigner: false, + isWritable: true, + pubkey: overflowCollection.publicKey, + }, + ]) + .sendAndConfirm(umi) + ); + + t.truthy(error); + t.regex((error as Error).message, /Group vector is at maximum capacity/); + } +); diff --git a/clients/js/test/groupComplexRelations.test.ts b/clients/js/test/groupComplexRelations.test.ts new file mode 100644 index 00000000..5718cc13 --- /dev/null +++ b/clients/js/test/groupComplexRelations.test.ts @@ -0,0 +1,220 @@ +import { generateSigner } from '@metaplex-foundation/umi'; +import test from 'ava'; +import { addGroupsToGroup, removeGroupsFromGroup } from '../src'; +import { assertGroup, createGroup, createUmi } from './_setupRaw'; + +// ----------------------------------------------------------------------------- +// Complex Group Relations – Parent ↔ Child Synchronisation +// ----------------------------------------------------------------------------- + +test('it keeps parentGroups in sync with groups when adding and removing child groups', async (t) => { + // --------------------------------------------------------------------------- + // 1. Setup – create a parent and a child group. + // --------------------------------------------------------------------------- + const umi = await createUmi(); + const parent = await createGroup(umi, { name: 'parent' }); + const child = await createGroup(umi, { name: 'child' }); + + // --------------------------------------------------------------------------- + // 2. Add the child to the parent. + // --------------------------------------------------------------------------- + await addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi); + + // Parent should list child, and child should list parent. + await assertGroup(t, umi, { + group: parent.publicKey, + updateAuthority: umi.identity.publicKey, + groups: [child.publicKey], + }); + + await assertGroup(t, umi, { + group: child.publicKey, + updateAuthority: umi.identity.publicKey, + parentGroups: [parent.publicKey], + }); + + // --------------------------------------------------------------------------- + // 3. Remove the child again. + // --------------------------------------------------------------------------- + await removeGroupsFromGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi); + + // Relations should now be cleared on both sides. + await assertGroup(t, umi, { + group: parent.publicKey, + updateAuthority: umi.identity.publicKey, + groups: [], + }); + + await assertGroup(t, umi, { + group: child.publicKey, + updateAuthority: umi.identity.publicKey, + parentGroups: [], + }); +}); + +test('it rejects adding a parent group as its own child group', async (t) => { + const umi = await createUmi(); + const parent = await createGroup(umi, { name: 'parent' }); + + await t.throwsAsync( + addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [parent.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: parent.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'IncorrectAccount' } + ); +}); + +test('it rejects addGroupsToGroup when signer is not parent group authority', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const parent = await createGroup(umi, { name: 'parent' }); + const child = await createGroup(umi, { name: 'child' }); + + const builder = addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: attacker, + }).addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]); + + await t.throwsAsync(builder.sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); + +test('it rejects removeGroupsFromGroup when signer is not parent group authority', async (t) => { + const umi = await createUmi(); + const attacker = generateSigner(umi); + + const parent = await createGroup(umi, { name: 'parent' }); + const child = await createGroup(umi, { name: 'child' }); + + await addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi); + + const builder = removeGroupsFromGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: attacker, + }).addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]); + + await t.throwsAsync(builder.sendAndConfirm(umi), { + name: 'InvalidAuthority', + }); +}); + +test('it rejects duplicate child group in addGroupsToGroup', async (t) => { + const umi = await createUmi(); + const parent = await createGroup(umi, { name: 'parent' }); + const child = await createGroup(umi, { name: 'child' }); + + await t.throwsAsync( + addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey, child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'DuplicateEntry' } + ); +}); + +test('it rejects removing a child group that is not linked', async (t) => { + const umi = await createUmi(); + const parent = await createGroup(umi, { name: 'parent' }); + const unlinked = await createGroup(umi, { name: 'unlinked' }); + + await t.throwsAsync( + removeGroupsFromGroup(umi, { + parentGroup: parent.publicKey, + groups: [unlinked.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: unlinked.publicKey }, + ]) + .sendAndConfirm(umi), + { name: 'IncorrectAccount' } + ); +}); + +test.serial( + 'it rejects addGroupsToGroup when child group vector exceeds max size', + async (t) => { + const umi = await createUmi(); + const parent = await createGroup(umi, { name: 'parent-max-size' }); + + // Keep this in sync with MAX_GROUP_VECTOR_SIZE in Rust state. + const maxChildGroups = 256; + + for (let i = 0; i < maxChildGroups; i += 1) { + const child = await createGroup(umi, { name: `child-${i}` }); + await addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [child.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: child.publicKey }, + ]) + .sendAndConfirm(umi); + } + + const overflowChild = await createGroup(umi, { name: 'child-overflow' }); + const error = await t.throwsAsync( + addGroupsToGroup(umi, { + parentGroup: parent.publicKey, + groups: [overflowChild.publicKey], + authority: umi.identity, + }) + .addRemainingAccounts([ + { + isSigner: false, + isWritable: true, + pubkey: overflowChild.publicKey, + }, + ]) + .sendAndConfirm(umi) + ); + + t.truthy(error); + t.regex((error as Error).message, /Group vector is at maximum capacity/); + } +); diff --git a/clients/js/test/groupsPluginBlocking.test.ts b/clients/js/test/groupsPluginBlocking.test.ts new file mode 100644 index 00000000..ad00aa83 --- /dev/null +++ b/clients/js/test/groupsPluginBlocking.test.ts @@ -0,0 +1,210 @@ +import { generateSigner } from '@metaplex-foundation/umi'; +import test from 'ava'; + +import { + PluginType, + addAssetsToGroup, + addCollectionPluginV1, + addCollectionsToGroup, + addPluginV1, + addressPluginAuthority, + approveCollectionPluginAuthorityV1, + approvePluginAuthorityV1, + createPlugin, + pluginAuthorityPair, + removeCollectionPluginV1, + removePluginV1, + revokeCollectionPluginAuthorityV1, + revokePluginAuthorityV1, + updateCollectionPluginV1, + updatePluginV1, +} from '../src'; +import { + DEFAULT_ASSET, + DEFAULT_COLLECTION, + assertAsset, + assertCollection, + createAsset, + createCollection, + createGroup, + createUmi, +} from './_setupRaw'; + +test('it cannot create an asset with a Groups plugin', async (t) => { + const umi = await createUmi(); + + await t.throwsAsync( + createAsset(umi, { + plugins: [ + pluginAuthorityPair({ + type: 'Groups', + data: { groups: [umi.identity.publicKey] }, + }), + ], + }), + { name: 'InvalidPlugin' } + ); +}); + +test('it cannot create a collection with a Groups plugin', async (t) => { + const umi = await createUmi(); + + await t.throwsAsync( + createCollection(umi, { + plugins: [ + pluginAuthorityPair({ + type: 'Groups', + data: { groups: [umi.identity.publicKey] }, + }), + ], + }), + { name: 'InvalidPlugin' } + ); +}); + +test('it blocks generic asset plugin operations for Groups', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); + const group = await createGroup(umi); + const delegate = generateSigner(umi); + + await t.throwsAsync( + addPluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'Groups', + data: { groups: [group.publicKey] }, + }), + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await addAssetsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: asset.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + groups: { + authority: { type: 'UpdateAuthority' }, + groups: [group.publicKey], + }, + }); + + await t.throwsAsync( + updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'Groups', + data: { groups: [] }, + }), + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await t.throwsAsync( + removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.Groups, + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await t.throwsAsync( + approvePluginAuthorityV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.Groups, + newAuthority: addressPluginAuthority(delegate.publicKey), + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await t.throwsAsync( + revokePluginAuthorityV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.Groups, + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); +}); + +test('it blocks generic collection plugin operations for Groups', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi); + const group = await createGroup(umi); + const delegate = generateSigner(umi); + + await t.throwsAsync( + addCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'Groups', + data: { groups: [group.publicKey] }, + }), + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await addCollectionsToGroup(umi, { + group: group.publicKey, + authority: umi.identity, + }) + .addRemainingAccounts([ + { isSigner: false, isWritable: true, pubkey: collection.publicKey }, + ]) + .sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + groups: { + authority: { type: 'UpdateAuthority' }, + groups: [group.publicKey], + }, + }); + + await t.throwsAsync( + updateCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'Groups', + data: { groups: [] }, + }), + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await t.throwsAsync( + removeCollectionPluginV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.Groups, + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await t.throwsAsync( + approveCollectionPluginAuthorityV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.Groups, + newAuthority: addressPluginAuthority(delegate.publicKey), + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); + + await t.throwsAsync( + revokeCollectionPluginAuthorityV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.Groups, + }).sendAndConfirm(umi), + { name: 'InvalidPlugin' } + ); +}); diff --git a/clients/js/test/helps/fetch.test.ts b/clients/js/test/helps/fetch.test.ts index 930b8be3..a946f6a0 100644 --- a/clients/js/test/helps/fetch.test.ts +++ b/clients/js/test/helps/fetch.test.ts @@ -2,23 +2,26 @@ import test from 'ava'; import { generateSigner } from '@metaplex-foundation/umi'; import { + fetchAllAssets, fetchAssetsByCollection, fetchAssetsByOwner, fetchCollectionsByUpdateAuthority, - fetchAllAssets, } from '../../src'; import { createUmi } from '../_setupRaw'; import { createAsset, createCollection } from '../_setupSdk'; -test('it can use the helper to fetch assets by owner', async (t) => { +// Run all tests in this file serially to avoid overwhelming the local validator and hitting +// TransactionExpiredBlockheightExceededError when many concurrent transactions are sent. +const serial = test.serial; + +serial('it can use the helper to fetch assets by owner', async (t) => { const umi = await createUmi(); const owner = generateSigner(umi); - const assets = await Promise.all( - Array(5) - .fill(0) - .map(() => createAsset(umi, { owner: owner.publicKey })) - ); + const assets = [] as Awaited>[]; + for (let i = 0; i < 5; i += 1) { + assets.push(await createAsset(umi, { owner: owner.publicKey })); + } const fetchedAssets = await fetchAssetsByOwner(umi, owner.publicKey); @@ -29,15 +32,14 @@ test('it can use the helper to fetch assets by owner', async (t) => { ); }); -test('it can use helper to fetch assets by collection', async (t) => { +serial('it can use helper to fetch assets by collection', async (t) => { const umi = await createUmi(); const collection = await createCollection(umi); - const assets = await Promise.all( - Array(5) - .fill(0) - .map(() => createAsset(umi, { collection })) - ); + const assets = [] as Awaited>[]; + for (let i = 0; i < 5; i += 1) { + assets.push(await createAsset(umi, { collection })); + } const fetchedAssets = await fetchAssetsByCollection( umi, @@ -51,90 +53,57 @@ test('it can use helper to fetch assets by collection', async (t) => { ); }); -test('it can use helper to fetch collections by update authority', async (t) => { - const umi = await createUmi(); - const updateAuthority = generateSigner(umi); - - const collections = await Promise.all( - Array(5) - .fill(0) - .map(() => - createCollection(umi, { updateAuthority: updateAuthority.publicKey }) - ) - ); +serial( + 'it can use helper to fetch collections by update authority', + async (t) => { + const umi = await createUmi(); + const updateAuthority = generateSigner(umi); - const fetchedCollections = await fetchCollectionsByUpdateAuthority( - umi, - updateAuthority.publicKey - ); - - t.is(fetchedCollections.length, collections.length); - t.deepEqual( - fetchedCollections.map((collection) => collection.publicKey).sort(), - collections.map((collection) => collection.publicKey).sort() - ); -}); + const collections = [] as Awaited>[]; + for (let i = 0; i < 5; i += 1) { + collections.push( + await createCollection(umi, { + updateAuthority: updateAuthority.publicKey, + }) + ); + } -test('it can use helper to fetch assets by collection and derive plugins', async (t) => { - const umi = await createUmi(); - const collection = await createCollection(umi, { - plugins: [ - { - type: 'Attributes', - attributeList: [ - { - key: 'collection', - value: 'col', - }, - ], - }, - ], - }); + const fetchedCollections = await fetchCollectionsByUpdateAuthority( + umi, + updateAuthority.publicKey + ); - const override = await createAsset(umi, { - collection, - plugins: [ - { - type: 'Attributes', - attributeList: [ - { - key: 'asset', - value: 'asset', - }, - ], - }, - ], - }); + t.is(fetchedCollections.length, collections.length); + t.deepEqual( + fetchedCollections.map((collection) => collection.publicKey).sort(), + collections.map((collection) => collection.publicKey).sort() + ); + } +); - const assets = await Promise.all( - Array(4) - .fill(0) - .map(() => - createAsset(umi, { - collection, - plugins: [ +serial( + 'it can use helper to fetch assets by collection and derive plugins', + async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'Attributes', + attributeList: [ { - type: 'FreezeDelegate', - frozen: true, + key: 'collection', + value: 'col', }, ], - }) - ) - ); - - const fetchedAssets = await fetchAssetsByCollection( - umi, - collection.publicKey - ); - - t.is(fetchedAssets.length, assets.length + 1); + }, + ], + }); - fetchedAssets.forEach((asset) => { - if (asset.publicKey === override.publicKey) { - t.like(asset, { - numMinted: undefined, - currentSize: undefined, - attributes: { + const override = await createAsset(umi, { + collection, + plugins: [ + { + type: 'Attributes', attributeList: [ { key: 'asset', @@ -142,28 +111,67 @@ test('it can use helper to fetch assets by collection and derive plugins', async }, ], }, - }); - } else { - t.like(asset, { - numMinted: undefined, - currentSize: undefined, - freezeDelegate: { - frozen: true, - }, - attributes: { - attributeList: [ + ], + }); + + const assets = [] as Awaited>[]; + for (let i = 0; i < 4; i += 1) { + assets.push( + await createAsset(umi, { + collection, + plugins: [ { - key: 'collection', - value: 'col', + type: 'FreezeDelegate', + frozen: true, }, ], - }, - }); + }) + ); } - }); -}); -test('it can use helper to fetch all assets', async (t) => { + const fetchedAssets = await fetchAssetsByCollection( + umi, + collection.publicKey + ); + + t.is(fetchedAssets.length, assets.length + 1); + + fetchedAssets.forEach((asset) => { + if (asset.publicKey === override.publicKey) { + t.like(asset, { + numMinted: undefined, + currentSize: undefined, + attributes: { + attributeList: [ + { + key: 'asset', + value: 'asset', + }, + ], + }, + }); + } else { + t.like(asset, { + numMinted: undefined, + currentSize: undefined, + freezeDelegate: { + frozen: true, + }, + attributes: { + attributeList: [ + { + key: 'collection', + value: 'col', + }, + ], + }, + }); + } + }); + } +); + +serial('it can use helper to fetch all assets', async (t) => { const umi = await createUmi(); const collection = await createCollection(umi, { @@ -174,49 +182,47 @@ test('it can use helper to fetch all assets', async (t) => { ], }); - const assetsOfOwner1 = await Promise.all( - Array(2) - .fill(0) - .map((_, index) => - createAsset(umi, { - collection, - name: `Asset ${index + 1}`, - plugins: [ - { - type: 'Attributes', - attributeList: [ - { - key: 'asset', - value: 'asset', - }, - ], - }, - ], - }) - ) - ); + const assetsOfOwner1 = [] as Awaited>[]; + for (let i = 0; i < 2; i += 1) { + assetsOfOwner1.push( + await createAsset(umi, { + collection, + name: `Asset ${i + 1}`, + plugins: [ + { + type: 'Attributes', + attributeList: [ + { + key: 'asset', + value: 'asset', + }, + ], + }, + ], + }) + ); + } - const assetsOfOwner2 = await Promise.all( - Array(2) - .fill(0) - .map((_, index) => - createAsset(umi, { - collection, - name: `Asset ${index + 1}`, - plugins: [ - { - type: 'Attributes', - attributeList: [ - { - key: 'asset', - value: 'asset', - }, - ], - }, - ], - }) - ) - ); + const assetsOfOwner2 = [] as Awaited>[]; + for (let i = 0; i < 2; i += 1) { + assetsOfOwner2.push( + await createAsset(umi, { + collection, + name: `Asset ${i + 1}`, + plugins: [ + { + type: 'Attributes', + attributeList: [ + { + key: 'asset', + value: 'asset', + }, + ], + }, + ], + }) + ); + } const allCreatedAssets = [...assetsOfOwner1, ...assetsOfOwner2]; diff --git a/clients/js/test/plugins/asset/bubblegumV2.test.ts b/clients/js/test/plugins/asset/bubblegumV2.test.ts new file mode 100644 index 00000000..ebe2bf9a --- /dev/null +++ b/clients/js/test/plugins/asset/bubblegumV2.test.ts @@ -0,0 +1,35 @@ +import test from 'ava'; +import { createPlugin, addPluginV1 } from '../../../src'; +import { createUmi } from '../../_setupRaw'; +import { createAsset } from '../../_setupSdk'; + +test('it cannot create asset with BubblegumV2 plugin', async (t) => { + const umi = await createUmi(); + const result = createAsset(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + ], + }); + + await t.throwsAsync(result, { + name: 'InvalidPlugin', + }); +}); + +test('it cannot add BubblegumV2 to asset', async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); + + const result = addPluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'BubblegumV2', + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); +}); diff --git a/clients/js/test/plugins/asset/freezeExecute.test.ts b/clients/js/test/plugins/asset/freezeExecute.test.ts new file mode 100644 index 00000000..596dc9de --- /dev/null +++ b/clients/js/test/plugins/asset/freezeExecute.test.ts @@ -0,0 +1,93 @@ +import { transferSol } from '@metaplex-foundation/mpl-toolbox'; +import { + createNoopSigner, + generateSigner, + publicKey, + sol, +} from '@metaplex-foundation/umi'; +import test from 'ava'; + +import { + burnV1, + create, + execute, + fetchAssetV1, + findAssetSignerPda, +} from '../../../src'; +import { assertAsset, assertBurned, createUmi } from '../../_setupRaw'; + +test('it covers the freeze execute backed NFT flow', async (t) => { + // ---------------------------------- + // 0. Test setup. + // ---------------------------------- + const umi = await createUmi(); + + // ---------------------------------- + // 1. Mint an asset with FreezeExecute { frozen: true }. + // ---------------------------------- + const assetSigner = generateSigner(umi); + + await create(umi, { + asset: assetSigner, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [{ type: 'FreezeExecute', frozen: true }], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + }); + + // ---------------------------------- + // 2. Deposit backing SOL into the asset account (simulate 0.5 SOL backing). + // ---------------------------------- + // The Execute instruction pulls funds from the asset signer PDA, not the + // asset account itself, so credit that PDA with some lamports. + const [assetSignerPda] = findAssetSignerPda(umi, { + asset: asset.publicKey, + }); + + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + // ---------------------------------- + // 3. Attempt Execute → should fail because plugin is frozen. + // ---------------------------------- + const recipient = generateSigner(umi); + + const execResult = execute(umi, { + asset, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(execResult, { name: 'InvalidAuthority' }); + + // ---------------------------------- + // 4. Burn the asset → user should receive lamports back, asset account closed. + // ---------------------------------- + const balanceBefore = await umi.rpc.getBalance(umi.identity.publicKey); + + await burnV1(umi, { + asset: asset.publicKey, + }).sendAndConfirm(umi); + + // Assert the asset account is burned (resized to 1 byte). + await assertBurned(t, umi, asset.publicKey); + + const balanceAfter = await umi.rpc.getBalance(umi.identity.publicKey); + t.true( + balanceAfter.basisPoints > balanceBefore.basisPoints, + 'Payer balance did not increase after burn refund' + ); +}); diff --git a/clients/js/test/plugins/asset/freezeExecuteRemoval.test.ts b/clients/js/test/plugins/asset/freezeExecuteRemoval.test.ts new file mode 100644 index 00000000..7b6abbf1 --- /dev/null +++ b/clients/js/test/plugins/asset/freezeExecuteRemoval.test.ts @@ -0,0 +1,371 @@ +import { transferSol } from '@metaplex-foundation/mpl-toolbox'; +import { + createNoopSigner, + generateSigner, + publicKey, + sol, +} from '@metaplex-foundation/umi'; +import test from 'ava'; + +import { + approvePluginAuthorityV1, + create, + createPlugin, + execute, + fetchAssetV1, + findAssetSignerPda, + PluginType, + removePluginV1, + revokePluginAuthorityV1, + updatePluginV1, +} from '../../../src'; +import { assertAsset, createUmi, DEFAULT_ASSET } from '../../_setupRaw'; + +test('it cannot remove FreezeExecute while frozen', async (t) => { + const umi = await createUmi(); + const owner = umi.identity; + const updateAuth = generateSigner(umi); + const assetSigner = generateSigner(umi); + + // 1. Create an asset with FreezeExecute frozen. + // Owner and updateAuthority are distinct. + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + updateAuthority: updateAuth.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [{ type: 'FreezeExecute', frozen: true }], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + freezeExecute: { + authority: { type: 'Owner' }, + frozen: true, + }, + }); + + // 2. Owner removes FreezeExecute while frozen. + const result = removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.FreezeExecute, + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); + +test('it cannot revoke FreezeExecute as the owner while frozen', async (t) => { + const umi = await createUmi(); + const owner = umi.identity; + const updateAuth = generateSigner(umi); + const assetSigner = generateSigner(umi); + + // 1. Create an asset with FreezeExecute frozen. + // Owner and updateAuthority are distinct. + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + updateAuthority: updateAuth.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [{ type: 'FreezeExecute', frozen: true }], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + freezeExecute: { + authority: { type: 'Owner' }, + frozen: true, + }, + }); + + // 2. Owner revokes FreezeExecute while frozen. + const result = revokePluginAuthorityV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.FreezeExecute, + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); + +test('it cannot approve a new authority for FreezeExecute as the owner while frozen', async (t) => { + const umi = await createUmi(); + const owner = umi.identity; + const updateAuth = generateSigner(umi); + const assetSigner = generateSigner(umi); + const delegate = generateSigner(umi); + + // 1. Create an asset with FreezeExecute frozen. + // Owner and updateAuthority are distinct. + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + updateAuthority: updateAuth.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [{ type: 'FreezeExecute', frozen: true }], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + freezeExecute: { + authority: { type: 'Owner' }, + frozen: true, + }, + }); + + // 2. Owner approves a new authority for FreezeExecute while frozen. + const result = approvePluginAuthorityV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.FreezeExecute, + newAuthority: { __kind: 'Address', address: delegate.publicKey }, + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); + +test('Protocol-delegated FreezeExecute cannot be removed by owner despite freeze', async (t) => { + const umi = await createUmi(); + const owner = umi.identity; + const updateAuth = generateSigner(umi); + const protocol = generateSigner(umi); + const assetSigner = generateSigner(umi); + + // 1. Create asset with owner != updateAuthority. + // FreezeExecute is delegated to a protocol address and frozen. + // This simulates a protocol that locks Execute to guard PDA funds. + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + updateAuthority: updateAuth.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'FreezeExecute', + frozen: true, + authority: { type: 'Address', address: protocol.publicKey }, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + const [assetSignerPda] = findAssetSignerPda(umi, { asset: asset.publicKey }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + freezeExecute: { + authority: { type: 'Address', address: protocol.publicKey }, + frozen: true, + }, + }); + + // 2. Fund the PDA (simulating protocol-deposited funds). + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + // 3. Confirm Execute is blocked. + const recipient = generateSigner(umi); + const blockedExec = execute(umi, { + asset, + authority: owner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(blockedExec, { name: 'InvalidAuthority' }); + + // 4. Owner removes the protocol-delegated FreezeExecute while frozen. + // The protocol delegated this plugin and froze it — only the protocol + // should be able to unfreeze/remove. But owner-managed removal ignores + // the frozen state. + const result = removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.FreezeExecute, + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); +}); + +test('owner cannot unfreeze delegate-frozen FreezeExecute', async (t) => { + const umi = await createUmi(); + const owner = umi.identity; + const updateAuth = generateSigner(umi); + const delegate = generateSigner(umi); + const assetSigner = generateSigner(umi); + + // 1. Create asset with FreezeExecute delegated to a third party and frozen. + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + updateAuthority: updateAuth.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'FreezeExecute', + frozen: true, + authority: { type: 'Address', address: delegate.publicKey }, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + freezeExecute: { + authority: { type: 'Address', address: delegate.publicKey }, + frozen: true, + }, + }); + + // 2. Owner attempts to unfreeze — should be rejected (not the delegate). + const unfreezeResult = updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ type: 'FreezeExecute', data: { frozen: false } }), + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(unfreezeResult, { name: 'NoApprovals' }); + + // Plugin is still frozen. + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + freezeExecute: { + authority: { type: 'Address', address: delegate.publicKey }, + frozen: true, + }, + }); +}); + +test('delegate can unfreeze FreezeExecute', async (t) => { + const umi = await createUmi(); + const owner = umi.identity; + const updateAuth = generateSigner(umi); + const delegate = generateSigner(umi); + const assetSigner = generateSigner(umi); + + // 1. Create asset with FreezeExecute delegated and frozen. + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + updateAuthority: updateAuth.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'FreezeExecute', + frozen: true, + authority: { type: 'Address', address: delegate.publicKey }, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + // 2. Delegate unfreezes — should succeed. + await updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ type: 'FreezeExecute', data: { frozen: false } }), + authority: delegate, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: updateAuth.publicKey }, + freezeExecute: { + authority: { type: 'Address', address: delegate.publicKey }, + frozen: false, + }, + }); +}); + +test('owner can remove FreezeExecute after delegate unfreezes it', async (t) => { + const umi = await createUmi(); + const owner = umi.identity; + const updateAuth = generateSigner(umi); + const delegate = generateSigner(umi); + const assetSigner = generateSigner(umi); + + // 1. Create asset with FreezeExecute delegated and frozen. + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + updateAuthority: updateAuth.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'FreezeExecute', + frozen: true, + authority: { type: 'Address', address: delegate.publicKey }, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + // 2. Removal while frozen — should fail. + const blockedResult = removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.FreezeExecute, + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(blockedResult, { name: 'InvalidAuthority' }); + + // 3. Delegate unfreezes. + await updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ type: 'FreezeExecute', data: { frozen: false } }), + authority: delegate, + }).sendAndConfirm(umi); + + // 4. Owner removes now that it's unfrozen — should succeed. + await removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.FreezeExecute, + authority: owner, + }).sendAndConfirm(umi); + + const assetAfter = await fetchAssetV1(umi, asset.publicKey); + t.is(assetAfter.freezeExecute, undefined); +}); diff --git a/clients/js/test/plugins/asset/permanentFreezeExecute.test.ts b/clients/js/test/plugins/asset/permanentFreezeExecute.test.ts new file mode 100644 index 00000000..b443a102 --- /dev/null +++ b/clients/js/test/plugins/asset/permanentFreezeExecute.test.ts @@ -0,0 +1,567 @@ +import { transferSol } from '@metaplex-foundation/mpl-toolbox'; +import { + createNoopSigner, + generateSigner, + publicKey, + sol, +} from '@metaplex-foundation/umi'; +import test from 'ava'; + +import { + addPluginV1, + burnV1, + create, + createPlugin, + execute, + fetchAssetV1, + findAssetSignerPda, + PluginType, + removePluginV1, + transferV1, + updatePluginV1, +} from '../../../src'; +import { + assertAsset, + assertBurned, + createAsset, + createUmi, + DEFAULT_ASSET, +} from '../../_setupRaw'; + +test('it can freeze and unfreeze execute with PermanentFreezeExecute', async (t) => { + // Given a Umi instance + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(1)); + + // Create an asset with PermanentFreezeExecute plugin (frozen by default) + const assetSigner = generateSigner(umi); + + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Fund the asset signer PDA + const [assetSignerPda] = findAssetSignerPda(umi, { + asset: asset.publicKey, + }); + + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + // Attempt Execute → should fail because plugin is frozen + const recipient = generateSigner(umi); + + const execResult = execute(umi, { + asset, + payer: owner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(execResult, { name: 'InvalidAuthority' }); + + // Unfreeze the execute with update authority + await updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); + + // Now execute should succeed + await execute(umi, { + asset, + payer: owner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + // Verify recipient received the SOL + const recipientBalance = await umi.rpc.getBalance(recipient.publicKey); + t.true(recipientBalance.basisPoints >= sol(0.1).basisPoints); +}); + +test('it cannot add PermanentFreezeExecute after creation', async (t) => { + // Given a Umi instance and a new signer + const umi = await createUmi(); + const owner = generateSigner(umi); + + const asset = await createAsset(umi, { owner }); + + const result = addPluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: true }, + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: undefined, + }); +}); + +test('PermanentFreezeExecute persists after transfer to new owner and remains frozen', async (t) => { + // Given a Umi instance + const umi = await createUmi(); + const originalOwner = generateSigner(umi); + const newOwner = generateSigner(umi); + + // Create an asset with PermanentFreezeExecute plugin (frozen) + const assetSigner = generateSigner(umi); + + await create(umi, { + asset: assetSigner, + owner: originalOwner.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + // Verify initial state + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: originalOwner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Fund the asset signer PDA + const [assetSignerPda] = findAssetSignerPda(umi, { + asset: asset.publicKey, + }); + + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + // Transfer the asset to a new owner + await transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + authority: originalOwner, + }).sendAndConfirm(umi); + + // Verify the asset has been transferred + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: newOwner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Verify execute is still blocked with new owner + const recipient = generateSigner(umi); + + const execResult = execute(umi, { + asset, + payer: newOwner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(execResult, { name: 'InvalidAuthority' }); + + // Verify that only update authority (not the new owner) can unfreeze + const unfreezeByOwner = updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + authority: newOwner, + }).sendAndConfirm(umi); + + await t.throwsAsync(unfreezeByOwner, { name: 'NoApprovals' }); + + // Update authority can still unfreeze + await updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + authority: umi.identity, + }).sendAndConfirm(umi); + + // Verify unfrozen + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: newOwner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); +}); + +test('it cannot remove PermanentFreezeExecute plugin if frozen', async (t) => { + const umi = await createUmi(); + + const assetSigner = generateSigner(umi); + await create(umi, { + asset: assetSigner, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }).sendAndConfirm(umi); + const asset = await fetchAssetV1(umi, assetSigner.publicKey); + + const result = removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); +}); + +test('it can remove PermanentFreezeExecute plugin if unfrozen', async (t) => { + const umi = await createUmi(); + + const assetSigner = generateSigner(umi); + await create(umi, { + asset: assetSigner, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: false, + }, + ], + }).sendAndConfirm(umi); + const asset = await fetchAssetV1(umi, assetSigner.publicKey); + + await removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: undefined, + }); +}); + +test('it can add other plugins alongside PermanentFreezeExecute', async (t) => { + const umi = await createUmi(); + + const assetSigner = generateSigner(umi); + await create(umi, { + asset: assetSigner, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: false, + }, + ], + }).sendAndConfirm(umi); + const asset = await fetchAssetV1(umi, assetSigner.publicKey); + + await addPluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'TransferDelegate', + }), + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + transferDelegate: { + authority: { + type: 'Owner', + }, + }, + }); +}); + +test('PermanentFreezeExecute blocks execute but allows burn', async (t) => { + // Given a Umi instance + const umi = await createUmi(); + const owner = generateSigner(umi); + + // Create an asset with PermanentFreezeExecute plugin (frozen) + const assetSigner = generateSigner(umi); + + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + // Fund the asset signer PDA + const [assetSignerPda] = findAssetSignerPda(umi, { + asset: asset.publicKey, + }); + + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + // Verify execute is blocked + const recipient = generateSigner(umi); + const execResult = execute(umi, { + asset, + payer: owner, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(execResult, { name: 'InvalidAuthority' }); + + // But burn should still work + const balanceBefore = await umi.rpc.getBalance(owner.publicKey); + + await burnV1(umi, { + asset: asset.publicKey, + payer: owner, + }).sendAndConfirm(umi); + + // Assert the asset account is burned + await assertBurned(t, umi, asset.publicKey); + + const balanceAfter = await umi.rpc.getBalance(owner.publicKey); + t.true( + balanceAfter.basisPoints > balanceBefore.basisPoints, + 'Owner balance did not increase after burn refund' + ); +}); + +test('owner cannot remove or unfreeze PermanentFreezeExecute plugin', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + + // Create an asset with PermanentFreezeExecute plugin (frozen) + const assetSigner = generateSigner(umi); + + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, publicKey(assetSigner)); + + // Verify initial state + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Owner should not be able to unfreeze the plugin + const unfreezeResult = updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(unfreezeResult, { name: 'NoApprovals' }); + + // Owner should not be able to remove the plugin (even when frozen) + const removeResult = removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(removeResult, { name: 'InvalidAuthority' }); + + // Plugin should still be there and frozen + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Only update authority should be able to unfreeze + await updatePluginV1(umi, { + asset: asset.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + authority: umi.identity, // Update authority + }).sendAndConfirm(umi); + + // Now owner still cannot remove it even when unfrozen + const removeUnfrozenResult = removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + authority: owner, + }).sendAndConfirm(umi); + + await t.throwsAsync(removeUnfrozenResult, { name: 'NoApprovals' }); + + // But update authority can remove it when unfrozen + await removePluginV1(umi, { + asset: asset.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + authority: umi.identity, + }).sendAndConfirm(umi); + + // Verify plugin is removed + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + permanentFreezeExecute: undefined, + }); +}); diff --git a/clients/js/test/plugins/asset/pluginValidationOverrides.test.ts b/clients/js/test/plugins/asset/pluginValidationOverrides.test.ts new file mode 100644 index 00000000..3600a7f3 --- /dev/null +++ b/clients/js/test/plugins/asset/pluginValidationOverrides.test.ts @@ -0,0 +1,259 @@ +import test from 'ava'; +import { generateSigner, sol } from '@metaplex-foundation/umi'; +import { SPL_SYSTEM_PROGRAM_ID } from '@metaplex-foundation/mpl-toolbox'; +import { + pluginAuthorityPair, + addressPluginAuthority, + updatePluginAuthority, + burnV1, + transferV1, + ruleSet, +} from '../../../src'; +import { + assertAsset, + assertBurned, + createAsset, + createAssetWithCollection, + createUmi, +} from '../../_setupRaw'; + +// --------------------------------------------------------------------------- +// Gap 1: PermanentBurnDelegate burning a frozen asset (ForceApproved overrides +// freeze rejection on burn) +// --------------------------------------------------------------------------- + +test('it can burn a frozen asset using PermanentBurnDelegate (ForceApproved overrides freeze)', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(10)); + const delegate = generateSigner(umi); + + const asset = await createAsset(umi, { + owner, + plugins: [ + pluginAuthorityPair({ + type: 'PermanentBurnDelegate', + authority: addressPluginAuthority(delegate.publicKey), + }), + pluginAuthorityPair({ + type: 'FreezeDelegate', + data: { frozen: true }, + }), + ], + }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + freezeDelegate: { + authority: { type: 'Owner' }, + frozen: true, + }, + permanentBurnDelegate: { + authority: { type: 'Address', address: delegate.publicKey }, + }, + }); + + await burnV1(umi, { + asset: asset.publicKey, + authority: delegate, + payer: owner, + }).sendAndConfirm(umi); + + await assertBurned(t, umi, asset.publicKey); +}); + +test('it can burn a frozen asset using collection PermanentBurnDelegate (ForceApproved overrides freeze)', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(10)); + + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'FreezeDelegate', + data: { frozen: true }, + }), + ], + }, + { + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'PermanentBurnDelegate', + authority: updatePluginAuthority(), + }), + ], + } + ); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + freezeDelegate: { + authority: { type: 'Owner' }, + frozen: true, + }, + }); + + await burnV1(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + authority: owner, + payer: owner, + }).sendAndConfirm(umi); + + await assertBurned(t, umi, asset.publicKey); +}); + +// --------------------------------------------------------------------------- +// Gap 2: PermanentTransferDelegate overriding Royalties rejection +// --------------------------------------------------------------------------- + +test('it can transfer with PermanentTransferDelegate even when collection Royalties would reject', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(10)); + const delegate = generateSigner(umi); + + // Create a program-owned account to transfer to (triggers royalty check). + const programOwned = await createAsset(umi); + + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'PermanentTransferDelegate', + authority: addressPluginAuthority(delegate.publicKey), + }), + ], + }, + { + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'Royalties', + data: { + basisPoints: 500, + creators: [{ address: owner.publicKey, percentage: 100 }], + ruleSet: ruleSet('ProgramAllowList', [[SPL_SYSTEM_PROGRAM_ID]]), + }, + }), + ], + } + ); + + // Transfer to a program-owned address NOT on the allow list. + // Royalties would normally reject, but PermanentTransferDelegate ForceApproves. + await transferV1(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + authority: delegate, + newOwner: programOwned.publicKey, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: programOwned.publicKey, + }); +}); + +// --------------------------------------------------------------------------- +// Gap 3: Asset-level PermanentFreezeDelegate overrides collection-level +// PermanentFreezeDelegate (same PluginType key in BTreeMap, asset wins) +// --------------------------------------------------------------------------- + +test('asset PermanentFreezeDelegate(unfrozen) overrides collection PermanentFreezeDelegate(frozen) for transfer', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(10)); + const newOwner = generateSigner(umi); + + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'PermanentFreezeDelegate', + data: { frozen: false }, + }), + ], + }, + { + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'PermanentFreezeDelegate', + data: { frozen: true }, + }), + ], + } + ); + + // Asset's unfrozen PermanentFreezeDelegate should override collection's frozen one. + await transferV1(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + authority: owner, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: newOwner.publicKey, + }); +}); + +test('asset PermanentFreezeDelegate(frozen) blocks transfer even when collection PermanentFreezeDelegate is unfrozen', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(10)); + const newOwner = generateSigner(umi); + + const { asset, collection } = await createAssetWithCollection( + umi, + { + owner: owner.publicKey, + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'PermanentFreezeDelegate', + data: { frozen: true }, + }), + ], + }, + { + payer: owner, + plugins: [ + pluginAuthorityPair({ + type: 'PermanentFreezeDelegate', + data: { frozen: false }, + }), + ], + } + ); + + // Asset's frozen PermanentFreezeDelegate should block transfer regardless of collection. + const result = transferV1(umi, { + asset: asset.publicKey, + collection: collection.publicKey, + authority: owner, + newOwner: newOwner.publicKey, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'InvalidAuthority' }); + + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: owner.publicKey, + }); +}); diff --git a/clients/js/test/plugins/asset/updateDelegateRevokeBug.test.ts b/clients/js/test/plugins/asset/updateDelegateRevokeBug.test.ts new file mode 100644 index 00000000..0af5a5a7 --- /dev/null +++ b/clients/js/test/plugins/asset/updateDelegateRevokeBug.test.ts @@ -0,0 +1,429 @@ +/** + * Tests for PR 253: Operator precedence bug in UpdateDelegate validate_revoke_plugin_authority + * + * This test file validates a security vulnerability where the UpdateDelegate plugin's + * validate_revoke_plugin_authority function has incorrect operator precedence. Due to + * Rust's operator precedence (&& binds tighter than ||), the condition: + * + * A || B && C && D + * + * is evaluated as: + * + * A || (B && C && D) + * + * instead of the intended: + * + * (A || (B && C)) && D + * + * This means the manager check (plugin.manager() == Authority::UpdateAuthority) only + * applies to the additional_delegates branch, not the main resolved_authorities branch. + * + * The result is that UpdateDelegate can revoke authority on owner-managed plugins + * (like FreezeDelegate, TransferDelegate) when it should only be able to revoke + * authority on UpdateAuthority-managed plugins. + */ + +import { generateSigner } from '@metaplex-foundation/umi'; +import test from 'ava'; +import { approvePluginAuthority, revokePluginAuthority } from '../../../src'; +import { DEFAULT_ASSET, assertAsset, createUmi } from '../../_setupRaw'; +import { createAsset } from '../../_setupSdk'; + +/** + * This test demonstrates the operator precedence bug in validate_revoke_plugin_authority. + * + * When the UpdateAuthority (who implicitly has UpdateDelegate powers via resolved_authorities) + * tries to revoke authority on an owner-managed plugin (FreezeDelegate), it should fail + * because FreezeDelegate is owner-managed, not UpdateAuthority-managed. + * + * Due to the bug, this operation incorrectly SUCCEEDS because the manager check + * doesn't apply to the resolved_authorities branch. + * + * EXPECTED BEHAVIOR (after fix): This test should FAIL (throw NoApprovals) + * CURRENT BEHAVIOR (with bug): This test PASSES (allows the revoke) + */ +test('it should NOT allow update authority to revoke authority on owner-managed plugins via UpdateDelegate', async (t) => { + const umi = await createUmi(); + // IMPORTANT: Use a separate owner distinct from the update authority (umi.identity) + // This ensures the signer acts ONLY as update authority, not as owner. + // Without this separation, the revoke would succeed via owner permissions, + // not through the UpdateDelegate bug path we're trying to test. + const owner = generateSigner(umi); + const freezeDelegateAuthority = generateSigner(umi); + + // Create an asset with: + // - owner: separate signer (NOT umi.identity) + // - updateAuthority: umi.identity + // - UpdateDelegate plugin (default authority: UpdateAuthority) + // - FreezeDelegate plugin (default authority: Owner - an owner-managed plugin) + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + { + type: 'FreezeDelegate', + frozen: false, + }, + ], + }); + + // Verify the asset was created with correct plugin authorities + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { type: 'UpdateAuthority' }, + additionalDelegates: [], + }, + freezeDelegate: { + authority: { type: 'Owner' }, + frozen: false, + }, + }); + + // Now as the owner, approve a new authority for FreezeDelegate + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'FreezeDelegate' }, + newAuthority: { + type: 'Address', + address: freezeDelegateAuthority.publicKey, + }, + authority: owner, // Owner must sign to approve authority on owner-managed plugin + }).sendAndConfirm(umi); + + // Verify the FreezeDelegate authority was changed + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { type: 'UpdateAuthority' }, + additionalDelegates: [], + }, + freezeDelegate: { + authority: { + type: 'Address', + address: freezeDelegateAuthority.publicKey, + }, + frozen: false, + }, + }); + + // Now, try to revoke authority on FreezeDelegate using the UpdateAuthority + // (who has UpdateDelegate powers via resolved_authorities). + // + // THIS SHOULD FAIL because FreezeDelegate is an owner-managed plugin, + // not an UpdateAuthority-managed plugin. UpdateDelegate should only be able + // to revoke authority on UpdateAuthority-managed plugins. + // + // Due to the operator precedence bug, this incorrectly succeeds. + const result = revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'FreezeDelegate' }, + // Using the default authority (umi.identity = UpdateAuthority, NOT owner) + }).sendAndConfirm(umi); + + // After the fix, this should throw NoApprovals + // With the bug, this will pass (no error thrown) + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +/** + * This test is the counterpart - it verifies that UpdateDelegate CAN revoke + * authority on UpdateAuthority-managed plugins. This should always work. + */ +test('it should allow update authority to revoke authority on UpdateAuthority-managed plugins via UpdateDelegate', async (t) => { + const umi = await createUmi(); + // Use separate owner for consistency with other tests + const owner = generateSigner(umi); + const editionAuthority = generateSigner(umi); + + // Create an asset with: + // - owner: separate signer + // - updateAuthority: umi.identity + // - UpdateDelegate plugin (default authority: UpdateAuthority) + // - Edition plugin (default authority: UpdateAuthority - an authority-managed plugin) + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + { + type: 'Edition', + number: 1, + }, + ], + }); + + // Approve a new authority for Edition (UpdateAuthority can do this) + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'Edition' }, + newAuthority: { type: 'Address', address: editionAuthority.publicKey }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { type: 'UpdateAuthority' }, + additionalDelegates: [], + }, + edition: { + authority: { type: 'Address', address: editionAuthority.publicKey }, + number: 1, + }, + }); + + // Revoke authority on Edition using the UpdateAuthority + // This SHOULD succeed because Edition is UpdateAuthority-managed + await revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'Edition' }, + }).sendAndConfirm(umi); + + // Edition authority should be reverted to UpdateAuthority + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { type: 'UpdateAuthority' }, + additionalDelegates: [], + }, + edition: { + authority: { type: 'UpdateAuthority' }, + number: 1, + }, + }); +}); + +/** + * Test the bug with TransferDelegate (another owner-managed plugin) + */ +test('it should NOT allow update authority to revoke authority on TransferDelegate via UpdateDelegate', async (t) => { + const umi = await createUmi(); + // IMPORTANT: Use a separate owner distinct from the update authority (umi.identity) + const owner = generateSigner(umi); + const transferDelegateAuthority = generateSigner(umi); + + // Create an asset with UpdateDelegate and TransferDelegate + // owner is separate from updateAuthority to isolate the UpdateDelegate bug + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + { + type: 'TransferDelegate', + }, + ], + }); + + // Approve a new authority for TransferDelegate (as owner) + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'TransferDelegate' }, + newAuthority: { + type: 'Address', + address: transferDelegateAuthority.publicKey, + }, + authority: owner, // Owner must sign to approve authority on owner-managed plugin + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { type: 'UpdateAuthority' }, + additionalDelegates: [], + }, + transferDelegate: { + authority: { + type: 'Address', + address: transferDelegateAuthority.publicKey, + }, + }, + }); + + // Try to revoke authority on TransferDelegate using the UpdateAuthority + // This SHOULD FAIL because TransferDelegate is owner-managed + const result = revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'TransferDelegate' }, + // Using the default authority (umi.identity = UpdateAuthority, NOT owner) + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +/** + * Test that a separate UpdateDelegate authority (not the UpdateAuthority itself) + * also cannot revoke authority on owner-managed plugins. + * + * This tests the same bug but through a delegated UpdateDelegate authority. + */ +test('it should NOT allow delegated update delegate to revoke authority on owner-managed plugins', async (t) => { + const umi = await createUmi(); + const updateDelegateAuthority = generateSigner(umi); + const freezeDelegateAuthority = generateSigner(umi); + + // Create an asset with: + // 1. UpdateDelegate plugin with a separate delegated authority + // 2. FreezeDelegate plugin + const asset = await createAsset(umi, { + plugins: [ + { + type: 'UpdateDelegate', + additionalDelegates: [], + authority: { + type: 'Address', + address: updateDelegateAuthority.publicKey, + }, + }, + { + type: 'FreezeDelegate', + frozen: false, + }, + ], + }); + + // As owner, approve a new authority for FreezeDelegate + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'FreezeDelegate' }, + newAuthority: { + type: 'Address', + address: freezeDelegateAuthority.publicKey, + }, + }).sendAndConfirm(umi); + + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + updateDelegate: { + authority: { + type: 'Address', + address: updateDelegateAuthority.publicKey, + }, + additionalDelegates: [], + }, + freezeDelegate: { + authority: { + type: 'Address', + address: freezeDelegateAuthority.publicKey, + }, + frozen: false, + }, + }); + + // Try to revoke authority on FreezeDelegate using the delegated UpdateDelegate + // This SHOULD FAIL because FreezeDelegate is owner-managed + const result = revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'FreezeDelegate' }, + authority: updateDelegateAuthority, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { name: 'NoApprovals' }); +}); + +/** + * Positive test: verify that the owner CAN revoke authority on owner-managed plugins. + * + * This is the complement to the negative tests above. While UpdateDelegate/UpdateAuthority + * should NOT be able to revoke authority on owner-managed plugins, the actual owner should + * still be able to do so. Uses a distinct owner (separate from update authority) to isolate + * the owner role. + */ +test('it should allow the owner to revoke authority on owner-managed plugins', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + const freezeDelegateAuthority = generateSigner(umi); + + // Create an asset with FreezeDelegate (owner-managed) and a distinct owner + const asset = await createAsset(umi, { + owner: owner.publicKey, + plugins: [ + { + type: 'FreezeDelegate', + frozen: false, + }, + ], + }); + + // Verify initial state: FreezeDelegate is owner-managed + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + freezeDelegate: { + authority: { type: 'Owner' }, + frozen: false, + }, + }); + + // As the owner, approve a new delegate authority for FreezeDelegate + await approvePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'FreezeDelegate' }, + newAuthority: { + type: 'Address', + address: freezeDelegateAuthority.publicKey, + }, + authority: owner, + }).sendAndConfirm(umi); + + // Verify the FreezeDelegate authority was changed to the delegate + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + freezeDelegate: { + authority: { + type: 'Address', + address: freezeDelegateAuthority.publicKey, + }, + frozen: false, + }, + }); + + // Owner revokes the delegate authority on FreezeDelegate + await revokePluginAuthority(umi, { + asset: asset.publicKey, + plugin: { type: 'FreezeDelegate' }, + authority: owner, + }).sendAndConfirm(umi); + + // FreezeDelegate should revert to owner-managed + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Address', address: umi.identity.publicKey }, + freezeDelegate: { + authority: { type: 'Owner' }, + frozen: false, + }, + }); +}); diff --git a/clients/js/test/plugins/collection/bubblegumV2.test.ts b/clients/js/test/plugins/collection/bubblegumV2.test.ts new file mode 100644 index 00000000..e0cfb787 --- /dev/null +++ b/clients/js/test/plugins/collection/bubblegumV2.test.ts @@ -0,0 +1,390 @@ +import test from 'ava'; +import { generateSigner, PublicKey } from '@metaplex-foundation/umi'; +import { + addCollectionPluginV1, + createPlugin, + removeCollectionPluginV1, + PluginType, + addCollectionPlugin, + ExternalPluginAdapterSchema, +} from '../../../src'; +import { + DEFAULT_COLLECTION, + assertCollection, + createUmi, +} from '../../_setupRaw'; +import { createCollection } from '../../_setupSdk'; + +const MPL_BUBBLEGUM_PROGRAM_ID = + 'BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY' as PublicKey<'BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY'>; + +test('it can create collection with BubblegumV2 plugin', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + bubblegumV2: { + authority: { + type: 'Address', + address: MPL_BUBBLEGUM_PROGRAM_ID, + }, + }, + }); +}); + +test('it cannot add BubblegumV2 to collection after creation', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi); + + const result = addCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'BubblegumV2', + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + bubblegumV2: undefined, + }); +}); + +test('Update Authority cannot remove BubblegumV2 from collection', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + bubblegumV2: { + authority: { + type: 'Address', + address: MPL_BUBBLEGUM_PROGRAM_ID, + }, + }, + }); + + const result = removeCollectionPluginV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.BubblegumV2, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + bubblegumV2: { + authority: { + type: 'Address', + address: MPL_BUBBLEGUM_PROGRAM_ID, + }, + }, + }); +}); + +test('it can create collection with BubblegumV2 plugin and other allow-listed plugins', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + { + type: 'PermanentFreezeDelegate', + frozen: false, + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + bubblegumV2: { + authority: { + type: 'Address', + address: MPL_BUBBLEGUM_PROGRAM_ID, + }, + }, + updateDelegate: { + authority: { + type: 'UpdateAuthority', + }, + additionalDelegates: [], + }, + permanentFreezeDelegate: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); +}); + +test('it cannot create collection with BubblegumV2 plugin and non-allow-listed plugins', async (t) => { + const umi = await createUmi(); + const result = createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + { + type: 'UpdateDelegate', + additionalDelegates: [], + }, + { + type: 'PermanentFreezeDelegate', + frozen: false, + }, + { + type: 'MasterEdition', + maxSupply: 100, + name: 'master', + uri: 'uri master', + }, + ], + }); + + await t.throwsAsync(result, { + name: 'BlockedByBubblegumV2', + }); +}); + +test('it can add allow-listed plugins to collection with BubblegumV2 plugin', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + bubblegumV2: { + authority: { + type: 'Address', + address: MPL_BUBBLEGUM_PROGRAM_ID, + }, + }, + }); + + await addCollectionPlugin(umi, { + collection: collection.publicKey, + plugin: { + type: 'Royalties', + basisPoints: 500, + creators: [ + { + address: umi.identity.publicKey, + percentage: 100, + }, + ], + ruleSet: { + type: 'ProgramDenyList', + addresses: [umi.identity.publicKey], + }, + }, + }).sendAndConfirm(umi); +}); + +test('it cannot add non-allow-listed plugins to collection with BubblegumV2 plugin', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + bubblegumV2: { + authority: { + type: 'Address', + address: MPL_BUBBLEGUM_PROGRAM_ID, + }, + }, + }); + + const result = addCollectionPlugin(umi, { + collection: collection.publicKey, + plugin: { + type: 'AddBlocker', + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); +}); + +test('it cannot create collection with BubblegumV2 plugin and external plugin', async (t) => { + const umi = await createUmi(); + const result = createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + { + type: 'AppData', + dataAuthority: { type: 'UpdateAuthority' }, + schema: ExternalPluginAdapterSchema.Json, + }, + ], + }); + + await t.throwsAsync(result, { + name: 'BlockedByBubblegumV2', + }); +}); + +test('it cannot add external plugin to collection with BubblegumV2 plugin', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + currentSize: 0, + numMinted: 0, + bubblegumV2: { + authority: { + type: 'Address', + address: MPL_BUBBLEGUM_PROGRAM_ID, + }, + }, + }); + + const result = addCollectionPlugin(umi, { + collection: collection.publicKey, + plugin: { + type: 'AppData', + dataAuthority: { type: 'UpdateAuthority' }, + schema: ExternalPluginAdapterSchema.Json, + }, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); +}); + +test('it cannot create collection with BubblegumV2 plugin using wrong authority', async (t) => { + const umi = await createUmi(); + const updateAuthorityResult = createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + authority: { + type: 'UpdateAuthority', + }, + }, + ], + }); + + await t.throwsAsync(updateAuthorityResult, { + name: 'InvalidAuthority', + }); + + const noneResult = createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + authority: { + type: 'None', + }, + }, + ], + }); + + await t.throwsAsync(noneResult, { + name: 'InvalidAuthority', + }); + + const ownerResult = createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + authority: { + type: 'Owner', + }, + }, + ], + }); + + await t.throwsAsync(ownerResult, { + name: 'InvalidAuthority', + }); + + const addressResult = createCollection(umi, { + plugins: [ + { + type: 'BubblegumV2', + authority: { + type: 'Address', + address: generateSigner(umi).publicKey, + }, + }, + ], + }); + + await t.throwsAsync(addressResult, { + name: 'InvalidAuthority', + }); +}); diff --git a/clients/js/test/plugins/collection/permanentFreezeExecute.test.ts b/clients/js/test/plugins/collection/permanentFreezeExecute.test.ts new file mode 100644 index 00000000..ae8022e5 --- /dev/null +++ b/clients/js/test/plugins/collection/permanentFreezeExecute.test.ts @@ -0,0 +1,612 @@ +import { transferSol } from '@metaplex-foundation/mpl-toolbox'; +import { + createNoopSigner, + generateSigner, + publicKey, + sol, +} from '@metaplex-foundation/umi'; +import test from 'ava'; + +import { + addCollectionPluginV1, + create, + createPlugin, + execute, + fetchAssetV1, + findAssetSignerPda, + PluginType, + removeCollectionPluginV1, + transferV1, + updateCollectionPluginV1, +} from '../../../src'; +import { + DEFAULT_COLLECTION, + assertAsset, + assertCollection, + createUmi, + DEFAULT_ASSET, +} from '../../_setupRaw'; +import { createCollection } from '../../_setupSdk'; + +test('it can add PermanentFreezeExecute to collection', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); +}); + +test('it can remove PermanentFreezeExecute from collection when unfrozen', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: false, + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); + + await removeCollectionPluginV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: undefined, + }); +}); + +test('it cannot remove PermanentFreezeExecute from collection when frozen', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + const result = removeCollectionPluginV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); +}); + +test('it cannot add PermanentFreezeExecute to collection after creation', async (t) => { + const umi = await createUmi(); + + const collection = await createCollection(umi); + + const result = addCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: true }, + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(result, { + name: 'InvalidAuthority', + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: undefined, + }); +}); + +test('it can freeze and unfreeze a collection', async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi, { + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: false, + }, + ], + }); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); + + await updateCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: true }, + }), + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + await updateCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + }).sendAndConfirm(umi); + + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); +}); + +test('assets inherit PermanentFreezeExecute plugin from collection and execute is blocked when frozen', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(1)); + + // Create collection with PermanentFreezeExecute plugin frozen + const collection = await createCollection(umi, { + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }); + + // Create asset in the collection + const assetSigner = generateSigner(umi); + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + collection, + name: 'Test Asset', + uri: 'https://example.com/asset', + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, assetSigner.publicKey); + + // Asset should not have its own permanentFreezeExecute plugin (it inherits from collection) + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + permanentFreezeExecute: undefined, // No asset-level plugin + }); + + // Fund the asset signer PDA + const [assetSignerPda] = findAssetSignerPda(umi, { + asset: asset.publicKey, + }); + + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + // Execute should be blocked due to collection plugin + const recipient = generateSigner(umi); + const execResult = execute(umi, { + asset, + payer: owner, + collection, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(execResult, { name: 'InvalidAuthority' }); + + // Unfreeze at collection level should allow execute + await updateCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + }).sendAndConfirm(umi); + + // Now execute should succeed + await execute(umi, { + asset, + payer: owner, + collection, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + // Verify recipient received the SOL + const recipientBalance = await umi.rpc.getBalance(recipient.publicKey); + t.true(recipientBalance.basisPoints >= sol(0.1).basisPoints); +}); + +test('asset-level PermanentFreezeExecute overrides collection-level plugin when unfrozen', async (t) => { + const umi = await createUmi(); + const owner = generateSigner(umi); + await umi.rpc.airdrop(owner.publicKey, sol(1)); + + // Create collection with PermanentFreezeExecute plugin frozen + const collection = await createCollection(umi, { + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }); + + // Create asset in the collection with its own unfrozen PermanentFreezeExecute plugin + const assetSigner = generateSigner(umi); + await create(umi, { + asset: assetSigner, + owner: owner.publicKey, + collection, + name: 'Test Asset', + uri: 'https://example.com/asset', + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: false, + }, + ], + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, assetSigner.publicKey); + + // Asset should have its own permanentFreezeExecute plugin + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: owner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: false, + }, + }); + + // Fund the asset signer PDA + const [assetSignerPda] = findAssetSignerPda(umi, { + asset: asset.publicKey, + }); + + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + // Execute should succeed because asset-level plugin overrides collection (asset plugin is unfrozen) + const recipient = generateSigner(umi); + await execute(umi, { + asset, + payer: owner, + collection, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + // Verify recipient received the SOL + const recipientBalance = await umi.rpc.getBalance(recipient.publicKey); + t.true(recipientBalance.basisPoints >= sol(0.1).basisPoints); +}); + +test('collection PermanentFreezeExecute persists through asset transfer and still blocks execute', async (t) => { + const umi = await createUmi(); + const originalOwner = generateSigner(umi); + const newOwner = generateSigner(umi); + await umi.rpc.airdrop(originalOwner.publicKey, sol(1)); + await umi.rpc.airdrop(newOwner.publicKey, sol(1)); + + // Create collection with PermanentFreezeExecute plugin frozen + const collection = await createCollection(umi, { + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }); + + // Create asset in the collection + const assetSigner = generateSigner(umi); + await create(umi, { + asset: assetSigner, + owner: originalOwner.publicKey, + collection, + name: 'Test Asset', + uri: 'https://example.com/asset', + }).sendAndConfirm(umi); + + const asset = await fetchAssetV1(umi, assetSigner.publicKey); + + // Verify initial state - execute should be blocked + const [assetSignerPda] = findAssetSignerPda(umi, { + asset: asset.publicKey, + }); + + await transferSol(umi, { + source: umi.identity, + destination: publicKey(assetSignerPda), + amount: sol(0.5), + }).sendAndConfirm(umi); + + const recipient1 = generateSigner(umi); + const execResult1 = execute(umi, { + asset, + payer: originalOwner, + collection, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient1.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(execResult1, { name: 'InvalidAuthority' }); + + // Transfer the asset to a new owner + await transferV1(umi, { + asset: asset.publicKey, + newOwner: newOwner.publicKey, + authority: originalOwner, + collection: collection.publicKey, + }).sendAndConfirm(umi); + + // Verify the asset has been transferred + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: newOwner.publicKey, + updateAuthority: { type: 'Collection', address: collection.publicKey }, + permanentFreezeExecute: undefined, // No asset-level plugin + }); + + // Execute should still be blocked for the new owner due to inherited collection plugin + const recipient2 = generateSigner(umi); + const execResult2 = execute(umi, { + asset, + payer: newOwner, + collection, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient2.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + await t.throwsAsync(execResult2, { name: 'InvalidAuthority' }); + + // Verify that the collection plugin state persisted through the asset transfer + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Unfreeze collection plugin and verify execute now works for new owner + await updateCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + }).sendAndConfirm(umi); + + // Execute should now succeed for the new owner + await execute(umi, { + asset, + payer: newOwner, + collection, + instructions: transferSol(umi, { + source: createNoopSigner(publicKey(assetSignerPda)), + destination: recipient2.publicKey, + amount: sol(0.1), + }), + }).sendAndConfirm(umi); + + // Verify recipient received the SOL + const recipientBalance = await umi.rpc.getBalance(recipient2.publicKey); + t.true(recipientBalance.basisPoints >= sol(0.1).basisPoints); +}); + +test('collection owner cannot remove or unfreeze PermanentFreezeExecute plugin', async (t) => { + const umi = await createUmi(); + const collectionOwner = generateSigner(umi); + + // Create collection with PermanentFreezeExecute plugin (frozen) and specific owner + const collection = await createCollection(umi, { + updateAuthority: collectionOwner.publicKey, + plugins: [ + { + type: 'PermanentFreezeExecute', + frozen: true, + }, + ], + }); + + // Verify initial state + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionOwner.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Create a different user who will try to modify the plugin (not the update authority) + const unauthorizedUser = generateSigner(umi); + + // Unauthorized user should not be able to unfreeze the plugin + const unfreezeResult = updateCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + authority: unauthorizedUser, + }).sendAndConfirm(umi); + + await t.throwsAsync(unfreezeResult, { name: 'InvalidAuthority' }); + + // Unauthorized user should not be able to remove the plugin (even when frozen) + const removeResult = removeCollectionPluginV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + authority: unauthorizedUser, + }).sendAndConfirm(umi); + + await t.throwsAsync(removeResult, { name: 'InvalidAuthority' }); + + // Plugin should still be there and frozen + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionOwner.publicKey, + permanentFreezeExecute: { + authority: { + type: 'UpdateAuthority', + }, + frozen: true, + }, + }); + + // Only the collection's update authority should be able to unfreeze + await updateCollectionPluginV1(umi, { + collection: collection.publicKey, + plugin: createPlugin({ + type: 'PermanentFreezeExecute', + data: { frozen: false }, + }), + authority: collectionOwner, // Collection update authority + }).sendAndConfirm(umi); + + // Unauthorized user still cannot remove it even when unfrozen + const removeUnfrozenResult = removeCollectionPluginV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + authority: unauthorizedUser, + }).sendAndConfirm(umi); + + await t.throwsAsync(removeUnfrozenResult, { name: 'InvalidAuthority' }); + + // But collection update authority can remove it when unfrozen + await removeCollectionPluginV1(umi, { + collection: collection.publicKey, + pluginType: PluginType.PermanentFreezeExecute, + authority: collectionOwner, + }).sendAndConfirm(umi); + + // Verify plugin is removed + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: collectionOwner.publicKey, + permanentFreezeExecute: undefined, + }); +}); diff --git a/clients/js/test/sdkv1.test.ts b/clients/js/test/sdkv1.test.ts index b9c50e19..c606e46d 100644 --- a/clients/js/test/sdkv1.test.ts +++ b/clients/js/test/sdkv1.test.ts @@ -1,28 +1,23 @@ import { assertAccountExists, generateSigner } from '@metaplex-foundation/umi'; import test from 'ava'; import { - AssetAddablePluginAuthorityPairArgsV2, + addCollectionPlugin, addPlugin, + AssetAddablePluginAuthorityPairArgsV2, + AssetAllPluginArgsV2, burn, + CollectionAddablePluginAuthorityPairArgsV2, + CollectionAllPluginArgsV2, + ExternalPluginAdapterSchema, Key, - AssetAllPluginArgsV2, + removeCollectionPlugin, removePlugin, transfer, update, updateCollection, updateCollectionPlugin, updatePlugin, - CollectionAllPluginArgsV2, - CollectionAddablePluginAuthorityPairArgsV2, - addCollectionPlugin, - removeCollectionPlugin, - ExternalPluginAdapterSchema, } from '../src'; -import { - createAsset, - createAssetWithCollection, - createCollection, -} from './_setupSdk'; import { assertAsset, assertCollection, @@ -30,6 +25,15 @@ import { DEFAULT_ASSET, DEFAULT_COLLECTION, } from './_setupRaw'; +import { + createAsset, + createAssetWithCollection, + createCollection, +} from './_setupSdk'; + +// Heavy plugin manipulation tests can exhaust the validator when run in parallel. +// Use AVA's serial mode for these selected tests to prevent block height expiry. +const serial = test.serial; test('it can create asset and collection with all update auth managed party plugins', async (t) => { const umi = await createUmi(); @@ -409,133 +413,134 @@ test('it can create all owner and update auth managed party plugins to asset', a }); }); -test('it can add and remove all owner and update auth managed party plugins to asset', async (t) => { - const umi = await createUmi(); - const asset = await createAsset(umi); +serial( + 'it can add and remove all owner and update auth managed party plugins to asset', + async (t) => { + const umi = await createUmi(); + const asset = await createAsset(umi); - const plugins: AssetAddablePluginAuthorityPairArgsV2[] = [ - { - type: 'Royalties', - basisPoints: 500, - creators: [ - { + const plugins: AssetAddablePluginAuthorityPairArgsV2[] = [ + { + type: 'Royalties', + basisPoints: 500, + creators: [ + { + address: umi.identity.publicKey, + percentage: 100, + }, + ], + ruleSet: { + type: 'ProgramDenyList', + addresses: [umi.identity.publicKey], + }, + authority: { + type: 'Address', address: umi.identity.publicKey, - percentage: 100, }, - ], - ruleSet: { - type: 'ProgramDenyList', - addresses: [umi.identity.publicKey], }, - authority: { - type: 'Address', - address: umi.identity.publicKey, + { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], }, - }, - { - type: 'Attributes', - attributeList: [ - { - key: '123', - value: '456', + { + type: 'FreezeDelegate', + frozen: false, + }, + { + type: 'BurnDelegate', + }, + { + type: 'TransferDelegate', + authority: { + type: 'UpdateAuthority', }, - ], - }, - { - type: 'FreezeDelegate', - frozen: false, - }, - { - type: 'BurnDelegate', - }, - { - type: 'TransferDelegate', - authority: { - type: 'UpdateAuthority', }, - }, - ]; + ]; - await Promise.all( - plugins.map(async (plugin) => - addPlugin(umi, { + for (const plugin of plugins) { + await addPlugin(umi, { asset: asset.publicKey, plugin, - }).sendAndConfirm(umi) - ) - ); + }).sendAndConfirm(umi); + } - await assertAsset(t, umi, { - asset: asset.publicKey, - owner: umi.identity.publicKey, - royalties: { - basisPoints: 500, - creators: [ - { + await assertAsset(t, umi, { + asset: asset.publicKey, + owner: umi.identity.publicKey, + royalties: { + basisPoints: 500, + creators: [ + { + address: umi.identity.publicKey, + percentage: 100, + }, + ], + ruleSet: { + type: 'ProgramDenyList', + addresses: [umi.identity.publicKey], + }, + authority: { + type: 'Address', address: umi.identity.publicKey, - percentage: 100, }, - ], - ruleSet: { - type: 'ProgramDenyList', - addresses: [umi.identity.publicKey], }, - authority: { - type: 'Address', - address: umi.identity.publicKey, - }, - }, - attributes: { - attributeList: [ - { - key: '123', - value: '456', + attributes: { + attributeList: [ + { + key: '123', + value: '456', + }, + ], + authority: { + type: 'UpdateAuthority', }, - ], - authority: { - type: 'UpdateAuthority', }, - }, - freezeDelegate: { - frozen: false, - authority: { - type: 'Owner', + freezeDelegate: { + frozen: false, + authority: { + type: 'Owner', + }, }, - }, - burnDelegate: { - authority: { - type: 'Owner', + burnDelegate: { + authority: { + type: 'Owner', + }, }, - }, - transferDelegate: { - authority: { - type: 'UpdateAuthority', + transferDelegate: { + authority: { + type: 'UpdateAuthority', + }, }, - }, - }); + }); - await Promise.all( - plugins.map(async (plugin) => - removePlugin(umi, { - asset: asset.publicKey, - plugin, - }).sendAndConfirm(umi) - ) - ); + for (const plugin of plugins) { + if (plugin.type !== 'Groups') { + await removePlugin(umi, { + asset: asset.publicKey, + plugin: { type: plugin.type }, + }).sendAndConfirm(umi); + } + } - await assertAsset(t, umi, { - ...DEFAULT_ASSET, - asset: asset.publicKey, - owner: umi.identity.publicKey, - attributes: undefined, - royalties: undefined, - freezeDelegate: undefined, - burnDelegate: undefined, - transferDelegate: undefined, - }); -}); + await assertAsset(t, umi, { + ...DEFAULT_ASSET, + asset: asset.publicKey, + owner: umi.identity.publicKey, + attributes: undefined, + royalties: undefined, + freezeDelegate: undefined, + burnDelegate: undefined, + transferDelegate: undefined, + }); + } +); -test('it can update all updatable plugins on asset', async (t) => { +serial('it can update all updatable plugins on asset', async (t) => { const umi = await createUmi(); const asset = await createAsset(umi, { plugins: [ @@ -615,14 +620,12 @@ test('it can update all updatable plugins on asset', async (t) => { }, ]; - await Promise.all( - updates.map(async (plugin) => - updatePlugin(umi, { - asset: asset.publicKey, - plugin, - }).sendAndConfirm(umi) - ) - ); + for (const plugin of updates) { + await updatePlugin(umi, { + asset: asset.publicKey, + plugin, + }).sendAndConfirm(umi); + } await assertAsset(t, umi, { asset: asset.publicKey, @@ -675,7 +678,7 @@ test('it can update all updatable plugins on asset', async (t) => { }); }); -test('it can update all updatable plugins on collection', async (t) => { +serial('it can update all updatable plugins on collection', async (t) => { const umi = await createUmi(); const collection = await createCollection(umi, { plugins: [ @@ -751,14 +754,12 @@ test('it can update all updatable plugins on collection', async (t) => { }, ]; - await Promise.all( - updates.map(async (plugin) => - updateCollectionPlugin(umi, { - collection: collection.publicKey, - plugin, - }).sendAndConfirm(umi) - ) - ); + for (const plugin of updates) { + await updateCollectionPlugin(umi, { + collection: collection.publicKey, + plugin, + }).sendAndConfirm(umi); + } await assertCollection(t, umi, { collection: collection.publicKey, @@ -806,99 +807,100 @@ test('it can update all updatable plugins on collection', async (t) => { }); }); -test('it can add and remove all update auth managed party plugins to collection', async (t) => { - const umi = await createUmi(); - const collection = await createCollection(umi); +serial( + 'it can add and remove all update auth managed party plugins to collection', + async (t) => { + const umi = await createUmi(); + const collection = await createCollection(umi); - const plugins: CollectionAddablePluginAuthorityPairArgsV2[] = [ - { - type: 'Royalties', - basisPoints: 500, - creators: [ - { + const plugins: CollectionAddablePluginAuthorityPairArgsV2[] = [ + { + type: 'Royalties', + basisPoints: 500, + creators: [ + { + address: umi.identity.publicKey, + percentage: 100, + }, + ], + ruleSet: { + type: 'ProgramDenyList', + addresses: [umi.identity.publicKey], + }, + authority: { + type: 'Address', address: umi.identity.publicKey, - percentage: 100, }, - ], - ruleSet: { - type: 'ProgramDenyList', - addresses: [umi.identity.publicKey], }, - authority: { - type: 'Address', - address: umi.identity.publicKey, + { + type: 'Attributes', + attributeList: [ + { + key: '123', + value: '456', + }, + ], }, - }, - { - type: 'Attributes', - attributeList: [ - { - key: '123', - value: '456', - }, - ], - }, - ]; + ]; - await Promise.all( - plugins.map(async (plugin) => - addCollectionPlugin(umi, { + for (const plugin of plugins) { + await addCollectionPlugin(umi, { collection: collection.publicKey, plugin, - }).sendAndConfirm(umi) - ) - ); + }).sendAndConfirm(umi); + } - await assertCollection(t, umi, { - collection: collection.publicKey, - updateAuthority: umi.identity.publicKey, - royalties: { - basisPoints: 500, - creators: [ - { + await assertCollection(t, umi, { + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + royalties: { + basisPoints: 500, + creators: [ + { + address: umi.identity.publicKey, + percentage: 100, + }, + ], + ruleSet: { + type: 'ProgramDenyList', + addresses: [umi.identity.publicKey], + }, + authority: { + type: 'Address', address: umi.identity.publicKey, - percentage: 100, }, - ], - ruleSet: { - type: 'ProgramDenyList', - addresses: [umi.identity.publicKey], }, - authority: { - type: 'Address', - address: umi.identity.publicKey, - }, - }, - attributes: { - attributeList: [ - { - key: '123', - value: '456', + attributes: { + attributeList: [ + { + key: '123', + value: '456', + }, + ], + authority: { + type: 'UpdateAuthority', }, - ], - authority: { - type: 'UpdateAuthority', }, - }, - }); + }); - await Promise.all( - plugins.map(async (plugin) => - removeCollectionPlugin(umi, { - collection: collection.publicKey, - plugin, - }).sendAndConfirm(umi) - ) - ); + for (const plugin of plugins) { + if (plugin.type !== 'Groups') { + await removeCollectionPlugin(umi, { + collection: collection.publicKey, + plugin: { type: plugin.type }, + }).sendAndConfirm(umi); + } + } - await assertCollection(t, umi, { - ...DEFAULT_COLLECTION, - collection: collection.publicKey, - updateAuthority: umi.identity.publicKey, - attributes: undefined, - royalties: undefined, - }); -}); + await assertCollection(t, umi, { + ...DEFAULT_COLLECTION, + collection: collection.publicKey, + updateAuthority: umi.identity.publicKey, + attributes: undefined, + royalties: undefined, + }); + } +); test('it can transfer asset', async (t) => { const umi = await createUmi(); diff --git a/clients/js/test/updateGroupAuthority.test.ts b/clients/js/test/updateGroupAuthority.test.ts new file mode 100644 index 00000000..96abab7f --- /dev/null +++ b/clients/js/test/updateGroupAuthority.test.ts @@ -0,0 +1,88 @@ +import { generateSigner } from '@metaplex-foundation/umi'; +import test from 'ava'; +import { updateGroup } from '../src'; +import { + assertGroup, + createGroup, + createUmi, + DEFAULT_GROUP, +} from './_setupRaw'; + +// ----------------------------------------------------------------------------- +// Update Authority Transfer +// ----------------------------------------------------------------------------- + +test("it can transfer a group's update authority", async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi); + + const newAuthority = generateSigner(umi); + + // 1. Transfer the update authority to the new signer. + await updateGroup(umi, { + group: group.publicKey, + payer: umi.identity, + authority: umi.identity, + newUpdateAuthority: newAuthority.publicKey, + newName: null, + newUri: null, + }).sendAndConfirm(umi); + + await assertGroup(t, umi, { + ...DEFAULT_GROUP, + group: group.publicKey, + updateAuthority: newAuthority.publicKey, + }); + + // 2. The new authority updates the group's name. + const UPDATED_NAME = 'Updated Group Name'; + + await updateGroup(umi, { + group: group.publicKey, + payer: umi.identity, + authority: newAuthority, + newName: UPDATED_NAME, + newUri: null, + }).sendAndConfirm(umi); + + await assertGroup(t, umi, { + group: group.publicKey, + name: UPDATED_NAME, + updateAuthority: newAuthority.publicKey, + }); + + // 3. Old authority attempting further updates should fail. + const error = await t.throwsAsync( + updateGroup(umi, { + group: group.publicKey, + payer: umi.identity, + authority: umi.identity, + newName: 'Should Fail', + newUri: null, + }).sendAndConfirm(umi) + ); + t.is(error?.name, 'InvalidAuthority'); +}); + +test('it can updateGroup with both name and URI simultaneously', async (t) => { + const umi = await createUmi(); + const group = await createGroup(umi, { + name: 'original', + uri: 'https://original.com', + }); + + await updateGroup(umi, { + group: group.publicKey, + payer: umi.identity, + authority: umi.identity, + newName: 'updated', + newUri: 'https://updated.com', + }).sendAndConfirm(umi); + + await assertGroup(t, umi, { + group: group.publicKey, + updateAuthority: umi.identity.publicKey, + name: 'updated', + uri: 'https://updated.com', + }); +}); diff --git a/clients/rust/Cargo.toml b/clients/rust/Cargo.toml index da459691..fc3d8e5e 100644 --- a/clients/rust/Cargo.toml +++ b/clients/rust/Cargo.toml @@ -5,33 +5,38 @@ license-file = "../../LICENSE" name = "mpl-core" readme = "README.md" repository = "https://github.com/metaplex-foundation/mpl-core" -version = "0.8.1-beta.1" +version = "0.11.1" [lib] crate-type = ["cdylib", "lib"] [features] +default = ["borsh-v1"] anchor = ["dep:anchor-lang", "kaigan/anchor"] serde = ["dep:serde", "dep:serde_with"] test-sbf = [] +borsh-v1 = ["kaigan/borsh-v1"] [dependencies] -anchor-lang = { version = "0.30.0", optional = true } +anchor-lang = { version = "0.31.1", optional = true } base64 = "0.22.0" -borsh = "^0.10" +borsh = { version = "1.5", features = ["derive"] } modular-bitfield = "0.11.2" -num-derive = "^0.3" +num-derive = "^0.4" num-traits = "^0.2" rmp-serde = "1.0" serde = { version = "^1.0", features = ["derive"], optional = true } serde_json = "1.0" serde_with = { version = "^3.0", optional = true } -solana-program = "> 1.14" +solana-program = "3.0.0" +solana-program-error = "3.0.0" thiserror = "^1.0" -kaigan = { version = "0.2.6", features = ["serde"], optional = false } +kaigan = { version = "0.5.0", features = ["serde"], optional = false } + [dev-dependencies] assert_matches = "1.5.0" -solana-program-test = "> 1.14" -solana-sdk = "> 1.14" +solana-program-test = "3.0.0" +solana-sdk = "3.0.0" +solana-system-interface = { version = "2.0.0", features = ["bincode"] } diff --git a/clients/rust/src/generated/accounts/group_v1.rs b/clients/rust/src/generated/accounts/group_v1.rs new file mode 100644 index 00000000..62c42828 --- /dev/null +++ b/clients/rust/src/generated/accounts/group_v1.rs @@ -0,0 +1,67 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::Key; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct GroupV1 { + pub key: Key, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub update_authority: Pubkey, + pub name: String, + pub uri: String, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::>") + )] + pub collections: Vec, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::>") + )] + pub groups: Vec, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::>") + )] + pub parent_groups: Vec, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::>") + )] + pub assets: Vec, +} + +impl GroupV1 { + #[inline(always)] + pub fn from_bytes(data: &[u8]) -> Result { + let mut data = data; + Self::deserialize(&mut data) + } +} + +impl<'a> TryFrom<&solana_program::account_info::AccountInfo<'a>> for GroupV1 { + type Error = std::io::Error; + + fn try_from( + account_info: &solana_program::account_info::AccountInfo<'a>, + ) -> Result { + let mut data: &[u8] = &(*account_info.data).borrow(); + Self::deserialize(&mut data) + } +} diff --git a/clients/rust/src/generated/accounts/mod.rs b/clients/rust/src/generated/accounts/mod.rs index 27923350..9c543a2e 100644 --- a/clients/rust/src/generated/accounts/mod.rs +++ b/clients/rust/src/generated/accounts/mod.rs @@ -8,6 +8,7 @@ pub(crate) mod r#asset_signer; pub(crate) mod r#base_asset_v1; pub(crate) mod r#base_collection_v1; +pub(crate) mod r#group_v1; pub(crate) mod r#hashed_asset_v1; pub(crate) mod r#plugin_header_v1; pub(crate) mod r#plugin_registry_v1; @@ -15,6 +16,7 @@ pub(crate) mod r#plugin_registry_v1; pub use self::r#asset_signer::*; pub use self::r#base_asset_v1::*; pub use self::r#base_collection_v1::*; +pub use self::r#group_v1::*; pub use self::r#hashed_asset_v1::*; pub use self::r#plugin_header_v1::*; pub use self::r#plugin_registry_v1::*; diff --git a/clients/rust/src/generated/errors/mpl_core.rs b/clients/rust/src/generated/errors/mpl_core.rs index be395f5d..8aecdf2e 100644 --- a/clients/rust/src/generated/errors/mpl_core.rs +++ b/clients/rust/src/generated/errors/mpl_core.rs @@ -6,6 +6,7 @@ //! use num_derive::FromPrimitive; +use solana_program_error::{ProgramError, ToStr}; use thiserror::Error; #[derive(Clone, Debug, Eq, Error, FromPrimitive, PartialEq)] @@ -160,13 +161,198 @@ pub enum MplCoreError { /// 49 (0x31) - Invalid Signing PDA for Asset or Collection Execute #[error("Invalid Signing PDA for Asset or Collection Execute")] InvalidExecutePda, - /// 50 (0x32) - Plugin is not allowed to be added to an Asset + /// 50 (0x32) - Bubblegum V2 Plugin limits other plugins + #[error("Bubblegum V2 Plugin limits other plugins")] + BlockedByBubblegumV2, + /// 51 (0x33) - Agent Identity Program must sign + #[error("Agent Identity Program must sign")] + AgentIdentityMustSign, + /// 52 (0x34) - Group must be empty to be closed + #[error("Group must be empty to be closed")] + GroupMustBeEmpty, + /// 53 (0x35) - Duplicate entry provided when adding relationships to a group + #[error("Duplicate entry provided when adding relationships to a group")] + DuplicateEntry, + /// 54 (0x36) - Group vector is at maximum capacity + #[error("Group vector is at maximum capacity")] + GroupVectorFull, + /// 55 (0x37) - Group nesting depth exceeded + #[error("Group nesting depth exceeded")] + GroupNestingDepthExceeded, + /// 56 (0x38) - Bidirectional group relationship is inconsistent + #[error("Bidirectional group relationship is inconsistent")] + InconsistentGroupRelationship, + /// 57 (0x39) - Plugin is not allowed to be added to an Asset #[error("Plugin is not allowed to be added to an Asset")] PluginNotAllowedOnAsset, } -impl solana_program::program_error::PrintProgramError for MplCoreError { - fn print(&self) { - solana_program::msg!(&self.to_string()); +impl From for ProgramError { + fn from(e: MplCoreError) -> Self { + ProgramError::Custom(e as u32) + } +} + +impl TryFrom for MplCoreError { + type Error = ProgramError; + fn try_from(error: u32) -> Result { + match error { + 0 => Ok(MplCoreError::InvalidSystemProgram), + 1 => Ok(MplCoreError::DeserializationError), + 2 => Ok(MplCoreError::SerializationError), + 3 => Ok(MplCoreError::PluginsNotInitialized), + 4 => Ok(MplCoreError::PluginNotFound), + 5 => Ok(MplCoreError::NumericalOverflow), + 6 => Ok(MplCoreError::IncorrectAccount), + 7 => Ok(MplCoreError::IncorrectAssetHash), + 8 => Ok(MplCoreError::InvalidPlugin), + 9 => Ok(MplCoreError::InvalidAuthority), + 10 => Ok(MplCoreError::AssetIsFrozen), + 11 => Ok(MplCoreError::MissingCompressionProof), + 12 => Ok(MplCoreError::CannotMigrateMasterWithSupply), + 13 => Ok(MplCoreError::CannotMigratePrints), + 14 => Ok(MplCoreError::CannotBurnCollection), + 15 => Ok(MplCoreError::PluginAlreadyExists), + 16 => Ok(MplCoreError::NumericalOverflowError), + 17 => Ok(MplCoreError::AlreadyCompressed), + 18 => Ok(MplCoreError::AlreadyDecompressed), + 19 => Ok(MplCoreError::InvalidCollection), + 20 => Ok(MplCoreError::MissingUpdateAuthority), + 21 => Ok(MplCoreError::MissingNewOwner), + 22 => Ok(MplCoreError::MissingSystemProgram), + 23 => Ok(MplCoreError::NotAvailable), + 24 => Ok(MplCoreError::InvalidAsset), + 25 => Ok(MplCoreError::MissingCollection), + 26 => Ok(MplCoreError::NoApprovals), + 27 => Ok(MplCoreError::CannotRedelegate), + 28 => Ok(MplCoreError::InvalidPluginSetting), + 29 => Ok(MplCoreError::ConflictingAuthority), + 30 => Ok(MplCoreError::InvalidLogWrapperProgram), + 31 => Ok(MplCoreError::ExternalPluginAdapterNotFound), + 32 => Ok(MplCoreError::ExternalPluginAdapterAlreadyExists), + 33 => Ok(MplCoreError::MissingAsset), + 34 => Ok(MplCoreError::MissingExternalPluginAdapterAccount), + 35 => Ok(MplCoreError::OracleCanRejectOnly), + 36 => Ok(MplCoreError::RequiresLifecycleCheck), + 37 => Ok(MplCoreError::DuplicateLifecycleChecks), + 38 => Ok(MplCoreError::InvalidOracleAccountData), + 39 => Ok(MplCoreError::UninitializedOracleAccount), + 40 => Ok(MplCoreError::MissingSigner), + 41 => Ok(MplCoreError::InvalidPluginOperation), + 42 => Ok(MplCoreError::CollectionMustBeEmpty), + 43 => Ok(MplCoreError::TwoDataSources), + 44 => Ok(MplCoreError::UnsupportedOperation), + 45 => Ok(MplCoreError::NoDataSources), + 46 => Ok(MplCoreError::InvalidPluginAdapterTarget), + 47 => Ok(MplCoreError::CannotAddDataSection), + 48 => Ok(MplCoreError::PermanentDelegatesPreventMove), + 49 => Ok(MplCoreError::InvalidExecutePda), + 50 => Ok(MplCoreError::BlockedByBubblegumV2), + 51 => Ok(MplCoreError::AgentIdentityMustSign), + 52 => Ok(MplCoreError::GroupMustBeEmpty), + 53 => Ok(MplCoreError::DuplicateEntry), + 54 => Ok(MplCoreError::GroupVectorFull), + 55 => Ok(MplCoreError::GroupNestingDepthExceeded), + 56 => Ok(MplCoreError::InconsistentGroupRelationship), + 57 => Ok(MplCoreError::PluginNotAllowedOnAsset), + _ => Err(ProgramError::InvalidArgument), + } + } +} + +impl ToStr for MplCoreError { + fn to_str(&self) -> &'static str { + match self { + MplCoreError::InvalidSystemProgram => "Invalid System Program", + MplCoreError::DeserializationError => "Error deserializing account", + MplCoreError::SerializationError => "Error serializing account", + MplCoreError::PluginsNotInitialized => "Plugins not initialized", + MplCoreError::PluginNotFound => "Plugin not found", + MplCoreError::NumericalOverflow => "Numerical Overflow", + MplCoreError::IncorrectAccount => "Incorrect account", + MplCoreError::IncorrectAssetHash => "Incorrect asset hash", + MplCoreError::InvalidPlugin => "Invalid Plugin", + MplCoreError::InvalidAuthority => "Invalid Authority", + MplCoreError::AssetIsFrozen => "Cannot transfer a frozen asset", + MplCoreError::MissingCompressionProof => "Missing compression proof", + MplCoreError::CannotMigrateMasterWithSupply => { + "Cannot migrate a master edition used for prints" + } + MplCoreError::CannotMigratePrints => "Cannot migrate a print edition", + MplCoreError::CannotBurnCollection => "Cannot burn a collection NFT", + MplCoreError::PluginAlreadyExists => "Plugin already exists", + MplCoreError::NumericalOverflowError => "Numerical overflow", + MplCoreError::AlreadyCompressed => "Already compressed account", + MplCoreError::AlreadyDecompressed => "Already decompressed account", + MplCoreError::InvalidCollection => "Invalid Collection passed in", + MplCoreError::MissingUpdateAuthority => "Missing update authority", + MplCoreError::MissingNewOwner => "Missing new owner", + MplCoreError::MissingSystemProgram => "Missing system program", + MplCoreError::NotAvailable => "Feature not available", + MplCoreError::InvalidAsset => "Invalid Asset passed in", + MplCoreError::MissingCollection => "Missing collection", + MplCoreError::NoApprovals => { + "Neither the asset or any plugins have approved this operation" + } + MplCoreError::CannotRedelegate => { + "Plugin Manager cannot redelegate a delegated plugin without revoking first" + } + MplCoreError::InvalidPluginSetting => "Invalid setting for plugin", + MplCoreError::ConflictingAuthority => { + "Cannot specify both an update authority and collection on an asset" + } + MplCoreError::InvalidLogWrapperProgram => "Invalid Log Wrapper Program", + MplCoreError::ExternalPluginAdapterNotFound => "External Plugin Adapter not found", + MplCoreError::ExternalPluginAdapterAlreadyExists => { + "External Plugin Adapter already exists" + } + MplCoreError::MissingAsset => "Missing asset needed for extra account PDA derivation", + MplCoreError::MissingExternalPluginAdapterAccount => { + "Missing account needed for external plugin adapter" + } + MplCoreError::OracleCanRejectOnly => { + "Oracle external plugin adapter can only be configured to reject" + } + MplCoreError::RequiresLifecycleCheck => { + "External plugin adapter must have at least one lifecycle check" + } + MplCoreError::DuplicateLifecycleChecks => { + "Duplicate lifecycle checks were provided for external plugin adapter " + } + MplCoreError::InvalidOracleAccountData => "Could not read from oracle account", + MplCoreError::UninitializedOracleAccount => "Oracle account is uninitialized", + MplCoreError::MissingSigner => "Missing required signer for operation", + MplCoreError::InvalidPluginOperation => "Invalid plugin operation", + MplCoreError::CollectionMustBeEmpty => "Collection must be empty to be burned", + MplCoreError::TwoDataSources => "Two data sources provided, only one is allowed", + MplCoreError::UnsupportedOperation => "External Plugin does not support this operation", + MplCoreError::NoDataSources => "No data sources provided, one is required", + MplCoreError::InvalidPluginAdapterTarget => { + "This plugin adapter cannot be added to an Asset" + } + MplCoreError::CannotAddDataSection => { + "Cannot add a Data Section without a linked external plugin" + } + MplCoreError::PermanentDelegatesPreventMove => { + "Cannot move asset to collection with permanent delegates" + } + MplCoreError::InvalidExecutePda => { + "Invalid Signing PDA for Asset or Collection Execute" + } + MplCoreError::BlockedByBubblegumV2 => "Bubblegum V2 Plugin limits other plugins", + MplCoreError::AgentIdentityMustSign => "Agent Identity Program must sign", + MplCoreError::GroupMustBeEmpty => "Group must be empty to be closed", + MplCoreError::DuplicateEntry => { + "Duplicate entry provided when adding relationships to a group" + } + MplCoreError::GroupVectorFull => "Group vector is at maximum capacity", + MplCoreError::GroupNestingDepthExceeded => "Group nesting depth exceeded", + MplCoreError::InconsistentGroupRelationship => { + "Bidirectional group relationship is inconsistent" + } + MplCoreError::PluginNotAllowedOnAsset => { + "Plugin is not allowed to be added to an Asset" + } + } } } diff --git a/clients/rust/src/generated/instructions/add_assets_to_group_v1.rs b/clients/rust/src/generated/instructions/add_assets_to_group_v1.rs new file mode 100644 index 00000000..2adbb443 --- /dev/null +++ b/clients/rust/src/generated/instructions/add_assets_to_group_v1.rs @@ -0,0 +1,417 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct AddAssetsToGroupV1 { + /// The address of the group to modify + pub group: solana_program::pubkey::Pubkey, + /// The account paying for storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The group update authority and asset update authority or delegate + pub authority: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl AddAssetsToGroupV1 { + pub fn instruction(&self) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.group, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = borsh::to_vec(&(AddAssetsToGroupV1InstructionData::new())).unwrap(); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct AddAssetsToGroupV1InstructionData { + discriminator: u8, +} + +impl AddAssetsToGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 35 } + } +} + +/// Instruction builder for `AddAssetsToGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct AddAssetsToGroupV1Builder { + group: Option, + payer: Option, + authority: Option, + system_program: Option, + __remaining_accounts: Vec, +} + +impl AddAssetsToGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: solana_program::pubkey::Pubkey) -> &mut Self { + self.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and asset update authority or delegate + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = AddAssetsToGroupV1 { + group: self.group.expect("group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `add_assets_to_group_v1` CPI accounts. +pub struct AddAssetsToGroupV1CpiAccounts<'a, 'b> { + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and asset update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `add_assets_to_group_v1` CPI instruction. +pub struct AddAssetsToGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and asset update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +impl<'a, 'b> AddAssetsToGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: AddAssetsToGroupV1CpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + group: accounts.group, + payer: accounts.payer, + authority: accounts.authority, + system_program: accounts.system_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let data = borsh::to_vec(&(AddAssetsToGroupV1InstructionData::new())).unwrap(); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `AddAssetsToGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[]` system_program +pub struct AddAssetsToGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> AddAssetsToGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(AddAssetsToGroupV1CpiBuilderInstruction { + __program: program, + group: None, + payer: None, + authority: None, + system_program: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and asset update authority or delegate + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let instruction = AddAssetsToGroupV1Cpi { + __program: self.instruction.__program, + + group: self.instruction.group.expect("group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct AddAssetsToGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/add_collection_external_plugin_adapter_v1.rs b/clients/rust/src/generated/instructions/add_collection_external_plugin_adapter_v1.rs index 117d693c..9a32e290 100644 --- a/clients/rust/src/generated/instructions/add_collection_external_plugin_adapter_v1.rs +++ b/clients/rust/src/generated/instructions/add_collection_external_plugin_adapter_v1.rs @@ -72,10 +72,9 @@ impl AddCollectionExternalPluginAdapterV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = AddCollectionExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(AddCollectionExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -327,14 +326,13 @@ impl<'a, 'b> AddCollectionExternalPluginAdapterV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = AddCollectionExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(AddCollectionExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/add_collection_plugin_v1.rs b/clients/rust/src/generated/instructions/add_collection_plugin_v1.rs index bc2ac73b..c3252181 100644 --- a/clients/rust/src/generated/instructions/add_collection_plugin_v1.rs +++ b/clients/rust/src/generated/instructions/add_collection_plugin_v1.rs @@ -73,10 +73,8 @@ impl AddCollectionPluginV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = AddCollectionPluginV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(AddCollectionPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -337,14 +335,12 @@ impl<'a, 'b> AddCollectionPluginV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = AddCollectionPluginV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(AddCollectionPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/add_collections_to_group_v1.rs b/clients/rust/src/generated/instructions/add_collections_to_group_v1.rs new file mode 100644 index 00000000..7d483d1f --- /dev/null +++ b/clients/rust/src/generated/instructions/add_collections_to_group_v1.rs @@ -0,0 +1,417 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct AddCollectionsToGroupV1 { + /// The address of the group to modify + pub group: solana_program::pubkey::Pubkey, + /// The account paying for storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The group update authority and collection update authority or delegate + pub authority: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl AddCollectionsToGroupV1 { + pub fn instruction(&self) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.group, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let data = borsh::to_vec(&(AddCollectionsToGroupV1InstructionData::new())).unwrap(); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct AddCollectionsToGroupV1InstructionData { + discriminator: u8, +} + +impl AddCollectionsToGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 33 } + } +} + +/// Instruction builder for `AddCollectionsToGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct AddCollectionsToGroupV1Builder { + group: Option, + payer: Option, + authority: Option, + system_program: Option, + __remaining_accounts: Vec, +} + +impl AddCollectionsToGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: solana_program::pubkey::Pubkey) -> &mut Self { + self.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and collection update authority or delegate + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = AddCollectionsToGroupV1 { + group: self.group.expect("group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `add_collections_to_group_v1` CPI accounts. +pub struct AddCollectionsToGroupV1CpiAccounts<'a, 'b> { + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and collection update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `add_collections_to_group_v1` CPI instruction. +pub struct AddCollectionsToGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and collection update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +impl<'a, 'b> AddCollectionsToGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: AddCollectionsToGroupV1CpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + group: accounts.group, + payer: accounts.payer, + authority: accounts.authority, + system_program: accounts.system_program, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let data = borsh::to_vec(&(AddCollectionsToGroupV1InstructionData::new())).unwrap(); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `AddCollectionsToGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[]` system_program +pub struct AddCollectionsToGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> AddCollectionsToGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(AddCollectionsToGroupV1CpiBuilderInstruction { + __program: program, + group: None, + payer: None, + authority: None, + system_program: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and collection update authority or delegate + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let instruction = AddCollectionsToGroupV1Cpi { + __program: self.instruction.__program, + + group: self.instruction.group.expect("group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct AddCollectionsToGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/add_external_plugin_adapter_v1.rs b/clients/rust/src/generated/instructions/add_external_plugin_adapter_v1.rs index 58f773a9..f86def13 100644 --- a/clients/rust/src/generated/instructions/add_external_plugin_adapter_v1.rs +++ b/clients/rust/src/generated/instructions/add_external_plugin_adapter_v1.rs @@ -83,10 +83,8 @@ impl AddExternalPluginAdapterV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = AddExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(AddExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -364,14 +362,12 @@ impl<'a, 'b> AddExternalPluginAdapterV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = AddExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(AddExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/add_groups_to_group_v1.rs b/clients/rust/src/generated/instructions/add_groups_to_group_v1.rs new file mode 100644 index 00000000..0366ea4c --- /dev/null +++ b/clients/rust/src/generated/instructions/add_groups_to_group_v1.rs @@ -0,0 +1,465 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +/// Accounts. +pub struct AddGroupsToGroupV1 { + /// The address of the parent group to modify + pub parent_group: solana_program::pubkey::Pubkey, + /// The account paying for storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The update authority of the parent and child groups + pub authority: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl AddGroupsToGroupV1 { + pub fn instruction( + &self, + args: AddGroupsToGroupV1InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: AddGroupsToGroupV1InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.parent_group, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = borsh::to_vec(&(AddGroupsToGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct AddGroupsToGroupV1InstructionData { + discriminator: u8, +} + +impl AddGroupsToGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 37 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AddGroupsToGroupV1InstructionArgs { + pub groups: Vec, +} + +/// Instruction builder for `AddGroupsToGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` parent_group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct AddGroupsToGroupV1Builder { + parent_group: Option, + payer: Option, + authority: Option, + system_program: Option, + groups: Option>, + __remaining_accounts: Vec, +} + +impl AddGroupsToGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the parent group to modify + #[inline(always)] + pub fn parent_group(&mut self, parent_group: solana_program::pubkey::Pubkey) -> &mut Self { + self.parent_group = Some(parent_group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the parent and child groups + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn groups(&mut self, groups: Vec) -> &mut Self { + self.groups = Some(groups); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = AddGroupsToGroupV1 { + parent_group: self.parent_group.expect("parent_group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = AddGroupsToGroupV1InstructionArgs { + groups: self.groups.clone().expect("groups is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `add_groups_to_group_v1` CPI accounts. +pub struct AddGroupsToGroupV1CpiAccounts<'a, 'b> { + /// The address of the parent group to modify + pub parent_group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the parent and child groups + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `add_groups_to_group_v1` CPI instruction. +pub struct AddGroupsToGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the parent group to modify + pub parent_group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the parent and child groups + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: AddGroupsToGroupV1InstructionArgs, +} + +impl<'a, 'b> AddGroupsToGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: AddGroupsToGroupV1CpiAccounts<'a, 'b>, + args: AddGroupsToGroupV1InstructionArgs, + ) -> Self { + Self { + __program: program, + parent_group: accounts.parent_group, + payer: accounts.payer, + authority: accounts.authority, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.parent_group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let mut data = borsh::to_vec(&(AddGroupsToGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.parent_group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `AddGroupsToGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` parent_group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[]` system_program +pub struct AddGroupsToGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> AddGroupsToGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(AddGroupsToGroupV1CpiBuilderInstruction { + __program: program, + parent_group: None, + payer: None, + authority: None, + system_program: None, + groups: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the parent group to modify + #[inline(always)] + pub fn parent_group( + &mut self, + parent_group: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.parent_group = Some(parent_group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the parent and child groups + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn groups(&mut self, groups: Vec) -> &mut Self { + self.instruction.groups = Some(groups); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = AddGroupsToGroupV1InstructionArgs { + groups: self.instruction.groups.clone().expect("groups is not set"), + }; + let instruction = AddGroupsToGroupV1Cpi { + __program: self.instruction.__program, + + parent_group: self + .instruction + .parent_group + .expect("parent_group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct AddGroupsToGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + parent_group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + groups: Option>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/add_plugin_v1.rs b/clients/rust/src/generated/instructions/add_plugin_v1.rs index 41f5ad6c..f34acc98 100644 --- a/clients/rust/src/generated/instructions/add_plugin_v1.rs +++ b/clients/rust/src/generated/instructions/add_plugin_v1.rs @@ -84,8 +84,8 @@ impl AddPluginV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = AddPluginV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(AddPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -372,12 +372,12 @@ impl<'a, 'b> AddPluginV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = AddPluginV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(AddPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/approve_collection_plugin_authority_v1.rs b/clients/rust/src/generated/instructions/approve_collection_plugin_authority_v1.rs index 673bcfe0..bb932cb9 100644 --- a/clients/rust/src/generated/instructions/approve_collection_plugin_authority_v1.rs +++ b/clients/rust/src/generated/instructions/approve_collection_plugin_authority_v1.rs @@ -73,10 +73,9 @@ impl ApproveCollectionPluginAuthorityV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = ApproveCollectionPluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(ApproveCollectionPluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -339,14 +338,13 @@ impl<'a, 'b> ApproveCollectionPluginAuthorityV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = ApproveCollectionPluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(ApproveCollectionPluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/approve_plugin_authority_v1.rs b/clients/rust/src/generated/instructions/approve_plugin_authority_v1.rs index d8277e68..002cdcaf 100644 --- a/clients/rust/src/generated/instructions/approve_plugin_authority_v1.rs +++ b/clients/rust/src/generated/instructions/approve_plugin_authority_v1.rs @@ -84,10 +84,8 @@ impl ApprovePluginAuthorityV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = ApprovePluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(ApprovePluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -376,14 +374,12 @@ impl<'a, 'b> ApprovePluginAuthorityV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = ApprovePluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(ApprovePluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/burn_collection_v1.rs b/clients/rust/src/generated/instructions/burn_collection_v1.rs index 95450532..46983f84 100644 --- a/clients/rust/src/generated/instructions/burn_collection_v1.rs +++ b/clients/rust/src/generated/instructions/burn_collection_v1.rs @@ -66,8 +66,8 @@ impl BurnCollectionV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = BurnCollectionV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(BurnCollectionV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -299,12 +299,12 @@ impl<'a, 'b> BurnCollectionV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = BurnCollectionV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(BurnCollectionV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/burn_v1.rs b/clients/rust/src/generated/instructions/burn_v1.rs index a58d762b..6d5551b1 100644 --- a/clients/rust/src/generated/instructions/burn_v1.rs +++ b/clients/rust/src/generated/instructions/burn_v1.rs @@ -90,8 +90,8 @@ impl BurnV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = BurnV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(BurnV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -378,12 +378,12 @@ impl<'a, 'b> BurnV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = BurnV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(BurnV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/close_group_v1.rs b/clients/rust/src/generated/instructions/close_group_v1.rs new file mode 100644 index 00000000..a8b5a124 --- /dev/null +++ b/clients/rust/src/generated/instructions/close_group_v1.rs @@ -0,0 +1,372 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct CloseGroupV1 { + /// The address of the group to close + pub group: solana_program::pubkey::Pubkey, + /// The account receiving reclaimed lamports + pub payer: solana_program::pubkey::Pubkey, + /// The update authority of the group + pub authority: Option, +} + +impl CloseGroupV1 { + pub fn instruction(&self) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(&[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.group, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.extend_from_slice(remaining_accounts); + let data = borsh::to_vec(&(CloseGroupV1InstructionData::new())).unwrap(); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct CloseGroupV1InstructionData { + discriminator: u8, +} + +impl CloseGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 40 } + } +} + +/// Instruction builder for `CloseGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +#[derive(Default)] +pub struct CloseGroupV1Builder { + group: Option, + payer: Option, + authority: Option, + __remaining_accounts: Vec, +} + +impl CloseGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the group to close + #[inline(always)] + pub fn group(&mut self, group: solana_program::pubkey::Pubkey) -> &mut Self { + self.group = Some(group); + self + } + /// The account receiving reclaimed lamports + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the group + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = CloseGroupV1 { + group: self.group.expect("group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + }; + + accounts.instruction_with_remaining_accounts(&self.__remaining_accounts) + } +} + +/// `close_group_v1` CPI accounts. +pub struct CloseGroupV1CpiAccounts<'a, 'b> { + /// The address of the group to close + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account receiving reclaimed lamports + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the group + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, +} + +/// `close_group_v1` CPI instruction. +pub struct CloseGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the group to close + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account receiving reclaimed lamports + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the group + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, +} + +impl<'a, 'b> CloseGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: CloseGroupV1CpiAccounts<'a, 'b>, + ) -> Self { + Self { + __program: program, + group: accounts.group, + payer: accounts.payer, + authority: accounts.authority, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(3 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let data = borsh::to_vec(&(CloseGroupV1InstructionData::new())).unwrap(); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(3 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CloseGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +pub struct CloseGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CloseGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(CloseGroupV1CpiBuilderInstruction { + __program: program, + group: None, + payer: None, + authority: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the group to close + #[inline(always)] + pub fn group(&mut self, group: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.group = Some(group); + self + } + /// The account receiving reclaimed lamports + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the group + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let instruction = CloseGroupV1Cpi { + __program: self.instruction.__program, + + group: self.instruction.group.expect("group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct CloseGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/collect.rs b/clients/rust/src/generated/instructions/collect.rs index ba986da7..bced4b7b 100644 --- a/clients/rust/src/generated/instructions/collect.rs +++ b/clients/rust/src/generated/instructions/collect.rs @@ -37,7 +37,7 @@ impl Collect { false, )); accounts.extend_from_slice(remaining_accounts); - let data = CollectInstructionData::new().try_to_vec().unwrap(); + let data = borsh::to_vec(&(CollectInstructionData::new())).unwrap(); solana_program::instruction::Instruction { program_id: crate::MPL_CORE_ID, @@ -197,11 +197,11 @@ impl<'a, 'b> CollectCpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let data = CollectInstructionData::new().try_to_vec().unwrap(); + let data = borsh::to_vec(&(CollectInstructionData::new())).unwrap(); let instruction = solana_program::instruction::Instruction { program_id: crate::MPL_CORE_ID, diff --git a/clients/rust/src/generated/instructions/compress_v1.rs b/clients/rust/src/generated/instructions/compress_v1.rs index 2608e7fc..5b0da627 100644 --- a/clients/rust/src/generated/instructions/compress_v1.rs +++ b/clients/rust/src/generated/instructions/compress_v1.rs @@ -78,7 +78,7 @@ impl CompressV1 { )); } accounts.extend_from_slice(remaining_accounts); - let data = CompressV1InstructionData::new().try_to_vec().unwrap(); + let data = borsh::to_vec(&(CompressV1InstructionData::new())).unwrap(); solana_program::instruction::Instruction { program_id: crate::MPL_CORE_ID, @@ -334,11 +334,11 @@ impl<'a, 'b> CompressV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let data = CompressV1InstructionData::new().try_to_vec().unwrap(); + let data = borsh::to_vec(&(CompressV1InstructionData::new())).unwrap(); let instruction = solana_program::instruction::Instruction { program_id: crate::MPL_CORE_ID, diff --git a/clients/rust/src/generated/instructions/create_collection_v1.rs b/clients/rust/src/generated/instructions/create_collection_v1.rs index 612c1d3b..81c998e7 100644 --- a/clients/rust/src/generated/instructions/create_collection_v1.rs +++ b/clients/rust/src/generated/instructions/create_collection_v1.rs @@ -60,10 +60,8 @@ impl CreateCollectionV1 { false, )); accounts.extend_from_slice(remaining_accounts); - let mut data = CreateCollectionV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateCollectionV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -306,14 +304,12 @@ impl<'a, 'b> CreateCollectionV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = CreateCollectionV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateCollectionV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/create_collection_v2.rs b/clients/rust/src/generated/instructions/create_collection_v2.rs index 49778729..eb65b46e 100644 --- a/clients/rust/src/generated/instructions/create_collection_v2.rs +++ b/clients/rust/src/generated/instructions/create_collection_v2.rs @@ -61,10 +61,8 @@ impl CreateCollectionV2 { false, )); accounts.extend_from_slice(remaining_accounts); - let mut data = CreateCollectionV2InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateCollectionV2InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -319,14 +317,12 @@ impl<'a, 'b> CreateCollectionV2Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = CreateCollectionV2InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateCollectionV2InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/create_group_v1.rs b/clients/rust/src/generated/instructions/create_group_v1.rs new file mode 100644 index 00000000..44d35a49 --- /dev/null +++ b/clients/rust/src/generated/instructions/create_group_v1.rs @@ -0,0 +1,501 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::RelationshipEntry; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct CreateGroupV1 { + /// The address of the new group + pub group: solana_program::pubkey::Pubkey, + /// The authority of the new group + pub update_authority: Option, + /// The account paying for the storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl CreateGroupV1 { + pub fn instruction( + &self, + args: CreateGroupV1InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: CreateGroupV1InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.group, true, + )); + if let Some(update_authority) = self.update_authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + update_authority, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = borsh::to_vec(&(CreateGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct CreateGroupV1InstructionData { + discriminator: u8, +} + +impl CreateGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 39 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct CreateGroupV1InstructionArgs { + pub name: String, + pub uri: String, + pub relationships: Vec, +} + +/// Instruction builder for `CreateGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` group +/// 1. `[signer, optional]` update_authority +/// 2. `[writable, signer]` payer +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct CreateGroupV1Builder { + group: Option, + update_authority: Option, + payer: Option, + system_program: Option, + name: Option, + uri: Option, + relationships: Option>, + __remaining_accounts: Vec, +} + +impl CreateGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the new group + #[inline(always)] + pub fn group(&mut self, group: solana_program::pubkey::Pubkey) -> &mut Self { + self.group = Some(group); + self + } + /// `[optional account]` + /// The authority of the new group + #[inline(always)] + pub fn update_authority( + &mut self, + update_authority: Option, + ) -> &mut Self { + self.update_authority = update_authority; + self + } + /// The account paying for the storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn name(&mut self, name: String) -> &mut Self { + self.name = Some(name); + self + } + #[inline(always)] + pub fn uri(&mut self, uri: String) -> &mut Self { + self.uri = Some(uri); + self + } + #[inline(always)] + pub fn relationships(&mut self, relationships: Vec) -> &mut Self { + self.relationships = Some(relationships); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = CreateGroupV1 { + group: self.group.expect("group is not set"), + update_authority: self.update_authority, + payer: self.payer.expect("payer is not set"), + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = CreateGroupV1InstructionArgs { + name: self.name.clone().expect("name is not set"), + uri: self.uri.clone().expect("uri is not set"), + relationships: self + .relationships + .clone() + .expect("relationships is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `create_group_v1` CPI accounts. +pub struct CreateGroupV1CpiAccounts<'a, 'b> { + /// The address of the new group + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The authority of the new group + pub update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The account paying for the storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `create_group_v1` CPI instruction. +pub struct CreateGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the new group + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The authority of the new group + pub update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The account paying for the storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: CreateGroupV1InstructionArgs, +} + +impl<'a, 'b> CreateGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: CreateGroupV1CpiAccounts<'a, 'b>, + args: CreateGroupV1InstructionArgs, + ) -> Self { + Self { + __program: program, + group: accounts.group, + update_authority: accounts.update_authority, + payer: accounts.payer, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.group.key, + true, + )); + if let Some(update_authority) = self.update_authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *update_authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let mut data = borsh::to_vec(&(CreateGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.group.clone()); + if let Some(update_authority) = self.update_authority { + account_infos.push(update_authority.clone()); + } + account_infos.push(self.payer.clone()); + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `CreateGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable, signer]` group +/// 1. `[signer, optional]` update_authority +/// 2. `[writable, signer]` payer +/// 3. `[]` system_program +pub struct CreateGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> CreateGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(CreateGroupV1CpiBuilderInstruction { + __program: program, + group: None, + update_authority: None, + payer: None, + system_program: None, + name: None, + uri: None, + relationships: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the new group + #[inline(always)] + pub fn group(&mut self, group: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.group = Some(group); + self + } + /// `[optional account]` + /// The authority of the new group + #[inline(always)] + pub fn update_authority( + &mut self, + update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.update_authority = update_authority; + self + } + /// The account paying for the storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn name(&mut self, name: String) -> &mut Self { + self.instruction.name = Some(name); + self + } + #[inline(always)] + pub fn uri(&mut self, uri: String) -> &mut Self { + self.instruction.uri = Some(uri); + self + } + #[inline(always)] + pub fn relationships(&mut self, relationships: Vec) -> &mut Self { + self.instruction.relationships = Some(relationships); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = CreateGroupV1InstructionArgs { + name: self.instruction.name.clone().expect("name is not set"), + uri: self.instruction.uri.clone().expect("uri is not set"), + relationships: self + .instruction + .relationships + .clone() + .expect("relationships is not set"), + }; + let instruction = CreateGroupV1Cpi { + __program: self.instruction.__program, + + group: self.instruction.group.expect("group is not set"), + + update_authority: self.instruction.update_authority, + + payer: self.instruction.payer.expect("payer is not set"), + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct CreateGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + name: Option, + uri: Option, + relationships: Option>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/create_v1.rs b/clients/rust/src/generated/instructions/create_v1.rs index c3aec2ef..bb6c2e63 100644 --- a/clients/rust/src/generated/instructions/create_v1.rs +++ b/clients/rust/src/generated/instructions/create_v1.rs @@ -109,8 +109,8 @@ impl CreateV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = CreateV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -468,12 +468,12 @@ impl<'a, 'b> CreateV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = CreateV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/create_v2.rs b/clients/rust/src/generated/instructions/create_v2.rs index d5b91499..a62c9bfd 100644 --- a/clients/rust/src/generated/instructions/create_v2.rs +++ b/clients/rust/src/generated/instructions/create_v2.rs @@ -110,8 +110,8 @@ impl CreateV2 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = CreateV2InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateV2InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -481,12 +481,12 @@ impl<'a, 'b> CreateV2Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = CreateV2InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(CreateV2InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/decompress_v1.rs b/clients/rust/src/generated/instructions/decompress_v1.rs index b0d20eb1..3d7d333c 100644 --- a/clients/rust/src/generated/instructions/decompress_v1.rs +++ b/clients/rust/src/generated/instructions/decompress_v1.rs @@ -83,8 +83,8 @@ impl DecompressV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = DecompressV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(DecompressV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -365,12 +365,12 @@ impl<'a, 'b> DecompressV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = DecompressV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(DecompressV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/execute_v1.rs b/clients/rust/src/generated/instructions/execute_v1.rs index 8741e3a7..f6b9500b 100644 --- a/clients/rust/src/generated/instructions/execute_v1.rs +++ b/clients/rust/src/generated/instructions/execute_v1.rs @@ -19,7 +19,7 @@ pub struct ExecuteV1 { /// The signing PDA for the asset pub asset_signer: solana_program::pubkey::Pubkey, /// The account paying for the storage fees - pub payer: solana_program::pubkey::Pubkey, + pub payer: (solana_program::pubkey::Pubkey, bool), /// The owner or delegate of the asset pub authority: Option, /// The system program @@ -60,7 +60,8 @@ impl ExecuteV1 { false, )); accounts.push(solana_program::instruction::AccountMeta::new( - self.payer, true, + self.payer.0, + self.payer.1, )); if let Some(authority) = self.authority { accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -81,8 +82,8 @@ impl ExecuteV1 { false, )); accounts.extend_from_slice(remaining_accounts); - let mut data = ExecuteV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(ExecuteV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -129,7 +130,7 @@ pub struct ExecuteV1Builder { asset: Option, collection: Option, asset_signer: Option, - payer: Option, + payer: Option<(solana_program::pubkey::Pubkey, bool)>, authority: Option, system_program: Option, program_id: Option, @@ -162,8 +163,8 @@ impl ExecuteV1Builder { } /// The account paying for the storage fees #[inline(always)] - pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { - self.payer = Some(payer); + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey, as_signer: bool) -> &mut Self { + self.payer = Some((payer, as_signer)); self } /// `[optional account]` @@ -242,7 +243,7 @@ pub struct ExecuteV1CpiAccounts<'a, 'b> { /// The signing PDA for the asset pub asset_signer: &'b solana_program::account_info::AccountInfo<'a>, /// The account paying for the storage fees - pub payer: &'b solana_program::account_info::AccountInfo<'a>, + pub payer: (&'b solana_program::account_info::AccountInfo<'a>, bool), /// The owner or delegate of the asset pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The system program @@ -262,7 +263,7 @@ pub struct ExecuteV1Cpi<'a, 'b> { /// The signing PDA for the asset pub asset_signer: &'b solana_program::account_info::AccountInfo<'a>, /// The account paying for the storage fees - pub payer: &'b solana_program::account_info::AccountInfo<'a>, + pub payer: (&'b solana_program::account_info::AccountInfo<'a>, bool), /// The owner or delegate of the asset pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, /// The system program @@ -345,8 +346,8 @@ impl<'a, 'b> ExecuteV1Cpi<'a, 'b> { false, )); accounts.push(solana_program::instruction::AccountMeta::new( - *self.payer.key, - true, + *self.payer.0.key, + self.payer.1, )); if let Some(authority) = self.authority { accounts.push(solana_program::instruction::AccountMeta::new_readonly( @@ -370,12 +371,12 @@ impl<'a, 'b> ExecuteV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = ExecuteV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(ExecuteV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { @@ -390,7 +391,7 @@ impl<'a, 'b> ExecuteV1Cpi<'a, 'b> { account_infos.push(collection.clone()); } account_infos.push(self.asset_signer.clone()); - account_infos.push(self.payer.clone()); + account_infos.push(self.payer.0.clone()); if let Some(authority) = self.authority { account_infos.push(authority.clone()); } @@ -466,8 +467,12 @@ impl<'a, 'b> ExecuteV1CpiBuilder<'a, 'b> { } /// The account paying for the storage fees #[inline(always)] - pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { - self.instruction.payer = Some(payer); + pub fn payer( + &mut self, + payer: &'b solana_program::account_info::AccountInfo<'a>, + as_signer: bool, + ) -> &mut Self { + self.instruction.payer = Some((payer, as_signer)); self } /// `[optional account]` @@ -587,7 +592,7 @@ struct ExecuteV1CpiBuilderInstruction<'a, 'b> { asset: Option<&'b solana_program::account_info::AccountInfo<'a>>, collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, asset_signer: Option<&'b solana_program::account_info::AccountInfo<'a>>, - payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<(&'b solana_program::account_info::AccountInfo<'a>, bool)>, authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, program_id: Option<&'b solana_program::account_info::AccountInfo<'a>>, diff --git a/clients/rust/src/generated/instructions/mod.rs b/clients/rust/src/generated/instructions/mod.rs index 601c46e1..f3c60ca6 100644 --- a/clients/rust/src/generated/instructions/mod.rs +++ b/clients/rust/src/generated/instructions/mod.rs @@ -5,66 +5,86 @@ //! [https://github.com/metaplex-foundation/kinobi] //! +pub(crate) mod r#add_assets_to_group_v1; pub(crate) mod r#add_collection_external_plugin_adapter_v1; pub(crate) mod r#add_collection_plugin_v1; +pub(crate) mod r#add_collections_to_group_v1; pub(crate) mod r#add_external_plugin_adapter_v1; +pub(crate) mod r#add_groups_to_group_v1; pub(crate) mod r#add_plugin_v1; pub(crate) mod r#approve_collection_plugin_authority_v1; pub(crate) mod r#approve_plugin_authority_v1; pub(crate) mod r#burn_collection_v1; pub(crate) mod r#burn_v1; +pub(crate) mod r#close_group_v1; pub(crate) mod r#collect; pub(crate) mod r#compress_v1; pub(crate) mod r#create_collection_v1; pub(crate) mod r#create_collection_v2; +pub(crate) mod r#create_group_v1; pub(crate) mod r#create_v1; pub(crate) mod r#create_v2; pub(crate) mod r#decompress_v1; pub(crate) mod r#execute_v1; +pub(crate) mod r#remove_assets_from_group_v1; pub(crate) mod r#remove_collection_external_plugin_adapter_v1; pub(crate) mod r#remove_collection_plugin_v1; +pub(crate) mod r#remove_collections_from_group_v1; pub(crate) mod r#remove_external_plugin_adapter_v1; +pub(crate) mod r#remove_groups_from_group_v1; pub(crate) mod r#remove_plugin_v1; pub(crate) mod r#revoke_collection_plugin_authority_v1; pub(crate) mod r#revoke_plugin_authority_v1; pub(crate) mod r#transfer_v1; pub(crate) mod r#update_collection_external_plugin_adapter_v1; +pub(crate) mod r#update_collection_info_v1; pub(crate) mod r#update_collection_plugin_v1; pub(crate) mod r#update_collection_v1; pub(crate) mod r#update_external_plugin_adapter_v1; +pub(crate) mod r#update_group_v1; pub(crate) mod r#update_plugin_v1; pub(crate) mod r#update_v1; pub(crate) mod r#update_v2; pub(crate) mod r#write_collection_external_plugin_adapter_data_v1; pub(crate) mod r#write_external_plugin_adapter_data_v1; +pub use self::r#add_assets_to_group_v1::*; pub use self::r#add_collection_external_plugin_adapter_v1::*; pub use self::r#add_collection_plugin_v1::*; +pub use self::r#add_collections_to_group_v1::*; pub use self::r#add_external_plugin_adapter_v1::*; +pub use self::r#add_groups_to_group_v1::*; pub use self::r#add_plugin_v1::*; pub use self::r#approve_collection_plugin_authority_v1::*; pub use self::r#approve_plugin_authority_v1::*; pub use self::r#burn_collection_v1::*; pub use self::r#burn_v1::*; +pub use self::r#close_group_v1::*; pub use self::r#collect::*; pub use self::r#compress_v1::*; pub use self::r#create_collection_v1::*; pub use self::r#create_collection_v2::*; +pub use self::r#create_group_v1::*; pub use self::r#create_v1::*; pub use self::r#create_v2::*; pub use self::r#decompress_v1::*; pub use self::r#execute_v1::*; +pub use self::r#remove_assets_from_group_v1::*; pub use self::r#remove_collection_external_plugin_adapter_v1::*; pub use self::r#remove_collection_plugin_v1::*; +pub use self::r#remove_collections_from_group_v1::*; pub use self::r#remove_external_plugin_adapter_v1::*; +pub use self::r#remove_groups_from_group_v1::*; pub use self::r#remove_plugin_v1::*; pub use self::r#revoke_collection_plugin_authority_v1::*; pub use self::r#revoke_plugin_authority_v1::*; pub use self::r#transfer_v1::*; pub use self::r#update_collection_external_plugin_adapter_v1::*; +pub use self::r#update_collection_info_v1::*; pub use self::r#update_collection_plugin_v1::*; pub use self::r#update_collection_v1::*; pub use self::r#update_external_plugin_adapter_v1::*; +pub use self::r#update_group_v1::*; pub use self::r#update_plugin_v1::*; pub use self::r#update_v1::*; pub use self::r#update_v2::*; diff --git a/clients/rust/src/generated/instructions/remove_assets_from_group_v1.rs b/clients/rust/src/generated/instructions/remove_assets_from_group_v1.rs new file mode 100644 index 00000000..dc0fb5f1 --- /dev/null +++ b/clients/rust/src/generated/instructions/remove_assets_from_group_v1.rs @@ -0,0 +1,458 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +/// Accounts. +pub struct RemoveAssetsFromGroupV1 { + /// The address of the group to modify + pub group: solana_program::pubkey::Pubkey, + /// The account paying for storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The group update authority and asset update authority or delegate + pub authority: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl RemoveAssetsFromGroupV1 { + pub fn instruction( + &self, + args: RemoveAssetsFromGroupV1InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: RemoveAssetsFromGroupV1InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.group, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = borsh::to_vec(&(RemoveAssetsFromGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct RemoveAssetsFromGroupV1InstructionData { + discriminator: u8, +} + +impl RemoveAssetsFromGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 36 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RemoveAssetsFromGroupV1InstructionArgs { + pub assets: Vec, +} + +/// Instruction builder for `RemoveAssetsFromGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct RemoveAssetsFromGroupV1Builder { + group: Option, + payer: Option, + authority: Option, + system_program: Option, + assets: Option>, + __remaining_accounts: Vec, +} + +impl RemoveAssetsFromGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: solana_program::pubkey::Pubkey) -> &mut Self { + self.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and asset update authority or delegate + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn assets(&mut self, assets: Vec) -> &mut Self { + self.assets = Some(assets); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = RemoveAssetsFromGroupV1 { + group: self.group.expect("group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = RemoveAssetsFromGroupV1InstructionArgs { + assets: self.assets.clone().expect("assets is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `remove_assets_from_group_v1` CPI accounts. +pub struct RemoveAssetsFromGroupV1CpiAccounts<'a, 'b> { + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and asset update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `remove_assets_from_group_v1` CPI instruction. +pub struct RemoveAssetsFromGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and asset update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: RemoveAssetsFromGroupV1InstructionArgs, +} + +impl<'a, 'b> RemoveAssetsFromGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: RemoveAssetsFromGroupV1CpiAccounts<'a, 'b>, + args: RemoveAssetsFromGroupV1InstructionArgs, + ) -> Self { + Self { + __program: program, + group: accounts.group, + payer: accounts.payer, + authority: accounts.authority, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let mut data = borsh::to_vec(&(RemoveAssetsFromGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RemoveAssetsFromGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[]` system_program +pub struct RemoveAssetsFromGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RemoveAssetsFromGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(RemoveAssetsFromGroupV1CpiBuilderInstruction { + __program: program, + group: None, + payer: None, + authority: None, + system_program: None, + assets: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and asset update authority or delegate + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn assets(&mut self, assets: Vec) -> &mut Self { + self.instruction.assets = Some(assets); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = RemoveAssetsFromGroupV1InstructionArgs { + assets: self.instruction.assets.clone().expect("assets is not set"), + }; + let instruction = RemoveAssetsFromGroupV1Cpi { + __program: self.instruction.__program, + + group: self.instruction.group.expect("group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct RemoveAssetsFromGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + assets: Option>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/remove_collection_external_plugin_adapter_v1.rs b/clients/rust/src/generated/instructions/remove_collection_external_plugin_adapter_v1.rs index 5d2fb72d..8e7d1b18 100644 --- a/clients/rust/src/generated/instructions/remove_collection_external_plugin_adapter_v1.rs +++ b/clients/rust/src/generated/instructions/remove_collection_external_plugin_adapter_v1.rs @@ -72,10 +72,10 @@ impl RemoveCollectionExternalPluginAdapterV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = RemoveCollectionExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(RemoveCollectionExternalPluginAdapterV1InstructionData::new())) + .unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -327,14 +327,14 @@ impl<'a, 'b> RemoveCollectionExternalPluginAdapterV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = RemoveCollectionExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(RemoveCollectionExternalPluginAdapterV1InstructionData::new())) + .unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/remove_collection_plugin_v1.rs b/clients/rust/src/generated/instructions/remove_collection_plugin_v1.rs index beff3b2d..37526807 100644 --- a/clients/rust/src/generated/instructions/remove_collection_plugin_v1.rs +++ b/clients/rust/src/generated/instructions/remove_collection_plugin_v1.rs @@ -72,10 +72,8 @@ impl RemoveCollectionPluginV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = RemoveCollectionPluginV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(RemoveCollectionPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -327,14 +325,12 @@ impl<'a, 'b> RemoveCollectionPluginV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = RemoveCollectionPluginV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(RemoveCollectionPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/remove_collections_from_group_v1.rs b/clients/rust/src/generated/instructions/remove_collections_from_group_v1.rs new file mode 100644 index 00000000..7f9b6e6d --- /dev/null +++ b/clients/rust/src/generated/instructions/remove_collections_from_group_v1.rs @@ -0,0 +1,464 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +/// Accounts. +pub struct RemoveCollectionsFromGroupV1 { + /// The address of the group to modify + pub group: solana_program::pubkey::Pubkey, + /// The account paying for storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The group update authority and collection update authority or delegate + pub authority: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl RemoveCollectionsFromGroupV1 { + pub fn instruction( + &self, + args: RemoveCollectionsFromGroupV1InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: RemoveCollectionsFromGroupV1InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.group, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = + borsh::to_vec(&(RemoveCollectionsFromGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct RemoveCollectionsFromGroupV1InstructionData { + discriminator: u8, +} + +impl RemoveCollectionsFromGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 34 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RemoveCollectionsFromGroupV1InstructionArgs { + pub collections: Vec, +} + +/// Instruction builder for `RemoveCollectionsFromGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct RemoveCollectionsFromGroupV1Builder { + group: Option, + payer: Option, + authority: Option, + system_program: Option, + collections: Option>, + __remaining_accounts: Vec, +} + +impl RemoveCollectionsFromGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: solana_program::pubkey::Pubkey) -> &mut Self { + self.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and collection update authority or delegate + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn collections(&mut self, collections: Vec) -> &mut Self { + self.collections = Some(collections); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = RemoveCollectionsFromGroupV1 { + group: self.group.expect("group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = RemoveCollectionsFromGroupV1InstructionArgs { + collections: self.collections.clone().expect("collections is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `remove_collections_from_group_v1` CPI accounts. +pub struct RemoveCollectionsFromGroupV1CpiAccounts<'a, 'b> { + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and collection update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `remove_collections_from_group_v1` CPI instruction. +pub struct RemoveCollectionsFromGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the group to modify + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The group update authority and collection update authority or delegate + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: RemoveCollectionsFromGroupV1InstructionArgs, +} + +impl<'a, 'b> RemoveCollectionsFromGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: RemoveCollectionsFromGroupV1CpiAccounts<'a, 'b>, + args: RemoveCollectionsFromGroupV1InstructionArgs, + ) -> Self { + Self { + __program: program, + group: accounts.group, + payer: accounts.payer, + authority: accounts.authority, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let mut data = + borsh::to_vec(&(RemoveCollectionsFromGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RemoveCollectionsFromGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[]` system_program +pub struct RemoveCollectionsFromGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RemoveCollectionsFromGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(RemoveCollectionsFromGroupV1CpiBuilderInstruction { + __program: program, + group: None, + payer: None, + authority: None, + system_program: None, + collections: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the group to modify + #[inline(always)] + pub fn group(&mut self, group: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.group = Some(group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The group update authority and collection update authority or delegate + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn collections(&mut self, collections: Vec) -> &mut Self { + self.instruction.collections = Some(collections); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = RemoveCollectionsFromGroupV1InstructionArgs { + collections: self + .instruction + .collections + .clone() + .expect("collections is not set"), + }; + let instruction = RemoveCollectionsFromGroupV1Cpi { + __program: self.instruction.__program, + + group: self.instruction.group.expect("group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct RemoveCollectionsFromGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + collections: Option>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/remove_external_plugin_adapter_v1.rs b/clients/rust/src/generated/instructions/remove_external_plugin_adapter_v1.rs index 4e027b85..fdb29eb8 100644 --- a/clients/rust/src/generated/instructions/remove_external_plugin_adapter_v1.rs +++ b/clients/rust/src/generated/instructions/remove_external_plugin_adapter_v1.rs @@ -83,10 +83,9 @@ impl RemoveExternalPluginAdapterV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = RemoveExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(RemoveExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -364,14 +363,13 @@ impl<'a, 'b> RemoveExternalPluginAdapterV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = RemoveExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(RemoveExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/remove_groups_from_group_v1.rs b/clients/rust/src/generated/instructions/remove_groups_from_group_v1.rs new file mode 100644 index 00000000..99aa30e2 --- /dev/null +++ b/clients/rust/src/generated/instructions/remove_groups_from_group_v1.rs @@ -0,0 +1,465 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +/// Accounts. +pub struct RemoveGroupsFromGroupV1 { + /// The address of the parent group to modify + pub parent_group: solana_program::pubkey::Pubkey, + /// The account paying for storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The update authority of the parent and child groups + pub authority: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl RemoveGroupsFromGroupV1 { + pub fn instruction( + &self, + args: RemoveGroupsFromGroupV1InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: RemoveGroupsFromGroupV1InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.parent_group, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = borsh::to_vec(&(RemoveGroupsFromGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct RemoveGroupsFromGroupV1InstructionData { + discriminator: u8, +} + +impl RemoveGroupsFromGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 38 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RemoveGroupsFromGroupV1InstructionArgs { + pub groups: Vec, +} + +/// Instruction builder for `RemoveGroupsFromGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` parent_group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct RemoveGroupsFromGroupV1Builder { + parent_group: Option, + payer: Option, + authority: Option, + system_program: Option, + groups: Option>, + __remaining_accounts: Vec, +} + +impl RemoveGroupsFromGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the parent group to modify + #[inline(always)] + pub fn parent_group(&mut self, parent_group: solana_program::pubkey::Pubkey) -> &mut Self { + self.parent_group = Some(parent_group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the parent and child groups + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn groups(&mut self, groups: Vec) -> &mut Self { + self.groups = Some(groups); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = RemoveGroupsFromGroupV1 { + parent_group: self.parent_group.expect("parent_group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = RemoveGroupsFromGroupV1InstructionArgs { + groups: self.groups.clone().expect("groups is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `remove_groups_from_group_v1` CPI accounts. +pub struct RemoveGroupsFromGroupV1CpiAccounts<'a, 'b> { + /// The address of the parent group to modify + pub parent_group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the parent and child groups + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `remove_groups_from_group_v1` CPI instruction. +pub struct RemoveGroupsFromGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the parent group to modify + pub parent_group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the parent and child groups + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: RemoveGroupsFromGroupV1InstructionArgs, +} + +impl<'a, 'b> RemoveGroupsFromGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: RemoveGroupsFromGroupV1CpiAccounts<'a, 'b>, + args: RemoveGroupsFromGroupV1InstructionArgs, + ) -> Self { + Self { + __program: program, + parent_group: accounts.parent_group, + payer: accounts.payer, + authority: accounts.authority, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(4 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.parent_group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let mut data = borsh::to_vec(&(RemoveGroupsFromGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(4 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.parent_group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `RemoveGroupsFromGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` parent_group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[]` system_program +pub struct RemoveGroupsFromGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> RemoveGroupsFromGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(RemoveGroupsFromGroupV1CpiBuilderInstruction { + __program: program, + parent_group: None, + payer: None, + authority: None, + system_program: None, + groups: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the parent group to modify + #[inline(always)] + pub fn parent_group( + &mut self, + parent_group: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.parent_group = Some(parent_group); + self + } + /// The account paying for storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the parent and child groups + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + #[inline(always)] + pub fn groups(&mut self, groups: Vec) -> &mut Self { + self.instruction.groups = Some(groups); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = RemoveGroupsFromGroupV1InstructionArgs { + groups: self.instruction.groups.clone().expect("groups is not set"), + }; + let instruction = RemoveGroupsFromGroupV1Cpi { + __program: self.instruction.__program, + + parent_group: self + .instruction + .parent_group + .expect("parent_group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct RemoveGroupsFromGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + parent_group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + groups: Option>, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/remove_plugin_v1.rs b/clients/rust/src/generated/instructions/remove_plugin_v1.rs index 0b069144..091def55 100644 --- a/clients/rust/src/generated/instructions/remove_plugin_v1.rs +++ b/clients/rust/src/generated/instructions/remove_plugin_v1.rs @@ -83,8 +83,8 @@ impl RemovePluginV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = RemovePluginV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(RemovePluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -362,12 +362,12 @@ impl<'a, 'b> RemovePluginV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = RemovePluginV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(RemovePluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/revoke_collection_plugin_authority_v1.rs b/clients/rust/src/generated/instructions/revoke_collection_plugin_authority_v1.rs index 3b6c7fce..e2b11efc 100644 --- a/clients/rust/src/generated/instructions/revoke_collection_plugin_authority_v1.rs +++ b/clients/rust/src/generated/instructions/revoke_collection_plugin_authority_v1.rs @@ -72,10 +72,9 @@ impl RevokeCollectionPluginAuthorityV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = RevokeCollectionPluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(RevokeCollectionPluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -327,14 +326,13 @@ impl<'a, 'b> RevokeCollectionPluginAuthorityV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = RevokeCollectionPluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(RevokeCollectionPluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/revoke_plugin_authority_v1.rs b/clients/rust/src/generated/instructions/revoke_plugin_authority_v1.rs index 9b194290..2f8c668d 100644 --- a/clients/rust/src/generated/instructions/revoke_plugin_authority_v1.rs +++ b/clients/rust/src/generated/instructions/revoke_plugin_authority_v1.rs @@ -83,10 +83,8 @@ impl RevokePluginAuthorityV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = RevokePluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(RevokePluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -364,14 +362,12 @@ impl<'a, 'b> RevokePluginAuthorityV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = RevokePluginAuthorityV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(RevokePluginAuthorityV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/transfer_v1.rs b/clients/rust/src/generated/instructions/transfer_v1.rs index 35eb244c..b9361748 100644 --- a/clients/rust/src/generated/instructions/transfer_v1.rs +++ b/clients/rust/src/generated/instructions/transfer_v1.rs @@ -96,8 +96,8 @@ impl TransferV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = TransferV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(TransferV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -402,12 +402,12 @@ impl<'a, 'b> TransferV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = TransferV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(TransferV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/update_collection_external_plugin_adapter_v1.rs b/clients/rust/src/generated/instructions/update_collection_external_plugin_adapter_v1.rs index bc396088..6c98bab4 100644 --- a/clients/rust/src/generated/instructions/update_collection_external_plugin_adapter_v1.rs +++ b/clients/rust/src/generated/instructions/update_collection_external_plugin_adapter_v1.rs @@ -73,10 +73,10 @@ impl UpdateCollectionExternalPluginAdapterV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = UpdateCollectionExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(UpdateCollectionExternalPluginAdapterV1InstructionData::new())) + .unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -336,14 +336,14 @@ impl<'a, 'b> UpdateCollectionExternalPluginAdapterV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = UpdateCollectionExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(UpdateCollectionExternalPluginAdapterV1InstructionData::new())) + .unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/update_collection_info_v1.rs b/clients/rust/src/generated/instructions/update_collection_info_v1.rs new file mode 100644 index 00000000..539af344 --- /dev/null +++ b/clients/rust/src/generated/instructions/update_collection_info_v1.rs @@ -0,0 +1,391 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::UpdateType; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct UpdateCollectionInfoV1 { + /// The address of the asset + pub collection: solana_program::pubkey::Pubkey, + /// Bubblegum PDA signer + pub bubblegum_signer: solana_program::pubkey::Pubkey, +} + +impl UpdateCollectionInfoV1 { + pub fn instruction( + &self, + args: UpdateCollectionInfoV1InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: UpdateCollectionInfoV1InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(2 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.collection, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.bubblegum_signer, + true, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = borsh::to_vec(&(UpdateCollectionInfoV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct UpdateCollectionInfoV1InstructionData { + discriminator: u8, +} + +impl UpdateCollectionInfoV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 32 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct UpdateCollectionInfoV1InstructionArgs { + pub update_type: UpdateType, + pub amount: u32, +} + +/// Instruction builder for `UpdateCollectionInfoV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` collection +/// 1. `[signer]` bubblegum_signer +#[derive(Default)] +pub struct UpdateCollectionInfoV1Builder { + collection: Option, + bubblegum_signer: Option, + update_type: Option, + amount: Option, + __remaining_accounts: Vec, +} + +impl UpdateCollectionInfoV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the asset + #[inline(always)] + pub fn collection(&mut self, collection: solana_program::pubkey::Pubkey) -> &mut Self { + self.collection = Some(collection); + self + } + /// Bubblegum PDA signer + #[inline(always)] + pub fn bubblegum_signer( + &mut self, + bubblegum_signer: solana_program::pubkey::Pubkey, + ) -> &mut Self { + self.bubblegum_signer = Some(bubblegum_signer); + self + } + #[inline(always)] + pub fn update_type(&mut self, update_type: UpdateType) -> &mut Self { + self.update_type = Some(update_type); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u32) -> &mut Self { + self.amount = Some(amount); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = UpdateCollectionInfoV1 { + collection: self.collection.expect("collection is not set"), + bubblegum_signer: self.bubblegum_signer.expect("bubblegum_signer is not set"), + }; + let args = UpdateCollectionInfoV1InstructionArgs { + update_type: self.update_type.clone().expect("update_type is not set"), + amount: self.amount.clone().expect("amount is not set"), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `update_collection_info_v1` CPI accounts. +pub struct UpdateCollectionInfoV1CpiAccounts<'a, 'b> { + /// The address of the asset + pub collection: &'b solana_program::account_info::AccountInfo<'a>, + /// Bubblegum PDA signer + pub bubblegum_signer: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `update_collection_info_v1` CPI instruction. +pub struct UpdateCollectionInfoV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the asset + pub collection: &'b solana_program::account_info::AccountInfo<'a>, + /// Bubblegum PDA signer + pub bubblegum_signer: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: UpdateCollectionInfoV1InstructionArgs, +} + +impl<'a, 'b> UpdateCollectionInfoV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: UpdateCollectionInfoV1CpiAccounts<'a, 'b>, + args: UpdateCollectionInfoV1InstructionArgs, + ) -> Self { + Self { + __program: program, + collection: accounts.collection, + bubblegum_signer: accounts.bubblegum_signer, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(2 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.collection.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.bubblegum_signer.key, + true, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let mut data = borsh::to_vec(&(UpdateCollectionInfoV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(2 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.collection.clone()); + account_infos.push(self.bubblegum_signer.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `UpdateCollectionInfoV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` collection +/// 1. `[signer]` bubblegum_signer +pub struct UpdateCollectionInfoV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdateCollectionInfoV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(UpdateCollectionInfoV1CpiBuilderInstruction { + __program: program, + collection: None, + bubblegum_signer: None, + update_type: None, + amount: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the asset + #[inline(always)] + pub fn collection( + &mut self, + collection: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.collection = Some(collection); + self + } + /// Bubblegum PDA signer + #[inline(always)] + pub fn bubblegum_signer( + &mut self, + bubblegum_signer: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.bubblegum_signer = Some(bubblegum_signer); + self + } + #[inline(always)] + pub fn update_type(&mut self, update_type: UpdateType) -> &mut Self { + self.instruction.update_type = Some(update_type); + self + } + #[inline(always)] + pub fn amount(&mut self, amount: u32) -> &mut Self { + self.instruction.amount = Some(amount); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = UpdateCollectionInfoV1InstructionArgs { + update_type: self + .instruction + .update_type + .clone() + .expect("update_type is not set"), + amount: self.instruction.amount.clone().expect("amount is not set"), + }; + let instruction = UpdateCollectionInfoV1Cpi { + __program: self.instruction.__program, + + collection: self.instruction.collection.expect("collection is not set"), + + bubblegum_signer: self + .instruction + .bubblegum_signer + .expect("bubblegum_signer is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct UpdateCollectionInfoV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + collection: Option<&'b solana_program::account_info::AccountInfo<'a>>, + bubblegum_signer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + update_type: Option, + amount: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/update_collection_plugin_v1.rs b/clients/rust/src/generated/instructions/update_collection_plugin_v1.rs index dcdceea4..a113b86b 100644 --- a/clients/rust/src/generated/instructions/update_collection_plugin_v1.rs +++ b/clients/rust/src/generated/instructions/update_collection_plugin_v1.rs @@ -72,10 +72,8 @@ impl UpdateCollectionPluginV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = UpdateCollectionPluginV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateCollectionPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -327,14 +325,12 @@ impl<'a, 'b> UpdateCollectionPluginV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = UpdateCollectionPluginV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateCollectionPluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/update_collection_v1.rs b/clients/rust/src/generated/instructions/update_collection_v1.rs index 7213b870..8eef53b6 100644 --- a/clients/rust/src/generated/instructions/update_collection_v1.rs +++ b/clients/rust/src/generated/instructions/update_collection_v1.rs @@ -84,10 +84,8 @@ impl UpdateCollectionV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = UpdateCollectionV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateCollectionV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -378,14 +376,12 @@ impl<'a, 'b> UpdateCollectionV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = UpdateCollectionV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateCollectionV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/update_external_plugin_adapter_v1.rs b/clients/rust/src/generated/instructions/update_external_plugin_adapter_v1.rs index d55b2934..08dbd880 100644 --- a/clients/rust/src/generated/instructions/update_external_plugin_adapter_v1.rs +++ b/clients/rust/src/generated/instructions/update_external_plugin_adapter_v1.rs @@ -84,10 +84,9 @@ impl UpdateExternalPluginAdapterV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = UpdateExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(UpdateExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -373,14 +372,13 @@ impl<'a, 'b> UpdateExternalPluginAdapterV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = UpdateExternalPluginAdapterV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(UpdateExternalPluginAdapterV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/update_group_v1.rs b/clients/rust/src/generated/instructions/update_group_v1.rs new file mode 100644 index 00000000..b97845c9 --- /dev/null +++ b/clients/rust/src/generated/instructions/update_group_v1.rs @@ -0,0 +1,537 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +/// Accounts. +pub struct UpdateGroupV1 { + /// The address of the group to update + pub group: solana_program::pubkey::Pubkey, + /// The account paying for the storage fees + pub payer: solana_program::pubkey::Pubkey, + /// The update authority of the group + pub authority: Option, + /// The new update authority of the group + pub new_update_authority: Option, + /// The system program + pub system_program: solana_program::pubkey::Pubkey, +} + +impl UpdateGroupV1 { + pub fn instruction( + &self, + args: UpdateGroupV1InstructionArgs, + ) -> solana_program::instruction::Instruction { + self.instruction_with_remaining_accounts(args, &[]) + } + #[allow(clippy::vec_init_then_push)] + pub fn instruction_with_remaining_accounts( + &self, + args: UpdateGroupV1InstructionArgs, + remaining_accounts: &[solana_program::instruction::AccountMeta], + ) -> solana_program::instruction::Instruction { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + self.group, false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + self.payer, true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + authority, true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + if let Some(new_update_authority) = self.new_update_authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + new_update_authority, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + self.system_program, + false, + )); + accounts.extend_from_slice(remaining_accounts); + let mut data = borsh::to_vec(&(UpdateGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); + data.append(&mut args); + + solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +pub struct UpdateGroupV1InstructionData { + discriminator: u8, +} + +impl UpdateGroupV1InstructionData { + pub fn new() -> Self { + Self { discriminator: 41 } + } +} + +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct UpdateGroupV1InstructionArgs { + pub new_name: Option, + pub new_uri: Option, +} + +/// Instruction builder for `UpdateGroupV1`. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` new_update_authority +/// 4. `[optional]` system_program (default to `11111111111111111111111111111111`) +#[derive(Default)] +pub struct UpdateGroupV1Builder { + group: Option, + payer: Option, + authority: Option, + new_update_authority: Option, + system_program: Option, + new_name: Option, + new_uri: Option, + __remaining_accounts: Vec, +} + +impl UpdateGroupV1Builder { + pub fn new() -> Self { + Self::default() + } + /// The address of the group to update + #[inline(always)] + pub fn group(&mut self, group: solana_program::pubkey::Pubkey) -> &mut Self { + self.group = Some(group); + self + } + /// The account paying for the storage fees + #[inline(always)] + pub fn payer(&mut self, payer: solana_program::pubkey::Pubkey) -> &mut Self { + self.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the group + #[inline(always)] + pub fn authority(&mut self, authority: Option) -> &mut Self { + self.authority = authority; + self + } + /// `[optional account]` + /// The new update authority of the group + #[inline(always)] + pub fn new_update_authority( + &mut self, + new_update_authority: Option, + ) -> &mut Self { + self.new_update_authority = new_update_authority; + self + } + /// `[optional account, default to '11111111111111111111111111111111']` + /// The system program + #[inline(always)] + pub fn system_program(&mut self, system_program: solana_program::pubkey::Pubkey) -> &mut Self { + self.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_name(&mut self, new_name: String) -> &mut Self { + self.new_name = Some(new_name); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_uri(&mut self, new_uri: String) -> &mut Self { + self.new_uri = Some(new_uri); + self + } + /// Add an aditional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: solana_program::instruction::AccountMeta, + ) -> &mut Self { + self.__remaining_accounts.push(account); + self + } + /// Add additional accounts to the instruction. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[solana_program::instruction::AccountMeta], + ) -> &mut Self { + self.__remaining_accounts.extend_from_slice(accounts); + self + } + #[allow(clippy::clone_on_copy)] + pub fn instruction(&self) -> solana_program::instruction::Instruction { + let accounts = UpdateGroupV1 { + group: self.group.expect("group is not set"), + payer: self.payer.expect("payer is not set"), + authority: self.authority, + new_update_authority: self.new_update_authority, + system_program: self + .system_program + .unwrap_or(solana_program::pubkey!("11111111111111111111111111111111")), + }; + let args = UpdateGroupV1InstructionArgs { + new_name: self.new_name.clone(), + new_uri: self.new_uri.clone(), + }; + + accounts.instruction_with_remaining_accounts(args, &self.__remaining_accounts) + } +} + +/// `update_group_v1` CPI accounts. +pub struct UpdateGroupV1CpiAccounts<'a, 'b> { + /// The address of the group to update + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for the storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the group + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The new update authority of the group + pub new_update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, +} + +/// `update_group_v1` CPI instruction. +pub struct UpdateGroupV1Cpi<'a, 'b> { + /// The program to invoke. + pub __program: &'b solana_program::account_info::AccountInfo<'a>, + /// The address of the group to update + pub group: &'b solana_program::account_info::AccountInfo<'a>, + /// The account paying for the storage fees + pub payer: &'b solana_program::account_info::AccountInfo<'a>, + /// The update authority of the group + pub authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The new update authority of the group + pub new_update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + /// The system program + pub system_program: &'b solana_program::account_info::AccountInfo<'a>, + /// The arguments for the instruction. + pub __args: UpdateGroupV1InstructionArgs, +} + +impl<'a, 'b> UpdateGroupV1Cpi<'a, 'b> { + pub fn new( + program: &'b solana_program::account_info::AccountInfo<'a>, + accounts: UpdateGroupV1CpiAccounts<'a, 'b>, + args: UpdateGroupV1InstructionArgs, + ) -> Self { + Self { + __program: program, + group: accounts.group, + payer: accounts.payer, + authority: accounts.authority, + new_update_authority: accounts.new_update_authority, + system_program: accounts.system_program, + __args: args, + } + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], &[]) + } + #[inline(always)] + pub fn invoke_with_remaining_accounts( + &self, + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(&[], remaining_accounts) + } + #[inline(always)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed_with_remaining_accounts(signers_seeds, &[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed_with_remaining_accounts( + &self, + signers_seeds: &[&[&[u8]]], + remaining_accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> solana_program::entrypoint::ProgramResult { + let mut accounts = Vec::with_capacity(5 + remaining_accounts.len()); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.group.key, + false, + )); + accounts.push(solana_program::instruction::AccountMeta::new( + *self.payer.key, + true, + )); + if let Some(authority) = self.authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *authority.key, + true, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + if let Some(new_update_authority) = self.new_update_authority { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *new_update_authority.key, + false, + )); + } else { + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + crate::MPL_CORE_ID, + false, + )); + } + accounts.push(solana_program::instruction::AccountMeta::new_readonly( + *self.system_program.key, + false, + )); + remaining_accounts.iter().for_each(|remaining_account| { + accounts.push(solana_program::instruction::AccountMeta { + pubkey: *remaining_account.0.key, + is_writable: remaining_account.1, + is_signer: remaining_account.2, + }) + }); + let mut data = borsh::to_vec(&(UpdateGroupV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); + data.append(&mut args); + + let instruction = solana_program::instruction::Instruction { + program_id: crate::MPL_CORE_ID, + accounts, + data, + }; + let mut account_infos = Vec::with_capacity(5 + 1 + remaining_accounts.len()); + account_infos.push(self.__program.clone()); + account_infos.push(self.group.clone()); + account_infos.push(self.payer.clone()); + if let Some(authority) = self.authority { + account_infos.push(authority.clone()); + } + if let Some(new_update_authority) = self.new_update_authority { + account_infos.push(new_update_authority.clone()); + } + account_infos.push(self.system_program.clone()); + remaining_accounts + .iter() + .for_each(|remaining_account| account_infos.push(remaining_account.0.clone())); + + if signers_seeds.is_empty() { + solana_program::program::invoke(&instruction, &account_infos) + } else { + solana_program::program::invoke_signed(&instruction, &account_infos, signers_seeds) + } + } +} + +/// Instruction builder for `UpdateGroupV1` via CPI. +/// +/// ### Accounts: +/// +/// 0. `[writable]` group +/// 1. `[writable, signer]` payer +/// 2. `[signer, optional]` authority +/// 3. `[optional]` new_update_authority +/// 4. `[]` system_program +pub struct UpdateGroupV1CpiBuilder<'a, 'b> { + instruction: Box>, +} + +impl<'a, 'b> UpdateGroupV1CpiBuilder<'a, 'b> { + pub fn new(program: &'b solana_program::account_info::AccountInfo<'a>) -> Self { + let instruction = Box::new(UpdateGroupV1CpiBuilderInstruction { + __program: program, + group: None, + payer: None, + authority: None, + new_update_authority: None, + system_program: None, + new_name: None, + new_uri: None, + __remaining_accounts: Vec::new(), + }); + Self { instruction } + } + /// The address of the group to update + #[inline(always)] + pub fn group(&mut self, group: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.group = Some(group); + self + } + /// The account paying for the storage fees + #[inline(always)] + pub fn payer(&mut self, payer: &'b solana_program::account_info::AccountInfo<'a>) -> &mut Self { + self.instruction.payer = Some(payer); + self + } + /// `[optional account]` + /// The update authority of the group + #[inline(always)] + pub fn authority( + &mut self, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.authority = authority; + self + } + /// `[optional account]` + /// The new update authority of the group + #[inline(always)] + pub fn new_update_authority( + &mut self, + new_update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + ) -> &mut Self { + self.instruction.new_update_authority = new_update_authority; + self + } + /// The system program + #[inline(always)] + pub fn system_program( + &mut self, + system_program: &'b solana_program::account_info::AccountInfo<'a>, + ) -> &mut Self { + self.instruction.system_program = Some(system_program); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_name(&mut self, new_name: String) -> &mut Self { + self.instruction.new_name = Some(new_name); + self + } + /// `[optional argument]` + #[inline(always)] + pub fn new_uri(&mut self, new_uri: String) -> &mut Self { + self.instruction.new_uri = Some(new_uri); + self + } + /// Add an additional account to the instruction. + #[inline(always)] + pub fn add_remaining_account( + &mut self, + account: &'b solana_program::account_info::AccountInfo<'a>, + is_writable: bool, + is_signer: bool, + ) -> &mut Self { + self.instruction + .__remaining_accounts + .push((account, is_writable, is_signer)); + self + } + /// Add additional accounts to the instruction. + /// + /// Each account is represented by a tuple of the `AccountInfo`, a `bool` indicating whether the account is writable or not, + /// and a `bool` indicating whether the account is a signer or not. + #[inline(always)] + pub fn add_remaining_accounts( + &mut self, + accounts: &[( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )], + ) -> &mut Self { + self.instruction + .__remaining_accounts + .extend_from_slice(accounts); + self + } + #[inline(always)] + pub fn invoke(&self) -> solana_program::entrypoint::ProgramResult { + self.invoke_signed(&[]) + } + #[allow(clippy::clone_on_copy)] + #[allow(clippy::vec_init_then_push)] + pub fn invoke_signed( + &self, + signers_seeds: &[&[&[u8]]], + ) -> solana_program::entrypoint::ProgramResult { + let args = UpdateGroupV1InstructionArgs { + new_name: self.instruction.new_name.clone(), + new_uri: self.instruction.new_uri.clone(), + }; + let instruction = UpdateGroupV1Cpi { + __program: self.instruction.__program, + + group: self.instruction.group.expect("group is not set"), + + payer: self.instruction.payer.expect("payer is not set"), + + authority: self.instruction.authority, + + new_update_authority: self.instruction.new_update_authority, + + system_program: self + .instruction + .system_program + .expect("system_program is not set"), + __args: args, + }; + instruction.invoke_signed_with_remaining_accounts( + signers_seeds, + &self.instruction.__remaining_accounts, + ) + } +} + +struct UpdateGroupV1CpiBuilderInstruction<'a, 'b> { + __program: &'b solana_program::account_info::AccountInfo<'a>, + group: Option<&'b solana_program::account_info::AccountInfo<'a>>, + payer: Option<&'b solana_program::account_info::AccountInfo<'a>>, + authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + new_update_authority: Option<&'b solana_program::account_info::AccountInfo<'a>>, + system_program: Option<&'b solana_program::account_info::AccountInfo<'a>>, + new_name: Option, + new_uri: Option, + /// Additional instruction accounts `(AccountInfo, is_writable, is_signer)`. + __remaining_accounts: Vec<( + &'b solana_program::account_info::AccountInfo<'a>, + bool, + bool, + )>, +} diff --git a/clients/rust/src/generated/instructions/update_plugin_v1.rs b/clients/rust/src/generated/instructions/update_plugin_v1.rs index c8201f28..9ca8033b 100644 --- a/clients/rust/src/generated/instructions/update_plugin_v1.rs +++ b/clients/rust/src/generated/instructions/update_plugin_v1.rs @@ -83,8 +83,8 @@ impl UpdatePluginV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = UpdatePluginV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdatePluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -362,12 +362,12 @@ impl<'a, 'b> UpdatePluginV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = UpdatePluginV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdatePluginV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/update_v1.rs b/clients/rust/src/generated/instructions/update_v1.rs index 67de196b..5d699156 100644 --- a/clients/rust/src/generated/instructions/update_v1.rs +++ b/clients/rust/src/generated/instructions/update_v1.rs @@ -83,8 +83,8 @@ impl UpdateV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = UpdateV1InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -381,12 +381,12 @@ impl<'a, 'b> UpdateV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = UpdateV1InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/update_v2.rs b/clients/rust/src/generated/instructions/update_v2.rs index 925e4a7b..e181f110 100644 --- a/clients/rust/src/generated/instructions/update_v2.rs +++ b/clients/rust/src/generated/instructions/update_v2.rs @@ -96,8 +96,8 @@ impl UpdateV2 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = UpdateV2InstructionData::new().try_to_vec().unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateV2InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -423,12 +423,12 @@ impl<'a, 'b> UpdateV2Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = UpdateV2InstructionData::new().try_to_vec().unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = borsh::to_vec(&(UpdateV2InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs b/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs index 9f4e9692..5b0c5514 100644 --- a/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs +++ b/clients/rust/src/generated/instructions/write_collection_external_plugin_adapter_data_v1.rs @@ -84,10 +84,10 @@ impl WriteCollectionExternalPluginAdapterDataV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = WriteCollectionExternalPluginAdapterDataV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(WriteCollectionExternalPluginAdapterDataV1InstructionData::new())) + .unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -374,14 +374,14 @@ impl<'a, 'b> WriteCollectionExternalPluginAdapterDataV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = WriteCollectionExternalPluginAdapterDataV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(WriteCollectionExternalPluginAdapterDataV1InstructionData::new())) + .unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs b/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs index d5c51750..ce64fd16 100644 --- a/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs +++ b/clients/rust/src/generated/instructions/write_external_plugin_adapter_data_v1.rs @@ -95,10 +95,9 @@ impl WriteExternalPluginAdapterDataV1 { )); } accounts.extend_from_slice(remaining_accounts); - let mut data = WriteExternalPluginAdapterDataV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(WriteExternalPluginAdapterDataV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&args).unwrap(); data.append(&mut args); solana_program::instruction::Instruction { @@ -411,14 +410,13 @@ impl<'a, 'b> WriteExternalPluginAdapterDataV1Cpi<'a, 'b> { remaining_accounts.iter().for_each(|remaining_account| { accounts.push(solana_program::instruction::AccountMeta { pubkey: *remaining_account.0.key, - is_signer: remaining_account.1, - is_writable: remaining_account.2, + is_writable: remaining_account.1, + is_signer: remaining_account.2, }) }); - let mut data = WriteExternalPluginAdapterDataV1InstructionData::new() - .try_to_vec() - .unwrap(); - let mut args = self.__args.try_to_vec().unwrap(); + let mut data = + borsh::to_vec(&(WriteExternalPluginAdapterDataV1InstructionData::new())).unwrap(); + let mut args = borsh::to_vec(&self.__args).unwrap(); data.append(&mut args); let instruction = solana_program::instruction::Instruction { diff --git a/clients/rust/src/generated/types/agent_identity.rs b/clients/rust/src/generated/types/agent_identity.rs new file mode 100644 index 00000000..d72dddb1 --- /dev/null +++ b/clients/rust/src/generated/types/agent_identity.rs @@ -0,0 +1,19 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AgentIdentity { + pub uri: String, +} diff --git a/clients/rust/src/generated/types/agent_identity_init_info.rs b/clients/rust/src/generated/types/agent_identity_init_info.rs new file mode 100644 index 00000000..a62ce24a --- /dev/null +++ b/clients/rust/src/generated/types/agent_identity_init_info.rs @@ -0,0 +1,24 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalCheckResult; +use crate::generated::types::HookableLifecycleEvent; +use crate::generated::types::PluginAuthority; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AgentIdentityInitInfo { + pub uri: String, + pub init_plugin_authority: Option, + pub lifecycle_checks: Vec<(HookableLifecycleEvent, ExternalCheckResult)>, +} diff --git a/clients/rust/src/generated/types/agent_identity_update_info.rs b/clients/rust/src/generated/types/agent_identity_update_info.rs new file mode 100644 index 00000000..df3df24c --- /dev/null +++ b/clients/rust/src/generated/types/agent_identity_update_info.rs @@ -0,0 +1,22 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::ExternalCheckResult; +use crate::generated::types::HookableLifecycleEvent; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct AgentIdentityUpdateInfo { + pub uri: Option, + pub lifecycle_checks: Option>, +} diff --git a/clients/rust/src/generated/types/bubblegum_v2.rs b/clients/rust/src/generated/types/bubblegum_v2.rs new file mode 100644 index 00000000..9bd4a8e8 --- /dev/null +++ b/clients/rust/src/generated/types/bubblegum_v2.rs @@ -0,0 +1,17 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct BubblegumV2 {} diff --git a/clients/rust/src/generated/types/external_plugin_adapter.rs b/clients/rust/src/generated/types/external_plugin_adapter.rs index d691df27..8ea3249c 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter.rs @@ -5,6 +5,7 @@ //! [https://github.com/metaplex-foundation/kinobi] //! +use crate::generated::types::AgentIdentity; use crate::generated::types::AppData; use crate::generated::types::DataSection; use crate::generated::types::LifecycleHook; @@ -27,4 +28,5 @@ pub enum ExternalPluginAdapter { LinkedLifecycleHook(LinkedLifecycleHook), LinkedAppData(LinkedAppData), DataSection(DataSection), + AgentIdentity(AgentIdentity), } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs b/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs index 5992c9f7..8d0ca095 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_init_info.rs @@ -5,6 +5,7 @@ //! [https://github.com/metaplex-foundation/kinobi] //! +use crate::generated::types::AgentIdentityInitInfo; use crate::generated::types::AppDataInitInfo; use crate::generated::types::DataSectionInitInfo; use crate::generated::types::LifecycleHookInitInfo; @@ -27,4 +28,5 @@ pub enum ExternalPluginAdapterInitInfo { LinkedLifecycleHook(LinkedLifecycleHookInitInfo), LinkedAppData(LinkedAppDataInitInfo), DataSection(DataSectionInitInfo), + AgentIdentity(AgentIdentityInitInfo), } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_key.rs b/clients/rust/src/generated/types/external_plugin_adapter_key.rs index 6defc9f7..b0b014be 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_key.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_key.rs @@ -36,4 +36,5 @@ pub enum ExternalPluginAdapterKey { LinkedLifecycleHook(Pubkey), LinkedAppData(PluginAuthority), DataSection(LinkedDataKey), + AgentIdentity, } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_type.rs b/clients/rust/src/generated/types/external_plugin_adapter_type.rs index 4a3e299d..0488fa68 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_type.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_type.rs @@ -22,4 +22,5 @@ pub enum ExternalPluginAdapterType { LinkedLifecycleHook, LinkedAppData, DataSection, + AgentIdentity, } diff --git a/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs b/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs index 3b4840e2..eadd8c43 100644 --- a/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs +++ b/clients/rust/src/generated/types/external_plugin_adapter_update_info.rs @@ -5,6 +5,7 @@ //! [https://github.com/metaplex-foundation/kinobi] //! +use crate::generated::types::AgentIdentityUpdateInfo; use crate::generated::types::AppDataUpdateInfo; use crate::generated::types::LifecycleHookUpdateInfo; use crate::generated::types::LinkedAppDataUpdateInfo; @@ -25,4 +26,5 @@ pub enum ExternalPluginAdapterUpdateInfo { AppData(AppDataUpdateInfo), LinkedLifecycleHook(LinkedLifecycleHookUpdateInfo), LinkedAppData(LinkedAppDataUpdateInfo), + AgentIdentity(AgentIdentityUpdateInfo), } diff --git a/clients/rust/src/generated/types/freeze_execute.rs b/clients/rust/src/generated/types/freeze_execute.rs new file mode 100644 index 00000000..8568ccbe --- /dev/null +++ b/clients/rust/src/generated/types/freeze_execute.rs @@ -0,0 +1,19 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct FreezeExecute { + pub frozen: bool, +} diff --git a/clients/rust/src/generated/types/groups.rs b/clients/rust/src/generated/types/groups.rs new file mode 100644 index 00000000..c952d17f --- /dev/null +++ b/clients/rust/src/generated/types/groups.rs @@ -0,0 +1,24 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Groups { + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::>") + )] + pub groups: Vec, +} diff --git a/clients/rust/src/generated/types/hookable_lifecycle_event.rs b/clients/rust/src/generated/types/hookable_lifecycle_event.rs index 51e2288b..ee66cebe 100644 --- a/clients/rust/src/generated/types/hookable_lifecycle_event.rs +++ b/clients/rust/src/generated/types/hookable_lifecycle_event.rs @@ -20,4 +20,5 @@ pub enum HookableLifecycleEvent { Transfer, Burn, Update, + Execute, } diff --git a/clients/rust/src/generated/types/key.rs b/clients/rust/src/generated/types/key.rs index b6e4313d..f529e0a5 100644 --- a/clients/rust/src/generated/types/key.rs +++ b/clients/rust/src/generated/types/key.rs @@ -22,4 +22,5 @@ pub enum Key { PluginHeaderV1, PluginRegistryV1, CollectionV1, + GroupV1, } diff --git a/clients/rust/src/generated/types/mod.rs b/clients/rust/src/generated/types/mod.rs index 755acf21..d0167f5c 100644 --- a/clients/rust/src/generated/types/mod.rs +++ b/clients/rust/src/generated/types/mod.rs @@ -6,6 +6,9 @@ //! pub(crate) mod r#add_blocker; +pub(crate) mod r#agent_identity; +pub(crate) mod r#agent_identity_init_info; +pub(crate) mod r#agent_identity_update_info; pub(crate) mod r#app_data; pub(crate) mod r#app_data_init_info; pub(crate) mod r#app_data_update_info; @@ -13,6 +16,7 @@ pub(crate) mod r#attribute; pub(crate) mod r#attributes; pub(crate) mod r#autograph; pub(crate) mod r#autograph_signature; +pub(crate) mod r#bubblegum_v2; pub(crate) mod r#burn_delegate; pub(crate) mod r#compression_proof; pub(crate) mod r#creator; @@ -32,6 +36,8 @@ pub(crate) mod r#external_registry_record; pub(crate) mod r#external_validation_result; pub(crate) mod r#extra_account; pub(crate) mod r#freeze_delegate; +pub(crate) mod r#freeze_execute; +pub(crate) mod r#groups; pub(crate) mod r#hashable_plugin_schema; pub(crate) mod r#hashed_asset_schema; pub(crate) mod r#hookable_lifecycle_event; @@ -54,24 +60,31 @@ pub(crate) mod r#oracle_update_info; pub(crate) mod r#oracle_validation; pub(crate) mod r#permanent_burn_delegate; pub(crate) mod r#permanent_freeze_delegate; +pub(crate) mod r#permanent_freeze_execute; pub(crate) mod r#permanent_transfer_delegate; pub(crate) mod r#plugin; pub(crate) mod r#plugin_authority; pub(crate) mod r#plugin_authority_pair; pub(crate) mod r#plugin_type; pub(crate) mod r#registry_record; +pub(crate) mod r#relationship_entry; +pub(crate) mod r#relationship_kind; pub(crate) mod r#royalties; pub(crate) mod r#rule_set; pub(crate) mod r#seed; pub(crate) mod r#transfer_delegate; pub(crate) mod r#update_authority; pub(crate) mod r#update_delegate; +pub(crate) mod r#update_type; pub(crate) mod r#validation_result; pub(crate) mod r#validation_results_offset; pub(crate) mod r#verified_creators; pub(crate) mod r#verified_creators_signature; pub use self::r#add_blocker::*; +pub use self::r#agent_identity::*; +pub use self::r#agent_identity_init_info::*; +pub use self::r#agent_identity_update_info::*; pub use self::r#app_data::*; pub use self::r#app_data_init_info::*; pub use self::r#app_data_update_info::*; @@ -79,6 +92,7 @@ pub use self::r#attribute::*; pub use self::r#attributes::*; pub use self::r#autograph::*; pub use self::r#autograph_signature::*; +pub use self::r#bubblegum_v2::*; pub use self::r#burn_delegate::*; pub use self::r#compression_proof::*; pub use self::r#creator::*; @@ -98,6 +112,8 @@ pub use self::r#external_registry_record::*; pub use self::r#external_validation_result::*; pub use self::r#extra_account::*; pub use self::r#freeze_delegate::*; +pub use self::r#freeze_execute::*; +pub use self::r#groups::*; pub use self::r#hashable_plugin_schema::*; pub use self::r#hashed_asset_schema::*; pub use self::r#hookable_lifecycle_event::*; @@ -120,18 +136,22 @@ pub use self::r#oracle_update_info::*; pub use self::r#oracle_validation::*; pub use self::r#permanent_burn_delegate::*; pub use self::r#permanent_freeze_delegate::*; +pub use self::r#permanent_freeze_execute::*; pub use self::r#permanent_transfer_delegate::*; pub use self::r#plugin::*; pub use self::r#plugin_authority::*; pub use self::r#plugin_authority_pair::*; pub use self::r#plugin_type::*; pub use self::r#registry_record::*; +pub use self::r#relationship_entry::*; +pub use self::r#relationship_kind::*; pub use self::r#royalties::*; pub use self::r#rule_set::*; pub use self::r#seed::*; pub use self::r#transfer_delegate::*; pub use self::r#update_authority::*; pub use self::r#update_delegate::*; +pub use self::r#update_type::*; pub use self::r#validation_result::*; pub use self::r#validation_results_offset::*; pub use self::r#verified_creators::*; diff --git a/clients/rust/src/generated/types/permanent_freeze_execute.rs b/clients/rust/src/generated/types/permanent_freeze_execute.rs new file mode 100644 index 00000000..24c3f107 --- /dev/null +++ b/clients/rust/src/generated/types/permanent_freeze_execute.rs @@ -0,0 +1,19 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct PermanentFreezeExecute { + pub frozen: bool, +} diff --git a/clients/rust/src/generated/types/plugin.rs b/clients/rust/src/generated/types/plugin.rs index 98a923a9..37002234 100644 --- a/clients/rust/src/generated/types/plugin.rs +++ b/clients/rust/src/generated/types/plugin.rs @@ -8,13 +8,17 @@ use crate::generated::types::AddBlocker; use crate::generated::types::Attributes; use crate::generated::types::Autograph; +use crate::generated::types::BubblegumV2; use crate::generated::types::BurnDelegate; use crate::generated::types::Edition; use crate::generated::types::FreezeDelegate; +use crate::generated::types::FreezeExecute; +use crate::generated::types::Groups; use crate::generated::types::ImmutableMetadata; use crate::generated::types::MasterEdition; use crate::generated::types::PermanentBurnDelegate; use crate::generated::types::PermanentFreezeDelegate; +use crate::generated::types::PermanentFreezeExecute; use crate::generated::types::PermanentTransferDelegate; use crate::generated::types::Royalties; use crate::generated::types::TransferDelegate; @@ -45,4 +49,8 @@ pub enum Plugin { ImmutableMetadata(ImmutableMetadata), VerifiedCreators(VerifiedCreators), Autograph(Autograph), + BubblegumV2(BubblegumV2), + FreezeExecute(FreezeExecute), + PermanentFreezeExecute(PermanentFreezeExecute), + Groups(Groups), } diff --git a/clients/rust/src/generated/types/plugin_type.rs b/clients/rust/src/generated/types/plugin_type.rs index 7eb36292..8950a2c5 100644 --- a/clients/rust/src/generated/types/plugin_type.rs +++ b/clients/rust/src/generated/types/plugin_type.rs @@ -31,4 +31,8 @@ pub enum PluginType { ImmutableMetadata, VerifiedCreators, Autograph, + BubblegumV2, + FreezeExecute, + PermanentFreezeExecute, + Groups, } diff --git a/clients/rust/src/generated/types/relationship_entry.rs b/clients/rust/src/generated/types/relationship_entry.rs new file mode 100644 index 00000000..81948b35 --- /dev/null +++ b/clients/rust/src/generated/types/relationship_entry.rs @@ -0,0 +1,26 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +use crate::generated::types::RelationshipKind; +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::pubkey::Pubkey; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct RelationshipEntry { + pub kind: RelationshipKind, + #[cfg_attr( + feature = "serde", + serde(with = "serde_with::As::") + )] + pub key: Pubkey, +} diff --git a/clients/rust/src/generated/types/relationship_kind.rs b/clients/rust/src/generated/types/relationship_kind.rs new file mode 100644 index 00000000..fad38a80 --- /dev/null +++ b/clients/rust/src/generated/types/relationship_kind.rs @@ -0,0 +1,23 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use num_derive::FromPrimitive; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash, FromPrimitive)] +pub enum RelationshipKind { + Collection, + ChildGroup, + ParentGroup, + Asset, +} diff --git a/clients/rust/src/generated/types/update_type.rs b/clients/rust/src/generated/types/update_type.rs new file mode 100644 index 00000000..82f4f2e7 --- /dev/null +++ b/clients/rust/src/generated/types/update_type.rs @@ -0,0 +1,22 @@ +//! This code was AUTOGENERATED using the kinobi library. +//! Please DO NOT EDIT THIS FILE, instead use visitors +//! to add features, then rerun kinobi to update it. +//! +//! [https://github.com/metaplex-foundation/kinobi] +//! + +#[cfg(feature = "anchor")] +use anchor_lang::prelude::{AnchorDeserialize, AnchorSerialize}; +#[cfg(not(feature = "anchor"))] +use borsh::{BorshDeserialize, BorshSerialize}; +use num_derive::FromPrimitive; + +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] +#[cfg_attr(not(feature = "anchor"), derive(BorshSerialize, BorshDeserialize))] +#[cfg_attr(feature = "anchor", derive(AnchorSerialize, AnchorDeserialize))] +#[derive(Clone, Debug, Eq, PartialEq, PartialOrd, Hash, FromPrimitive)] +pub enum UpdateType { + Mint, + Add, + Remove, +} diff --git a/clients/rust/src/hooked/advanced_types.rs b/clients/rust/src/hooked/advanced_types.rs index 5dc81285..3e2c6b3b 100644 --- a/clients/rust/src/hooked/advanced_types.rs +++ b/clients/rust/src/hooked/advanced_types.rs @@ -8,10 +8,11 @@ use std::{cmp::Ordering, io::ErrorKind}; use crate::{ accounts::{BaseAssetV1, BaseCollectionV1, PluginHeaderV1}, types::{ - AddBlocker, AppData, Attributes, Autograph, BurnDelegate, DataSection, Edition, - ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterKey, FreezeDelegate, - ImmutableMetadata, Key, LifecycleHook, LinkedAppData, LinkedLifecycleHook, MasterEdition, - Oracle, PermanentBurnDelegate, PermanentFreezeDelegate, PermanentTransferDelegate, + AddBlocker, AgentIdentity, AppData, Attributes, Autograph, BubblegumV2, BurnDelegate, + DataSection, Edition, ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterKey, + FreezeDelegate, FreezeExecute, Groups, ImmutableMetadata, Key, LifecycleHook, + LinkedAppData, LinkedLifecycleHook, MasterEdition, Oracle, PermanentBurnDelegate, + PermanentFreezeDelegate, PermanentFreezeExecute, PermanentTransferDelegate, PluginAuthority, Royalties, TransferDelegate, UpdateDelegate, VerifiedCreators, }, }; @@ -160,6 +161,30 @@ pub struct AutographPlugin { pub autograph: Autograph, } +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct BubblegumV2Plugin { + pub base: BasePlugin, + pub bubblegum_v2: BubblegumV2, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct FreezeExecutePlugin { + pub base: BasePlugin, + pub freeze_execute: FreezeExecute, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct PermanentFreezeExecutePlugin { + pub base: BasePlugin, + pub permanent_freeze_execute: PermanentFreezeExecute, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub struct GroupsPlugin { + pub base: BasePlugin, + pub groups: Groups, +} + #[derive(Debug, Default)] pub struct PluginsList { pub royalties: Option, @@ -177,6 +202,10 @@ pub struct PluginsList { pub immutable_metadata: Option, pub verified_creators: Option, pub autograph: Option, + pub bubblegum_v2: Option, + pub freeze_execute: Option, + pub permanent_freeze_execute: Option, + pub groups: Option, } #[derive(Debug, Default)] @@ -187,6 +216,7 @@ pub struct ExternalPluginAdaptersList { pub app_data: Vec, pub linked_app_data: Vec, pub data_sections: Vec, + pub agent_identities: Vec, } #[derive(Debug)] @@ -345,6 +375,7 @@ impl From<&ExternalPluginAdapter> for ExternalPluginAdapterKey { ExternalPluginAdapterKey::LifecycleHook(lifecycle_hook.hooked_program) } ExternalPluginAdapter::DataSection(_) => todo!(), + ExternalPluginAdapter::AgentIdentity(_) => ExternalPluginAdapterKey::AgentIdentity, } } } diff --git a/clients/rust/src/hooked/asset.rs b/clients/rust/src/hooked/asset.rs index 4dcd849a..213c4c75 100644 --- a/clients/rust/src/hooked/asset.rs +++ b/clients/rust/src/hooked/asset.rs @@ -1,18 +1,20 @@ -#[cfg(feature = "anchor")] -use anchor_lang::prelude::AnchorSerialize; -#[cfg(not(feature = "anchor"))] -use borsh::BorshSerialize; +use std::io::ErrorKind; use crate::{ accounts::{BaseAssetV1, PluginHeaderV1}, - registry_records_to_external_plugin_adapter_list, registry_records_to_plugin_list, Asset, - ExternalPluginAdaptersList, PluginRegistryV1Safe, PluginsList, + registry_records_to_external_plugin_adapter_list, registry_records_to_plugin_list, + types::Key, + Asset, ExternalPluginAdaptersList, PluginRegistryV1Safe, PluginsList, }; impl Asset { pub fn deserialize(data: &[u8]) -> Result, std::io::Error> { + if Key::from_slice(data, 0)? != Key::AssetV1 { + return Err(ErrorKind::InvalidInput.into()); + } + let base = BaseAssetV1::from_bytes(data)?; - let base_data = base.try_to_vec()?; + let base_data = borsh::to_vec(&base)?; if base_data.len() != data.len() { return Self::deserialize_with_plugins(data, base, base_data); diff --git a/clients/rust/src/hooked/collection.rs b/clients/rust/src/hooked/collection.rs index 899edf1c..0643299d 100644 --- a/clients/rust/src/hooked/collection.rs +++ b/clients/rust/src/hooked/collection.rs @@ -1,18 +1,20 @@ -#[cfg(feature = "anchor")] -use anchor_lang::prelude::AnchorSerialize; -#[cfg(not(feature = "anchor"))] -use borsh::BorshSerialize; +use std::io::ErrorKind; use crate::{ accounts::{BaseCollectionV1, PluginHeaderV1}, - registry_records_to_external_plugin_adapter_list, registry_records_to_plugin_list, Collection, - ExternalPluginAdaptersList, PluginRegistryV1Safe, PluginsList, + registry_records_to_external_plugin_adapter_list, registry_records_to_plugin_list, + types::Key, + Collection, ExternalPluginAdaptersList, PluginRegistryV1Safe, PluginsList, }; impl Collection { pub fn deserialize(data: &[u8]) -> Result, std::io::Error> { + if Key::from_slice(data, 0)? != Key::CollectionV1 { + return Err(ErrorKind::InvalidInput.into()); + } + let base = BaseCollectionV1::from_bytes(data)?; - let base_data = base.try_to_vec()?; + let base_data = borsh::to_vec(&base)?; if base_data.len() != data.len() { return Self::deserialize_with_plugins(data, base, base_data); diff --git a/clients/rust/src/hooked/mod.rs b/clients/rust/src/hooked/mod.rs index ac063d26..ef079199 100644 --- a/clients/rust/src/hooked/mod.rs +++ b/clients/rust/src/hooked/mod.rs @@ -5,10 +5,8 @@ pub mod advanced_types; pub use advanced_types::*; pub mod asset; -pub use asset::*; pub mod collection; -pub use collection::*; #[cfg(feature = "anchor")] use anchor_lang::prelude::{ @@ -34,6 +32,8 @@ use solana_program::account_info::AccountInfo; impl From<&Plugin> for PluginType { fn from(plugin: &Plugin) -> Self { match plugin { + Plugin::AddBlocker(_) => PluginType::AddBlocker, + Plugin::ImmutableMetadata(_) => PluginType::ImmutableMetadata, Plugin::Royalties(_) => PluginType::Royalties, Plugin::FreezeDelegate(_) => PluginType::FreezeDelegate, Plugin::BurnDelegate(_) => PluginType::BurnDelegate, @@ -45,10 +45,12 @@ impl From<&Plugin> for PluginType { Plugin::PermanentBurnDelegate(_) => PluginType::PermanentBurnDelegate, Plugin::Edition(_) => PluginType::Edition, Plugin::MasterEdition(_) => PluginType::MasterEdition, - Plugin::AddBlocker(_) => PluginType::AddBlocker, - Plugin::ImmutableMetadata(_) => PluginType::ImmutableMetadata, Plugin::VerifiedCreators(_) => PluginType::VerifiedCreators, Plugin::Autograph(_) => PluginType::Autograph, + Plugin::BubblegumV2(_) => PluginType::BubblegumV2, + Plugin::FreezeExecute(_) => PluginType::FreezeExecute, + Plugin::PermanentFreezeExecute(_) => PluginType::PermanentFreezeExecute, + Plugin::Groups(_) => PluginType::Groups, } } } @@ -96,7 +98,7 @@ mod anchor_impl { // Not used but needed for Anchor. impl Discriminator for BaseAssetV1 { - const DISCRIMINATOR: [u8; 8] = [0; 8]; + const DISCRIMINATOR: &'static [u8] = &[Key::AssetV1 as u8]; } impl Owner for BaseAssetV1 { @@ -118,7 +120,7 @@ mod anchor_impl { // Not used but needed for Anchor. impl Discriminator for BaseCollectionV1 { - const DISCRIMINATOR: [u8; 8] = [0; 8]; + const DISCRIMINATOR: &'static [u8] = &[Key::CollectionV1 as u8]; } impl Owner for BaseCollectionV1 { @@ -174,14 +176,29 @@ impl SolanaAccount for PluginHeaderV1 { } } +impl Key { + /// Load the one byte key from a slice of data at the given offset. + pub fn from_slice(data: &[u8], offset: usize) -> Result { + let key_byte = *data.get(offset).ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::DeserializationError.to_string(), + ) + })?; + + Self::from_u8(key_byte).ok_or_else(|| { + std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::DeserializationError.to_string(), + ) + }) + } +} + /// Load the one byte key from the account data at the given offset. pub fn load_key(account: &AccountInfo, offset: usize) -> Result { - let key = Key::from_u8((*account.data).borrow()[offset]).ok_or(std::io::Error::new( - std::io::ErrorKind::Other, - MplCoreError::DeserializationError.to_string(), - ))?; - - Ok(key) + let data = account.data.borrow(); + Key::from_slice(&data, offset) } /// A trait for generic blobs of data that have size. @@ -207,6 +224,13 @@ pub trait SolanaAccount: CrateSerialize + CrateDeserialize { )); } + if account.owner != &crate::ID { + return Err(std::io::Error::new( + std::io::ErrorKind::Other, + MplCoreError::IncorrectAccount.to_string(), + )); + } + let mut bytes: &[u8] = &(*account.data).borrow()[offset..]; Self::deserialize(&mut bytes) } @@ -259,6 +283,7 @@ impl From<&ExternalPluginAdapterKey> for ExternalPluginAdapterType { ExternalPluginAdapterKey::AppData(_) => ExternalPluginAdapterType::AppData, ExternalPluginAdapterKey::LinkedAppData(_) => ExternalPluginAdapterType::LinkedAppData, ExternalPluginAdapterKey::DataSection(_) => ExternalPluginAdapterType::DataSection, + ExternalPluginAdapterKey::AgentIdentity => ExternalPluginAdapterType::AgentIdentity, } } } diff --git a/clients/rust/src/hooked/plugin.rs b/clients/rust/src/hooked/plugin.rs index 6640f091..6c0fad29 100644 --- a/clients/rust/src/hooked/plugin.rs +++ b/clients/rust/src/hooked/plugin.rs @@ -13,12 +13,13 @@ use crate::{ Plugin, PluginAuthority, PluginType, RegistryRecord, }, AddBlockerPlugin, AppDataWithData, AttributesPlugin, AutographPlugin, BaseAuthority, - BasePlugin, BurnDelegatePlugin, DataBlob, DataSectionWithData, EditionPlugin, - ExternalPluginAdaptersList, ExternalRegistryRecordSafe, FreezeDelegatePlugin, - ImmutableMetadataPlugin, LifecycleHookWithData, MasterEditionPlugin, - PermanentBurnDelegatePlugin, PermanentFreezeDelegatePlugin, PermanentTransferDelegatePlugin, - PluginRegistryV1Safe, PluginsList, RegistryRecordSafe, RoyaltiesPlugin, SolanaAccount, - TransferDelegatePlugin, UpdateDelegatePlugin, VerifiedCreatorsPlugin, + BasePlugin, BubblegumV2Plugin, BurnDelegatePlugin, DataBlob, DataSectionWithData, + EditionPlugin, ExternalPluginAdaptersList, ExternalRegistryRecordSafe, FreezeDelegatePlugin, + FreezeExecutePlugin, GroupsPlugin, ImmutableMetadataPlugin, LifecycleHookWithData, + MasterEditionPlugin, PermanentBurnDelegatePlugin, PermanentFreezeDelegatePlugin, + PermanentFreezeExecutePlugin, PermanentTransferDelegatePlugin, PluginRegistryV1Safe, + PluginsList, RegistryRecordSafe, RoyaltiesPlugin, SolanaAccount, TransferDelegatePlugin, + UpdateDelegatePlugin, VerifiedCreatorsPlugin, }; /// Fetch the plugin from the registry. @@ -345,6 +346,22 @@ pub(crate) fn registry_records_to_plugin_list( Plugin::Autograph(autograph) => { acc.autograph = Some(AutographPlugin { base, autograph }) } + Plugin::BubblegumV2(bubblegum_v2) => { + acc.bubblegum_v2 = Some(BubblegumV2Plugin { base, bubblegum_v2 }) + } + Plugin::Groups(groups) => acc.groups = Some(GroupsPlugin { base, groups }), + Plugin::FreezeExecute(freeze_execute) => { + acc.freeze_execute = Some(FreezeExecutePlugin { + base, + freeze_execute, + }) + } + Plugin::PermanentFreezeExecute(permanent_freeze_execute) => { + acc.permanent_freeze_execute = Some(PermanentFreezeExecutePlugin { + base, + permanent_freeze_execute, + }) + } } } Ok(acc) @@ -405,6 +422,9 @@ pub(crate) fn registry_records_to_external_plugin_adapter_list( data_len, }) } + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + acc.agent_identities.push(agent_identity) + } } } Ok(acc) @@ -508,6 +528,8 @@ pub(crate) fn find_external_plugin_adapter<'b>( } } } + // AgentIdentity is a unit variant key (only one per asset). + ExternalPluginAdapterKey::AgentIdentity => true, }) { result = (Some(i), Some(record)); diff --git a/clients/rust/src/indexable_asset.rs b/clients/rust/src/indexable_asset.rs index 919ed663..60a47ace 100644 --- a/clients/rust/src/indexable_asset.rs +++ b/clients/rust/src/indexable_asset.rs @@ -9,7 +9,7 @@ use solana_program::pubkey::Pubkey; use std::{cmp::Ordering, collections::HashMap, io::ErrorKind}; use crate::{ - accounts::{BaseAssetV1, BaseCollectionV1, PluginHeaderV1}, + accounts::{BaseAssetV1, BaseCollectionV1, GroupV1, PluginHeaderV1}, convert_external_plugin_adapter_data_to_string, types::{ ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterSchema, @@ -179,6 +179,8 @@ pub struct LifecycleChecks { pub transfer: Vec, #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))] pub burn: Vec, + #[cfg_attr(feature = "serde", serde(skip_serializing_if = "Vec::is_empty"))] + pub execute: Vec, } impl LifecycleChecks { @@ -187,6 +189,7 @@ impl LifecycleChecks { && self.update.is_empty() && self.transfer.is_empty() && self.burn.is_empty() + && self.execute.is_empty() } } @@ -246,6 +249,7 @@ impl ProcessedExternalPlugin { known_lifecycle_checks.transfer = checks } HookableLifecycleEvent::Burn => known_lifecycle_checks.burn = checks, + HookableLifecycleEvent::Execute => known_lifecycle_checks.execute = checks, }, None => unknown_lifecycle_checks.push((event, checks)), } @@ -273,6 +277,10 @@ impl ProcessedExternalPlugin { ExternalPluginAdapter::DataSection(data_section) => &data_section.schema, // Assume binary for `Oracle`, but this should never happen. ExternalPluginAdapter::Oracle(_) => &ExternalPluginAdapterSchema::Binary, + // AgentIdentity has no data section. + ExternalPluginAdapter::AgentIdentity(_) => { + &ExternalPluginAdapterSchema::Binary + } }; ( @@ -331,7 +339,7 @@ impl ProcessedExternalPlugin { } } -/// A type used to store both Core Assets and Core Collections for indexing. +/// A type used to store Core Assets, Collections, and Groups for indexing. #[derive(Clone, Debug, Eq, PartialEq)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct IndexableAsset { @@ -405,6 +413,40 @@ impl IndexableAsset { } } + /// Create a new `IndexableAsset` from a `GroupV1`. + pub fn from_group(group: GroupV1) -> Self { + Self { + owner: Some(group.update_authority), + update_authority: UpdateAuthority::Address(group.update_authority), + name: group.name, + uri: group.uri, + seq: 0, + num_minted: None, + current_size: None, + plugins: HashMap::new(), + unknown_plugins: vec![], + external_plugins: vec![], + unknown_external_plugins: vec![], + } + } + + fn group_len(group: &GroupV1) -> usize { + 1 // Key + + 32 // Update authority + + 4 // Name length + + group.name.len() + + 4 // URI length + + group.uri.len() + + 4 // collections length + + (group.collections.len() * 32) + + 4 // groups length + + (group.groups.len() * 32) + + 4 // parent_groups length + + (group.parent_groups.len() * 32) + + 4 // assets length + + (group.assets.len() * 32) + } + // Add a processed plugin to the correct `IndexableAsset` struct member. fn add_processed_plugin(&mut self, plugin: ProcessedPlugin) { match plugin { @@ -433,7 +475,7 @@ impl IndexableAsset { data_offset: Option, data_len: Option, account: &[u8], - ) -> Result, std::io::Error> { + ) -> Result>, std::io::Error> { if data_offset.is_some() && data_len.is_some() { let data_offset = data_offset.unwrap() as usize; let data_len = data_len.unwrap() as usize; @@ -495,9 +537,13 @@ impl IndexableAsset { Ok(()) } - /// Fetch the base `Asset`` or `Collection`` and all the plugins and store in an + /// Fetch the base `Asset`, `Collection`, or `Group` and all the plugins and store in an /// `IndexableAsset`. pub fn fetch(key: Key, account: &[u8]) -> Result { + if Key::from_slice(account, 0)? != key { + return Err(ErrorKind::InvalidInput.into()); + } + let (mut indexable_asset, base_size) = match key { Key::AssetV1 => { let asset = BaseAssetV1::from_bytes(account)?; @@ -511,6 +557,12 @@ impl IndexableAsset { let indexable_asset = Self::from_collection(collection); (indexable_asset, base_size) } + Key::GroupV1 => { + let group = GroupV1::from_bytes(account)?; + let base_size = Self::group_len(&group); + let indexable_asset = Self::from_group(group); + (indexable_asset, base_size) + } _ => return Err(ErrorKind::InvalidInput.into()), }; diff --git a/clients/rust/tests/create_collection_with_external_plugins.rs b/clients/rust/tests/create_collection_with_external_plugins.rs index 79568e3f..c6589e7b 100644 --- a/clients/rust/tests/create_collection_with_external_plugins.rs +++ b/clients/rust/tests/create_collection_with_external_plugins.rs @@ -300,7 +300,6 @@ async fn test_create_and_fetch_app_data_on_collection() { account.data.borrow_mut(), &account.owner, false, - 0, ); // Fetch external plugin adapter two ways. diff --git a/clients/rust/tests/create_with_external_plugins.rs b/clients/rust/tests/create_with_external_plugins.rs index 484b81e7..a1071b88 100644 --- a/clients/rust/tests/create_with_external_plugins.rs +++ b/clients/rust/tests/create_with_external_plugins.rs @@ -411,7 +411,6 @@ async fn test_create_and_fetch_app_data() { account.data.borrow_mut(), &account.owner, false, - 0, ); // Fetch external plugin adapter two ways. diff --git a/clients/rust/tests/freeze_execute.rs b/clients/rust/tests/freeze_execute.rs new file mode 100644 index 00000000..2976c398 --- /dev/null +++ b/clients/rust/tests/freeze_execute.rs @@ -0,0 +1,167 @@ +//! Integration tests for the FreezeExecute plugin covering the +//! "backed NFT" flow: mint → freeze → execute blocked → burn & refund. +#![cfg(feature = "test-sbf")] + +pub mod setup; +use mpl_core::{ + errors::MplCoreError, + instructions::{BurnV1Builder, ExecuteV1Builder}, + types::{FreezeExecute, Plugin, PluginAuthority, PluginAuthorityPair}, +}; +use setup::*; + +use solana_program::pubkey::Pubkey; +use solana_program_test::tokio; +use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction}; +use solana_system_interface::{instruction as system_instruction, program as system_program}; + +const FREEZE_EXECUTE_PREFIX: &str = "mpl-core-execute"; + +#[tokio::test] +async fn test_freeze_execute_backed_nft_flow() { + // ---------------------------------- + // 0. Test setup + // ---------------------------------- + let mut context = program_test().start_with_context().await; + + // Fund payer so we can deposit SOL to the asset later. + let payer_key = context.payer.pubkey(); + airdrop(&mut context, &payer_key, 2_000_000_000) + .await + .unwrap(); + + // ---------------------------------- + // 1. Mint an asset with FreezeExecute { frozen: true } + // ---------------------------------- + let asset = Keypair::new(); + create_asset( + &mut context, + CreateAssetHelperArgs { + owner: None, + payer: None, + asset: &asset, + data_state: None, + name: None, + uri: None, + authority: None, + update_authority: None, + collection: None, + plugins: vec![PluginAuthorityPair { + plugin: Plugin::FreezeExecute(FreezeExecute { frozen: true }), + authority: None, + }], + external_plugin_adapters: vec![], + }, + ) + .await + .unwrap(); + + assert_asset( + &mut context, + AssertAssetHelperArgs { + asset: asset.pubkey(), + owner: payer_key, + update_authority: None, + name: None, + uri: None, + plugins: vec![PluginAuthorityPair { + plugin: Plugin::FreezeExecute(FreezeExecute { frozen: true }), + authority: Some(PluginAuthority::Owner), + }], + external_plugin_adapters: vec![], + }, + ) + .await; + + // ---------------------------------- + // 2. Deposit backing SOL into the asset account (simulate 0.5 SOL backing) + // ---------------------------------- + let backing_amount: u64 = 500_000_000; // 0.5 SOL + let transfer_ix = system_instruction::transfer(&payer_key, &asset.pubkey(), backing_amount); + let tx = Transaction::new_signed_with_payer( + &[transfer_ix], + Some(&payer_key), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Capture lamports held by the asset account after deposit. + let asset_account_after_deposit = context + .banks_client + .get_account(asset.pubkey()) + .await + .expect("get_account") + .expect("asset account not found"); + let lamports_in_asset = asset_account_after_deposit.lamports; + + // ---------------------------------- + // 3. Attempt Execute → should fail because plugin is frozen. + // ---------------------------------- + let (asset_signer, _) = Pubkey::find_program_address( + &[FREEZE_EXECUTE_PREFIX.as_bytes(), asset.pubkey().as_ref()], + &mpl_core::ID, + ); + + let execute_ix = ExecuteV1Builder::new() + .asset(asset.pubkey()) + .collection(None) + .asset_signer(asset_signer) + .payer(payer_key, true) + .authority(Some(payer_key)) + .system_program(system_program::ID) + .program_id(system_program::ID) // use system program as harmless target + .instruction_data(Vec::new()) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[execute_ix], + Some(&payer_key), + &[&context.payer], + context.last_blockhash, + ); + + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + assert_custom_instruction_error!(0, error, MplCoreError::InvalidAuthority); + + // ---------------------------------- + // 4. Burn the asset → user should receive lamports back, asset account closed. + // ---------------------------------- + // Record payer balance before burn. + let payer_balance_before_burn = context.banks_client.get_balance(payer_key).await.unwrap(); + + let burn_ix = BurnV1Builder::new() + .asset(asset.pubkey()) + .collection(None) + .payer(payer_key) + .authority(Some(payer_key)) + .system_program(Some(system_program::ID)) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[burn_ix], + Some(&payer_key), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Asset account should be closed or at least drained. + let _asset_account_after_burn = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap(); + + // Verify payer balance increased (should receive refund though exact amount may be reduced by rent/taxes). + let payer_balance_after_burn = context.banks_client.get_balance(payer_key).await.unwrap(); + + assert!( + payer_balance_after_burn > payer_balance_before_burn, + "Payer balance did not increase after burn refund" + ); +} diff --git a/clients/rust/tests/plugin_shrink_corruption.rs b/clients/rust/tests/plugin_shrink_corruption.rs new file mode 100644 index 00000000..0f305925 --- /dev/null +++ b/clients/rust/tests/plugin_shrink_corruption.rs @@ -0,0 +1,792 @@ +#![cfg(feature = "test-sbf")] +pub mod setup; + +use std::borrow::BorrowMut; + +use mpl_core::{ + accounts::BaseAssetV1, + fetch_external_plugin_adapter_data_info, + instructions::{ + AddExternalPluginAdapterV1Builder, UpdatePluginV1Builder, + WriteExternalPluginAdapterDataV1Builder, + }, + types::{ + AppDataInitInfo, Attribute, Attributes, ExternalPluginAdapterInitInfo, + ExternalPluginAdapterKey, ExternalPluginAdapterSchema, FreezeDelegate, Plugin, + PluginAuthority, PluginAuthorityPair, + }, + Asset, +}; +pub use setup::*; + +use solana_program::account_info::AccountInfo; +use solana_program_test::tokio; +use solana_sdk::{signature::Keypair, signer::Signer, transaction::Transaction}; + +// ============================================================================ +// Test 1: WriteExternalPluginAdapterDataV1 — regression test for shrinking the +// first of two AppData plugins. +// +// Previously, update_external_plugin_adapter_data() in plugins/utils.rs called +// resize_or_reallocate_account() before sol_memmove, so shrinking caused +// data_len() to return the new (smaller) size and saturating_sub yielded 0, +// moving nothing and corrupting trailing plugin data and/or the registry. +// +// The fix reorders: memmove first (while the buffer is full-size), then realloc. +// This test verifies the shrunk plugin, the trailing plugin, and the registry +// all survive intact. +// ============================================================================ +#[tokio::test] +async fn test_write_external_plugin_adapter_data_shrink_preserves_second_plugin() { + let mut context = program_test().start_with_context().await; + + // Step 1: Create an asset with TWO AppData plugins (different data authorities). + let owner = Keypair::new(); + airdrop(&mut context, &owner.pubkey(), 10_000_000_000) + .await + .unwrap(); + + let asset = Keypair::new(); + create_asset( + &mut context, + CreateAssetHelperArgs { + owner: Some(owner.pubkey()), + payer: None, + asset: &asset, + data_state: None, + name: None, + uri: None, + authority: None, + update_authority: None, + collection: None, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: Some(ExternalPluginAdapterSchema::Binary), + }, + )], + }, + ) + .await + .unwrap(); + + // Add a second AppData plugin keyed by Owner authority. + let ix = AddExternalPluginAdapterV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .init_info(ExternalPluginAdapterInitInfo::AppData(AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::Owner, + schema: Some(ExternalPluginAdapterSchema::Binary), + })) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Step 2: Write LARGE data (500 bytes) to the FIRST AppData plugin. + let large_data: Vec = (0..500).map(|i| (i % 256) as u8).collect(); + let ix = WriteExternalPluginAdapterDataV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .data(large_data.clone()) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Step 3: Write a known pattern to the SECOND AppData plugin. + let second_plugin_data: Vec = vec![0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF]; + let ix = WriteExternalPluginAdapterDataV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .authority(Some(owner.pubkey())) + .key(ExternalPluginAdapterKey::AppData(PluginAuthority::Owner)) + .data(second_plugin_data.clone()) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer, &owner], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Verify both plugins are readable before shrink. + let account_before = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_before = account_before.data.len(); + println!("Account size before shrink: {}", size_before); + + let asset_before = Asset::from_bytes(&account_before.data).unwrap(); + assert_eq!(asset_before.external_plugin_adapter_list.app_data.len(), 2); + + // Verify second plugin data is intact. + { + let mut account_copy = account_before.clone(); + let binding = asset.pubkey(); + let account_info = AccountInfo::new( + &binding, + false, + false, + &mut account_copy.lamports, + account_copy.data.borrow_mut(), + &account_copy.owner, + false, + ); + + let (data_offset, data_len) = fetch_external_plugin_adapter_data_info::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::Owner), + ) + .unwrap(); + + let data_slice = &account_copy.data[data_offset..data_offset + data_len]; + assert_eq!( + data_slice, &second_plugin_data, + "Second plugin data should be intact before shrink" + ); + } + + // Step 4: SHRINK the first AppData from 500 bytes to 5 bytes. + // This exercises the memmove-before-realloc path for a large shrink (495 + // bytes). The trailing plugin data and registry must be shifted left before + // the account is truncated. + let small_data: Vec = vec![0x01, 0x02, 0x03, 0x04, 0x05]; + let ix = WriteExternalPluginAdapterDataV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .data(small_data.clone()) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context.banks_client.process_transaction(tx).await.unwrap(); + + // Step 5: Verify the asset is still intact after shrink. + let account_after = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_after = account_after.data.len(); + assert!( + size_after < size_before, + "Expected account to shrink from {} to {}, but it did not", + size_before, + size_after + ); + + // Deserialize the asset — should not fail. + let asset_after = Asset::from_bytes(&account_after.data) + .expect("Asset deserialization should succeed after shrink — registry must remain intact"); + + // Both AppData plugins should still be present. + assert_eq!( + asset_after.external_plugin_adapter_list.app_data.len(), + 2, + "Both AppData plugins should survive the shrink" + ); + + // Second plugin's data should be readable and unchanged. + { + let mut account_copy = account_after.clone(); + let binding = asset.pubkey(); + let account_info = AccountInfo::new( + &binding, + false, + false, + &mut account_copy.lamports, + account_copy.data.borrow_mut(), + &account_copy.owner, + false, + ); + + let (data_offset, data_len) = fetch_external_plugin_adapter_data_info::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::Owner), + ) + .expect("Should be able to fetch second plugin data after shrink"); + + assert!( + data_offset + data_len <= account_after.data.len(), + "Second plugin data out of bounds: offset={} len={} account_size={}", + data_offset, + data_len, + account_after.data.len() + ); + + let actual_data = &account_after.data[data_offset..data_offset + data_len]; + assert_eq!( + actual_data, &second_plugin_data, + "Second plugin data must be unchanged after shrinking the first plugin" + ); + } + + // First plugin's data should now equal the shrunk payload. + { + let mut account_copy = account_after.clone(); + let binding = asset.pubkey(); + let account_info = AccountInfo::new( + &binding, + false, + false, + &mut account_copy.lamports, + account_copy.data.borrow_mut(), + &account_copy.owner, + false, + ); + + let (data_offset, data_len) = fetch_external_plugin_adapter_data_info::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .expect("Should be able to fetch first plugin data after shrink"); + + assert!( + data_offset + data_len <= account_after.data.len(), + "First plugin data out of bounds: offset={} len={} account_size={}", + data_offset, + data_len, + account_after.data.len() + ); + + let actual_data = &account_after.data[data_offset..data_offset + data_len]; + assert_eq!( + actual_data, &small_data, + "First plugin data must equal the shrunk payload" + ); + } +} + +// ============================================================================ +// Test 2: UpdatePluginV1 — regression test for shrinking an Attributes plugin +// when a FreezeDelegate plugin follows it. +// +// Previously, process_update_plugin() in processor/update_plugin.rs called +// resize_or_reallocate_account() before sol_memmove, so on shrink the memmove +// source region could extend beyond the new (truncated) account boundary. +// +// The fix reorders: memmove first (reads from the full-size buffer), then +// realloc. This test verifies the Attributes content, the trailing +// FreezeDelegate, and the registry all survive intact. +// ============================================================================ +#[tokio::test] +async fn test_update_plugin_shrink_attributes_preserves_trailing_plugins() { + let mut context = program_test().start_with_context().await; + + // Step 1: Create an asset with a LARGE Attributes plugin and a FreezeDelegate. + // Attributes is variable-size (Vec), so we can shrink it. + let asset = Keypair::new(); + + // Create with many attributes to make it large. + let large_attributes: Vec = (0..30) + .map(|i| Attribute { + key: format!("key_{:03}", i), + value: format!( + "value_{:03}_padding_to_make_this_larger_{}", + i, + "x".repeat(20) + ), + }) + .collect(); + + create_asset( + &mut context, + CreateAssetHelperArgs { + owner: None, + payer: None, + asset: &asset, + data_state: None, + name: None, + uri: None, + authority: None, + update_authority: None, + collection: None, + plugins: vec![ + PluginAuthorityPair { + plugin: Plugin::Attributes(Attributes { + attribute_list: large_attributes.clone(), + }), + authority: None, + }, + PluginAuthorityPair { + plugin: Plugin::FreezeDelegate(FreezeDelegate { frozen: false }), + authority: None, + }, + ], + external_plugin_adapters: vec![], + }, + ) + .await + .unwrap(); + + // Verify initial state. + let account_before = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_before = account_before.data.len(); + println!("Account size before shrink: {}", size_before); + + let asset_before = Asset::from_bytes(&account_before.data).unwrap(); + assert!(asset_before.plugin_list.freeze_delegate.is_some()); + let attrs = asset_before.plugin_list.attributes.as_ref().unwrap(); + assert_eq!(attrs.attributes.attribute_list.len(), 30); + + // Step 2: Update Attributes to have very few attributes (massive shrink). + let small_attributes = vec![Attribute { + key: "x".to_string(), + value: "y".to_string(), + }]; + + let ix = UpdatePluginV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .plugin(Plugin::Attributes(Attributes { + attribute_list: small_attributes.clone(), + })) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context + .banks_client + .process_transaction(tx) + .await + .expect("Attributes shrink transaction should succeed"); + + // Step 3: Verify the asset is still fully readable and FreezeDelegate intact. + let account_after = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_after = account_after.data.len(); + assert!( + size_after < size_before, + "Expected account to shrink from {} to {}, but it did not", + size_before, + size_after + ); + + let asset_after = Asset::from_bytes(&account_after.data) + .expect("Asset deserialization should succeed after Attributes shrink"); + + // Check Attributes has the exact expected content. + let attrs_after = asset_after + .plugin_list + .attributes + .as_ref() + .expect("Attributes plugin must still be present after shrink"); + assert_eq!( + attrs_after.attributes.attribute_list.len(), + 1, + "Attributes should have exactly 1 entry after update" + ); + assert_eq!(attrs_after.attributes.attribute_list[0].key, "x"); + assert_eq!(attrs_after.attributes.attribute_list[0].value, "y"); + + // Check FreezeDelegate is still intact. + let fd = asset_after + .plugin_list + .freeze_delegate + .as_ref() + .expect("FreezeDelegate must still be present after Attributes shrink"); + assert_eq!( + fd.freeze_delegate, + FreezeDelegate { frozen: false }, + "FreezeDelegate should be unchanged" + ); +} + +// ============================================================================ +// Test 3: WriteExternalPluginAdapterDataV1 — shrink with a single AppData +// plugin (regression/coverage guard). +// +// With only one AppData plugin, sol_memmove has no trailing plugin data to +// shift — the tail length is just the registry, which is re-serialized from +// the in-memory PluginRegistryV1 after the move anyway. So this case does +// not exercise the specific realloc-before-memmove corruption path that +// multi-plugin layouts hit. It still guards against shrink-related regressions +// (e.g. incorrect new_size, data_offset math, or registry save errors). +// ============================================================================ +#[tokio::test] +async fn test_write_external_plugin_adapter_data_single_plugin_shrink() { + let mut context = program_test().start_with_context().await; + + let asset = Keypair::new(); + create_asset( + &mut context, + CreateAssetHelperArgs { + owner: None, + payer: None, + asset: &asset, + data_state: None, + name: None, + uri: None, + authority: None, + update_authority: None, + collection: None, + plugins: vec![], + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: Some(ExternalPluginAdapterSchema::Binary), + }, + )], + }, + ) + .await + .unwrap(); + + // Write large data. + let large_data: Vec = vec![0xAB; 800]; + let ix = WriteExternalPluginAdapterDataV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .data(large_data.clone()) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Verify pre-shrink. + let account_before = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_before = account_before.data.len(); + println!("Account size before shrink: {}", size_before); + + let asset_before = Asset::from_bytes(&account_before.data).unwrap(); + assert_eq!(asset_before.external_plugin_adapter_list.app_data.len(), 1); + + // Shrink to tiny data. + let small_data: Vec = vec![0x01]; + let ix = WriteExternalPluginAdapterDataV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .data(small_data.clone()) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context + .banks_client + .process_transaction(tx) + .await + .expect("Shrink transaction should succeed — program must handle shrinking gracefully"); + + // Verify post-shrink: can we still deserialize and read the data? + let account_after = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_after = account_after.data.len(); + assert!( + size_after < size_before, + "Expected account to shrink from {} to {}, but it did not", + size_before, + size_after + ); + + let asset_after = Asset::from_bytes(&account_after.data) + .expect("Asset deserialization should succeed after single-plugin shrink"); + + assert_eq!( + asset_after.external_plugin_adapter_list.app_data.len(), + 1, + "AppData plugin must still be present after shrink" + ); + + // Verify the data content matches what we wrote. + { + let mut account_copy = account_after.clone(); + let binding = asset.pubkey(); + let account_info = AccountInfo::new( + &binding, + false, + false, + &mut account_copy.lamports, + account_copy.data.borrow_mut(), + &account_copy.owner, + false, + ); + + let (data_offset, data_len) = fetch_external_plugin_adapter_data_info::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .expect("Should be able to fetch AppData after single-plugin shrink"); + + assert!( + data_offset + data_len <= account_after.data.len(), + "AppData region out of bounds: offset={} len={} account_size={}", + data_offset, + data_len, + account_after.data.len() + ); + + let actual = &account_after.data[data_offset..data_offset + data_len]; + assert_eq!( + actual, &small_data, + "AppData content must match the shrunk payload" + ); + } +} + +// ============================================================================ +// Test 4: UpdatePluginV1 — regression test for shrinking an Attributes plugin +// when an AppData external plugin is also present. +// +// Previously, process_update_plugin() in processor/update_plugin.rs called +// resize_or_reallocate_account() before sol_memmove, so on shrink the +// memmove's source region could extend beyond the truncated account boundary, +// corrupting the external plugin data stored after Attributes. +// +// The fix reorders: memmove first, then realloc. This test verifies the +// Attributes content, the trailing AppData plugin, and the registry all +// survive intact. +// ============================================================================ +#[tokio::test] +async fn test_update_plugin_shrink_attributes_preserves_external_plugin() { + let mut context = program_test().start_with_context().await; + + let asset = Keypair::new(); + + // Create with large Attributes + an AppData external plugin. + let large_attributes: Vec = (0..25) + .map(|i| Attribute { + key: format!("attr_{:03}", i), + value: format!("val_{:03}_{}", i, "abcdefghijklmnopqrstuvwxyz".repeat(2)), + }) + .collect(); + + create_asset( + &mut context, + CreateAssetHelperArgs { + owner: None, + payer: None, + asset: &asset, + data_state: None, + name: None, + uri: None, + authority: None, + update_authority: None, + collection: None, + plugins: vec![PluginAuthorityPair { + plugin: Plugin::Attributes(Attributes { + attribute_list: large_attributes.clone(), + }), + authority: None, + }], + external_plugin_adapters: vec![ExternalPluginAdapterInitInfo::AppData( + AppDataInitInfo { + init_plugin_authority: Some(PluginAuthority::UpdateAuthority), + data_authority: PluginAuthority::UpdateAuthority, + schema: Some(ExternalPluginAdapterSchema::Binary), + }, + )], + }, + ) + .await + .unwrap(); + + // Write data to AppData. + let app_data_content: Vec = vec![0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0xFE]; + let ix = WriteExternalPluginAdapterDataV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .key(ExternalPluginAdapterKey::AppData( + PluginAuthority::UpdateAuthority, + )) + .data(app_data_content.clone()) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + context.banks_client.process_transaction(tx).await.unwrap(); + + // Verify pre-shrink state. + let account_before = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_before = account_before.data.len(); + + let asset_before = Asset::from_bytes(&account_before.data).unwrap(); + assert!(asset_before.plugin_list.attributes.is_some()); + assert_eq!(asset_before.external_plugin_adapter_list.app_data.len(), 1); + println!("Account size before shrink: {}", size_before); + + // Shrink Attributes drastically. + let small_attributes = vec![Attribute { + key: "a".to_string(), + value: "b".to_string(), + }]; + + let ix = UpdatePluginV1Builder::new() + .asset(asset.pubkey()) + .payer(context.payer.pubkey()) + .plugin(Plugin::Attributes(Attributes { + attribute_list: small_attributes, + })) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer], + context.last_blockhash, + ); + + context + .banks_client + .process_transaction(tx) + .await + .expect("Attributes shrink transaction should succeed"); + + // Verify post-shrink. + let account_after = context + .banks_client + .get_account(asset.pubkey()) + .await + .unwrap() + .unwrap(); + let size_after = account_after.data.len(); + assert!( + size_after < size_before, + "Expected account to shrink from {} to {}, but it did not", + size_before, + size_after + ); + + let asset_after = Asset::from_bytes(&account_after.data) + .expect("Asset deserialization should succeed after Attributes shrink"); + + // Check Attributes has the exact expected content. + let attrs_after = asset_after + .plugin_list + .attributes + .as_ref() + .expect("Attributes plugin must still be present after shrink"); + assert_eq!( + attrs_after.attributes.attribute_list.len(), + 1, + "Attributes should have exactly 1 entry after update" + ); + assert_eq!(attrs_after.attributes.attribute_list[0].key, "a"); + assert_eq!(attrs_after.attributes.attribute_list[0].value, "b"); + + // Verify AppData external plugin is still present. + assert_eq!( + asset_after.external_plugin_adapter_list.app_data.len(), + 1, + "AppData plugin must still be present after Attributes shrink" + ); + + // Verify the AppData content is unchanged. + { + let mut account_copy = account_after.clone(); + let binding = asset.pubkey(); + let account_info = AccountInfo::new( + &binding, + false, + false, + &mut account_copy.lamports, + account_copy.data.borrow_mut(), + &account_copy.owner, + false, + ); + + let (data_offset, data_len) = fetch_external_plugin_adapter_data_info::( + &account_info, + None, + &ExternalPluginAdapterKey::AppData(PluginAuthority::UpdateAuthority), + ) + .expect("Should be able to fetch AppData after Attributes shrink"); + + assert!( + data_offset + data_len <= account_after.data.len(), + "AppData region out of bounds: offset={} len={} account_size={}", + data_offset, + data_len, + account_after.data.len() + ); + + let actual = &account_after.data[data_offset..data_offset + data_len]; + assert_eq!( + actual, &app_data_content, + "AppData content must be unchanged after Attributes shrink" + ); + } +} diff --git a/clients/rust/tests/plugins.rs b/clients/rust/tests/plugins.rs index fa658ecc..afbbce09 100644 --- a/clients/rust/tests/plugins.rs +++ b/clients/rust/tests/plugins.rs @@ -106,7 +106,6 @@ async fn test_fetch_plugin() { &mut asset_account.data, &asset_account.owner, false, - 1_000_000_000, ); let plugin = diff --git a/clients/rust/tests/setup/mod.rs b/clients/rust/tests/setup/mod.rs index 18dbe9e8..1b3de425 100644 --- a/clients/rust/tests/setup/mod.rs +++ b/clients/rust/tests/setup/mod.rs @@ -7,10 +7,8 @@ use mpl_core::{ Asset, Collection, }; use solana_program_test::{BanksClientError, ProgramTest, ProgramTestContext}; -use solana_sdk::{ - pubkey::Pubkey, signature::Keypair, signer::Signer, system_instruction, system_program, - transaction::Transaction, -}; +use solana_sdk::{pubkey::Pubkey, signature::Keypair, signer::Signer, transaction::Transaction}; +use solana_system_interface::{instruction as system_instruction, program as system_program}; pub fn program_test() -> ProgramTest { ProgramTest::new("mpl_core_program", mpl_core::ID, None) @@ -118,6 +116,16 @@ pub async fn assert_asset(context: &mut ProgramTestContext, input: AssertAssetHe } assert_eq!(plugin.freeze_delegate, freeze); } + PluginAuthorityPair { + plugin: Plugin::FreezeExecute(freeze_execute), + authority, + } => { + let plugin = asset.plugin_list.freeze_execute.clone().unwrap(); + if let Some(authority) = authority { + assert_eq!(plugin.base.authority, authority.into()); + } + assert_eq!(plugin.freeze_execute, freeze_execute); + } PluginAuthorityPair { plugin: Plugin::Royalties(royalties), authority, @@ -137,6 +145,7 @@ pub async fn assert_asset(context: &mut ProgramTestContext, input: AssertAssetHe asset.external_plugin_adapter_list.lifecycle_hooks.len() + asset.external_plugin_adapter_list.oracles.len() + asset.external_plugin_adapter_list.app_data.len() + + asset.external_plugin_adapter_list.agent_identities.len() ); for plugin in input.external_plugin_adapters { match plugin { @@ -176,6 +185,12 @@ pub async fn assert_asset(context: &mut ProgramTestContext, input: AssertAssetHe .iter() .any(|data_sections_with_data| data_sections_with_data.base == data)) } + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + assert!(asset + .external_plugin_adapter_list + .agent_identities + .contains(&agent_identity)) + } } } } @@ -272,6 +287,16 @@ pub async fn assert_collection( } assert_eq!(plugin.freeze_delegate, freeze); } + PluginAuthorityPair { + plugin: Plugin::FreezeExecute(freeze_execute), + authority, + } => { + let plugin = collection.plugin_list.freeze_execute.clone().unwrap(); + if let Some(authority) = authority { + assert_eq!(plugin.base.authority, authority.into()); + } + assert_eq!(plugin.freeze_execute, freeze_execute); + } PluginAuthorityPair { plugin: Plugin::Royalties(royalties), authority, @@ -294,6 +319,10 @@ pub async fn assert_collection( .len() + collection.external_plugin_adapter_list.oracles.len() + collection.external_plugin_adapter_list.app_data.len() + + collection + .external_plugin_adapter_list + .agent_identities + .len() ); for plugin in input.external_plugin_adapters { match plugin { @@ -336,6 +365,12 @@ pub async fn assert_collection( .iter() .any(|data_sections_with_data| data_sections_with_data.base == data)) } + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + assert!(collection + .external_plugin_adapter_list + .agent_identities + .contains(&agent_identity)) + } } } } diff --git a/clients/rust/tests/update_collection_info.rs b/clients/rust/tests/update_collection_info.rs new file mode 100644 index 00000000..1d6763bb --- /dev/null +++ b/clients/rust/tests/update_collection_info.rs @@ -0,0 +1,115 @@ +#![cfg(feature = "test-sbf")] +pub mod setup; +use mpl_core::{ + errors::MplCoreError, instructions::UpdateCollectionInfoV1Builder, types::UpdateType, +}; +pub use setup::*; + +use solana_program::pubkey::Pubkey; +use solana_program_test::tokio; +use solana_sdk::{pubkey, signature::Keypair, signer::Signer, transaction::Transaction}; +use solana_system_interface::instruction::create_account; + +pub const BUBBLEGUM_PROGRAM_ADDRESS: Pubkey = + pubkey!("BGUMAp9Gq7iTEuizy4pqaxsTyUCBK68MDfK752saRPUY"); + +#[tokio::test] +async fn test_cannot_update_collection_info_with_incorrect_signer() { + let mut context = program_test().start_with_context().await; + + let collection = Keypair::new(); + create_collection( + &mut context, + CreateCollectionHelperArgs { + collection: &collection, + update_authority: None, + payer: None, + name: None, + uri: None, + plugins: vec![], + external_plugin_adapters: vec![], + }, + ) + .await + .unwrap(); + + let update_authority = context.payer.pubkey(); + assert_collection( + &mut context, + AssertCollectionHelperArgs { + collection: collection.pubkey(), + update_authority, + name: None, + uri: None, + num_minted: 0, + current_size: 0, + plugins: vec![], + external_plugin_adapters: vec![], + }, + ) + .await; + + // Create a fake Bubblegum signer which is a normal keypair owned by the Bubblegum + // program. + let fake_bubblegum_signer = Keypair::new(); + let lamports = context + .banks_client + .get_rent() + .await + .unwrap() + .minimum_balance(0); + + let ix = create_account( + &context.payer.pubkey(), + &fake_bubblegum_signer.pubkey(), + lamports, + 0, + &BUBBLEGUM_PROGRAM_ADDRESS, + ); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer, &fake_bubblegum_signer], + context.last_blockhash, + ); + + context.banks_client.process_transaction(tx).await.unwrap(); + + // Verify the fake Bubblegum signer is owned by the Bubblegum program. + let fake_bubblegum_signer_account = context + .banks_client + .get_account(fake_bubblegum_signer.pubkey()) + .await + .expect("get_account") + .expect("fake Bubblegum signer account not found"); + + assert_eq!( + fake_bubblegum_signer_account.owner, + BUBBLEGUM_PROGRAM_ADDRESS + ); + assert_eq!(fake_bubblegum_signer_account.data.len(), 0); + + // Verify that calling `UpdateCollectionInfoV1` with the fake signer results in an error. + let ix = UpdateCollectionInfoV1Builder::new() + .collection(collection.pubkey()) + .bubblegum_signer(fake_bubblegum_signer.pubkey()) + .update_type(UpdateType::Mint) + .amount(1) + .instruction(); + + let tx = Transaction::new_signed_with_payer( + &[ix], + Some(&context.payer.pubkey()), + &[&context.payer, &fake_bubblegum_signer], + context.last_blockhash, + ); + + let error = context + .banks_client + .process_transaction(tx) + .await + .unwrap_err(); + + assert_custom_instruction_error!(0, error, MplCoreError::InvalidAuthority); +} diff --git a/configs/kinobi.cjs b/configs/kinobi.cjs index 89571440..d26a2602 100755 --- a/configs/kinobi.cjs +++ b/configs/kinobi.cjs @@ -10,336 +10,416 @@ const kinobi = k.createFromIdls([path.join(idlDir, "mpl_core.json")]); // Update programs. kinobi.update( - k.updateProgramsVisitor({ - mplCoreProgram: { name: "mplCore" }, - }) + k.updateProgramsVisitor({ + mplCoreProgram: { name: "mplCore" }, + }) ); // Append empty signer accounts. kinobi.update( - new k.bottomUpTransformerVisitor([{ - select: ['[programNode]', node => 'name' in node && node.name === "mplCore"], - transform: (node) => { - return k.programNode({ - ...node, - accounts: [ - ...node.accounts, - k.accountNode({ - name: "assetSigner", - size: 0, - data: k.structTypeNode([ - k.structFieldTypeNode({ - name: "data", - type: k.bytesTypeNode(k.remainderSizeNode()), - }) - ]), - }), - ], - }); - }, - }]) + new k.bottomUpTransformerVisitor([ + { + select: [ + "[programNode]", + (node) => "name" in node && node.name === "mplCore", + ], + transform: (node) => { + return k.programNode({ + ...node, + accounts: [ + ...node.accounts, + k.accountNode({ + name: "assetSigner", + size: 0, + data: k.structTypeNode([ + k.structFieldTypeNode({ + name: "data", + type: k.bytesTypeNode( + k.remainderSizeNode() + ), + }), + ]), + }), + ], + }); + }, + }, + ]) ); - kinobi.update( - new k.updateAccountsVisitor({ - assetV1: { - name: "baseAssetV1", - }, - collectionV1: { - name: "baseCollectionV1", - }, - assetSigner: { - size: 0, - seeds: [ - k.constantPdaSeedNodeFromString("mpl-core-execute"), - k.variablePdaSeedNode( - "asset", - k.publicKeyTypeNode(), - "The address of the asset account" - ), - ], - }, - }) + new k.updateAccountsVisitor({ + assetV1: { + name: "baseAssetV1", + }, + collectionV1: { + name: "baseCollectionV1", + }, + assetSigner: { + size: 0, + seeds: [ + k.constantPdaSeedNodeFromString("mpl-core-execute"), + k.variablePdaSeedNode( + "asset", + k.publicKeyTypeNode(), + "The address of the asset account" + ), + ], + }, + }) ); -kinobi.update(new k.updateDefinedTypesVisitor({ - authority: { - name: "pluginAuthority" - } -})) +kinobi.update( + new k.updateDefinedTypesVisitor({ + authority: { + name: "pluginAuthority", + }, + crate: { + name: "relationshipEntry", + }, + }) +); // Update instructions with default values kinobi.update( - k.updateInstructionsVisitor({ - // create: { - // bytesCreatedOnChain: k.bytesFromAccount("assetAccount"), - // }, - transferV1: { - arguments: { - compressionProof: { - defaultValue: k.noneValueNode() - } - } - }, - addPluginV1: { - arguments: { - initAuthority: { - defaultValue: k.noneValueNode() - } - } - }, - addCollectionPluginV1: { - arguments: { - initAuthority: { - defaultValue: k.noneValueNode() - } - } - }, - burnV1: { - arguments: { - compressionProof: { - defaultValue: k.noneValueNode() - } - } - }, - createV1: { - arguments: { - plugins: { - defaultValue: k.arrayValueNode([]) - }, - dataState: { - defaultValue: k.enumValueNode('DataState', 'AccountState') - } - } - }, - createV2: { - arguments: { - plugins: { - defaultValue: k.arrayValueNode([]) - }, - externalPluginAdapters: { - defaultValue: k.arrayValueNode([]) - }, - dataState: { - defaultValue: k.enumValueNode('DataState', 'AccountState') - } - } - }, - createCollectionV1: { - arguments: { - plugins: { - defaultValue: k.noneValueNode() - } - } - }, - createCollectionV2: { - arguments: { - plugins: { - defaultValue: k.noneValueNode() - }, - externalPluginAdapters: { - defaultValue: k.arrayValueNode([]) - }, - } - }, - collect: { - accounts: { - recipient1: { - defaultValue: k.publicKeyValueNode("8AT6o8Qk5T9QnZvPThMrF9bcCQLTGkyGvVZZzHgCw11v") - }, - recipient2: { - defaultValue: k.publicKeyValueNode("MmHsqX4LxTfifxoH8BVRLUKrwDn1LPCac6YcCZTHhwt") - } - } - }, - updateV1: { - arguments: { - newUpdateAuthority: { - defaultValue: k.noneValueNode() - }, - newName: { - defaultValue: k.noneValueNode() - }, - newUri: { - defaultValue: k.noneValueNode() - }, - } - }, - updateV2: { - arguments: { - newUpdateAuthority: { - defaultValue: k.noneValueNode() - }, - newName: { - defaultValue: k.noneValueNode() - }, - newUri: { - defaultValue: k.noneValueNode() - }, - } - }, - updateCollectionV1: { - arguments: { - newName: { - defaultValue: k.noneValueNode() - }, - newUri: { - defaultValue: k.noneValueNode() - }, - } - }, - executeV1: { - accounts: { - assetSigner: { - defaultValue: k.pdaValueNode("assetSigner") - } - } - }, - }) + k.updateInstructionsVisitor({ + // create: { + // bytesCreatedOnChain: k.bytesFromAccount("assetAccount"), + // }, + transferV1: { + arguments: { + compressionProof: { + defaultValue: k.noneValueNode(), + }, + }, + }, + addPluginV1: { + arguments: { + initAuthority: { + defaultValue: k.noneValueNode(), + }, + }, + }, + addCollectionPluginV1: { + arguments: { + initAuthority: { + defaultValue: k.noneValueNode(), + }, + }, + }, + burnV1: { + arguments: { + compressionProof: { + defaultValue: k.noneValueNode(), + }, + }, + }, + createV1: { + arguments: { + plugins: { + defaultValue: k.arrayValueNode([]), + }, + dataState: { + defaultValue: k.enumValueNode("DataState", "AccountState"), + }, + }, + }, + createV2: { + arguments: { + plugins: { + defaultValue: k.arrayValueNode([]), + }, + externalPluginAdapters: { + defaultValue: k.arrayValueNode([]), + }, + dataState: { + defaultValue: k.enumValueNode("DataState", "AccountState"), + }, + }, + }, + createCollectionV1: { + arguments: { + plugins: { + defaultValue: k.noneValueNode(), + }, + }, + }, + createCollectionV2: { + arguments: { + plugins: { + defaultValue: k.noneValueNode(), + }, + externalPluginAdapters: { + defaultValue: k.arrayValueNode([]), + }, + }, + }, + createGroupV1: { + arguments: { + relationships: { + // defaultValue: k.arrayValueNode([]), + }, + }, + }, + addGroupsToGroupV1: { + arguments: { + groups: { + // defaultValue: k.arrayValueNode([]), + }, + }, + }, + removeGroupsFromGroupV1: { + arguments: { + groups: { + // defaultValue: k.arrayValueNode([]), + }, + }, + }, + removeAssetsFromGroupV1: { + arguments: { + assets: { + // defaultValue: k.arrayValueNode([]), + }, + }, + }, + removeCollectionsFromGroupV1: { + arguments: { + collections: { + // defaultValue: k.arrayValueNode([]), + }, + }, + }, + updateGroupV1: { + arguments: { + newName: { + defaultValue: k.noneValueNode(), + }, + newUri: { + defaultValue: k.noneValueNode(), + }, + }, + }, + collect: { + accounts: { + recipient1: { + defaultValue: k.publicKeyValueNode( + "8AT6o8Qk5T9QnZvPThMrF9bcCQLTGkyGvVZZzHgCw11v" + ), + }, + recipient2: { + defaultValue: k.publicKeyValueNode( + "MmHsqX4LxTfifxoH8BVRLUKrwDn1LPCac6YcCZTHhwt" + ), + }, + }, + }, + updateV1: { + arguments: { + newUpdateAuthority: { + defaultValue: k.noneValueNode(), + }, + newName: { + defaultValue: k.noneValueNode(), + }, + newUri: { + defaultValue: k.noneValueNode(), + }, + }, + }, + updateV2: { + arguments: { + newUpdateAuthority: { + defaultValue: k.noneValueNode(), + }, + newName: { + defaultValue: k.noneValueNode(), + }, + newUri: { + defaultValue: k.noneValueNode(), + }, + }, + }, + updateCollectionV1: { + arguments: { + newName: { + defaultValue: k.noneValueNode(), + }, + newUri: { + defaultValue: k.noneValueNode(), + }, + }, + }, + executeV1: { + accounts: { + assetSigner: { + defaultValue: k.pdaValueNode("assetSigner"), + }, + }, + }, + }) ); // Set ShankAccount discriminator. const key = (name) => ({ field: "key", value: k.enumValueNode("Key", name) }); kinobi.update( - k.setAccountDiscriminatorFromFieldVisitor({ - assetV1: key("AssetV1"), - collectionV1: key("CollectionV1"), - }) + k.setAccountDiscriminatorFromFieldVisitor({ + assetV1: key("AssetV1"), + collectionV1: key("CollectionV1"), + groupV1: key("GroupV1"), + }) ); // Render Rust. const crateDir = path.join(clientDir, "rust"); const rustDir = path.join(clientDir, "rust", "src", "generated"); kinobi.accept( - k.renderRustVisitor(rustDir, { - formatCode: true, - crateFolder: crateDir, - }) + k.renderRustVisitor(rustDir, { + formatCode: true, + crateFolder: crateDir, + renderParentInstructions: true, + }) ); - // rewrite the account names for custom account data kinobi.update( - new k.updateAccountsVisitor({ - baseAssetV1: { - name: "assetV1", - }, - baseCollectionV1: { - name: "collectionV1", - } - }) + new k.updateAccountsVisitor({ + baseAssetV1: { + name: "assetV1", + }, + baseCollectionV1: { + name: "collectionV1", + }, + }) ); kinobi.update( - new k.updateDefinedTypesVisitor({ - ruleSet: { - name: "baseRuleSet" - }, - royalties: { - name: "baseRoyalties" - }, - pluginAuthority: { - name: "basePluginAuthority" - }, - updateAuthority: { - name: "baseUpdateAuthority" - }, - seed: { - name: "baseSeed" - }, - extraAccount: { - name: "baseExtraAccount" - }, - externalPluginAdapterKey: { - name: "baseExternalPluginAdapterKey" - }, - linkedDataKey: { - name: 'baseLinkedDataKey' - }, - externalPluginAdapterInitInfo: { - name: "baseExternalPluginAdapterInitInfo" - }, - externalPluginAdapterUpdateInfo: { - name: "baseExternalPluginAdapterUpdateInfo" - }, - oracle: { - name: "baseOracle" - }, - oracleInitInfo: { - name: "baseOracleInitInfo" - }, - oracleUpdateInfo: { - name: "baseOracleUpdateInfo" - }, - lifecycleHook: { - name: "baseLifecycleHook" - }, - lifecycleHookInitInfo: { - name: "baseLifecycleHookInitInfo" - }, - lifecycleHookUpdateInfo: { - name: "baseLifecycleHookUpdateInfo" - }, - linkedLifecycleHook: { - name: "baseLinkedLifecycleHook" - }, - linkedLifecycleHookInitInfo: { - name: "baseLinkedLifecycleHookInitInfo" - }, - linkedLifecycleHookUpdateInfo: { - name: "baseLinkedLifecycleHookUpdateInfo" - }, - appData: { - name: "baseAppData" - }, - appDataInitInfo: { - name: "baseAppDataInitInfo" - }, - appDataUpdateInfo: { - name: "baseAppDataUpdateInfo" - }, - linkedAppData: { - name: "baseLinkedAppData" - }, - linkedAppDataInitInfo: { - name: "baseLinkedAppDataInitInfo" - }, - linkedAppDataUpdateInfo: { - name: "baseLinkedAppDataUpdateInfo" - }, - dataSection: { - name: "baseDataSection" - }, - dataSectionInitInfo: { - name: "baseDataSectionInitInfo" - }, - dataSectionUpdateInfo: { - name: "baseDataSectionUpdateInfo" - }, - validationResultsOffset: { - name: "baseValidationResultsOffset" - }, - masterEdition: { - name: "baseMasterEdition" - } - }) -) + new k.updateDefinedTypesVisitor({ + ruleSet: { + name: "baseRuleSet", + }, + royalties: { + name: "baseRoyalties", + }, + pluginAuthority: { + name: "basePluginAuthority", + }, + updateAuthority: { + name: "baseUpdateAuthority", + }, + seed: { + name: "baseSeed", + }, + extraAccount: { + name: "baseExtraAccount", + }, + externalPluginAdapterKey: { + name: "baseExternalPluginAdapterKey", + }, + linkedDataKey: { + name: "baseLinkedDataKey", + }, + externalPluginAdapterInitInfo: { + name: "baseExternalPluginAdapterInitInfo", + }, + externalPluginAdapterUpdateInfo: { + name: "baseExternalPluginAdapterUpdateInfo", + }, + oracle: { + name: "baseOracle", + }, + oracleInitInfo: { + name: "baseOracleInitInfo", + }, + oracleUpdateInfo: { + name: "baseOracleUpdateInfo", + }, + lifecycleHook: { + name: "baseLifecycleHook", + }, + lifecycleHookInitInfo: { + name: "baseLifecycleHookInitInfo", + }, + lifecycleHookUpdateInfo: { + name: "baseLifecycleHookUpdateInfo", + }, + linkedLifecycleHook: { + name: "baseLinkedLifecycleHook", + }, + linkedLifecycleHookInitInfo: { + name: "baseLinkedLifecycleHookInitInfo", + }, + linkedLifecycleHookUpdateInfo: { + name: "baseLinkedLifecycleHookUpdateInfo", + }, + appData: { + name: "baseAppData", + }, + appDataInitInfo: { + name: "baseAppDataInitInfo", + }, + appDataUpdateInfo: { + name: "baseAppDataUpdateInfo", + }, + linkedAppData: { + name: "baseLinkedAppData", + }, + linkedAppDataInitInfo: { + name: "baseLinkedAppDataInitInfo", + }, + linkedAppDataUpdateInfo: { + name: "baseLinkedAppDataUpdateInfo", + }, + dataSection: { + name: "baseDataSection", + }, + dataSectionInitInfo: { + name: "baseDataSectionInitInfo", + }, + dataSectionUpdateInfo: { + name: "baseDataSectionUpdateInfo", + }, + validationResultsOffset: { + name: "baseValidationResultsOffset", + }, + masterEdition: { + name: "baseMasterEdition", + }, + agentIdentity: { + name: "baseAgentIdentity", + }, + agentIdentityInitInfo: { + name: "baseAgentIdentityInitInfo", + }, + agentIdentityUpdateInfo: { + name: "baseAgentIdentityUpdateInfo", + }, + }) +); // Render JavaScript. const jsDir = path.join(clientDir, "js", "src", "generated"); const prettier = require(path.join(clientDir, "js", ".prettierrc.json")); -kinobi.accept(k.renderJavaScriptVisitor(jsDir, { - prettier, - internalNodes: [], - customAccountData: [{ - name: "assetV1", - extract: true, - }, { - name: "collectionV1", - extract: true, - }, { - name: "pluginRegistryV1", - extract: true, - }], -})); \ No newline at end of file +kinobi.accept( + k.renderJavaScriptVisitor(jsDir, { + prettier, + internalNodes: [], + customAccountData: [ + { + name: "assetV1", + extract: true, + }, + { + name: "collectionV1", + extract: true, + }, + { + name: "groupV1", + extract: true, + }, + { + name: "pluginRegistryV1", + extract: true, + }, + ], + }) +); diff --git a/idls/mpl_core.json b/idls/mpl_core.json index 5968c528..4691f532 100644 --- a/idls/mpl_core.json +++ b/idls/mpl_core.json @@ -1,5 +1,5 @@ { - "version": "0.1.0", + "version": "0.2.0", "name": "mpl_core_program", "instructions": [ { @@ -2038,18 +2038,410 @@ { "name": "payer", "isMut": true, + "isSigner": false, + "isOptionalSigner": true, + "docs": [ + "The account paying for the storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The owner or delegate of the asset" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + }, + { + "name": "programId", + "isMut": false, + "isSigner": false, + "docs": [ + "The program id of the instruction" + ] + } + ], + "args": [ + { + "name": "executeV1Args", + "type": { + "defined": "ExecuteV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 31 + } + }, + { + "name": "UpdateCollectionInfoV1", + "accounts": [ + { + "name": "collection", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the asset" + ] + }, + { + "name": "bubblegumSigner", + "isMut": false, + "isSigner": true, + "docs": [ + "Bubblegum PDA signer" + ] + } + ], + "args": [ + { + "name": "updateCollectionInfoV1Args", + "type": { + "defined": "UpdateCollectionInfoV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 32 + } + }, + { + "name": "AddCollectionsToGroupV1", + "accounts": [ + { + "name": "group", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the group to modify" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The group update authority and collection update authority or delegate" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + } + ], + "args": [ + { + "name": "addCollectionsToGroupV1Args", + "type": { + "defined": "AddCollectionsToGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 33 + } + }, + { + "name": "RemoveCollectionsFromGroupV1", + "accounts": [ + { + "name": "group", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the group to modify" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The group update authority and collection update authority or delegate" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + } + ], + "args": [ + { + "name": "removeCollectionsFromGroupV1Args", + "type": { + "defined": "RemoveCollectionsFromGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 34 + } + }, + { + "name": "AddAssetsToGroupV1", + "accounts": [ + { + "name": "group", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the group to modify" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The group update authority and asset update authority or delegate" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + } + ], + "args": [ + { + "name": "addAssetsToGroupV1Args", + "type": { + "defined": "AddAssetsToGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 35 + } + }, + { + "name": "RemoveAssetsFromGroupV1", + "accounts": [ + { + "name": "group", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the group to modify" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The group update authority and asset update authority or delegate" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + } + ], + "args": [ + { + "name": "removeAssetsFromGroupV1Args", + "type": { + "defined": "RemoveAssetsFromGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 36 + } + }, + { + "name": "AddGroupsToGroupV1", + "accounts": [ + { + "name": "parentGroup", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the parent group to modify" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The update authority of the parent and child groups" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + } + ], + "args": [ + { + "name": "addGroupsToGroupV1Args", + "type": { + "defined": "AddGroupsToGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 37 + } + }, + { + "name": "RemoveGroupsFromGroupV1", + "accounts": [ + { + "name": "parentGroup", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the parent group to modify" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The update authority of the parent and child groups" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" + ] + } + ], + "args": [ + { + "name": "removeGroupsFromGroupV1Args", + "type": { + "defined": "RemoveGroupsFromGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 38 + } + }, + { + "name": "CreateGroupV1", + "accounts": [ + { + "name": "group", + "isMut": true, "isSigner": true, "docs": [ - "The account paying for the storage fees" + "The address of the new group" ] }, { - "name": "authority", + "name": "updateAuthority", "isMut": false, "isSigner": true, "isOptional": true, "docs": [ - "The owner or delegate of the asset" + "The authority of the new group" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for the storage fees" ] }, { @@ -2059,27 +2451,120 @@ "docs": [ "The system program" ] + } + ], + "args": [ + { + "name": "createGroupV1Args", + "type": { + "defined": "CreateGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 39 + } + }, + { + "name": "CloseGroupV1", + "accounts": [ + { + "name": "group", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the group to close" + ] }, { - "name": "programId", + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account receiving reclaimed lamports" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The update authority of the group" + ] + } + ], + "args": [ + { + "name": "closeGroupV1Args", + "type": { + "defined": "CloseGroupV1Args" + } + } + ], + "discriminant": { + "type": "u8", + "value": 40 + } + }, + { + "name": "UpdateGroupV1", + "accounts": [ + { + "name": "group", + "isMut": true, + "isSigner": false, + "docs": [ + "The address of the group to update" + ] + }, + { + "name": "payer", + "isMut": true, + "isSigner": true, + "docs": [ + "The account paying for the storage fees" + ] + }, + { + "name": "authority", + "isMut": false, + "isSigner": true, + "isOptional": true, + "docs": [ + "The update authority of the group" + ] + }, + { + "name": "newUpdateAuthority", "isMut": false, "isSigner": false, + "isOptional": true, "docs": [ - "The program id of the instruction" + "The new update authority of the group" + ] + }, + { + "name": "systemProgram", + "isMut": false, + "isSigner": false, + "docs": [ + "The system program" ] } ], "args": [ { - "name": "executeV1Args", + "name": "updateGroupV1Args", "type": { - "defined": "ExecuteV1Args" + "defined": "UpdateGroupV1Args" } } ], "discriminant": { "type": "u8", - "value": 31 + "value": 41 } } ], @@ -2204,6 +2689,56 @@ ] } }, + { + "name": "GroupV1", + "type": { + "kind": "struct", + "fields": [ + { + "name": "key", + "type": { + "defined": "Key" + } + }, + { + "name": "updateAuthority", + "type": "publicKey" + }, + { + "name": "name", + "type": "string" + }, + { + "name": "uri", + "type": "string" + }, + { + "name": "collections", + "type": { + "vec": "publicKey" + } + }, + { + "name": "groups", + "type": { + "vec": "publicKey" + } + }, + { + "name": "parentGroups", + "type": { + "vec": "publicKey" + } + }, + { + "name": "assets", + "type": { + "vec": "publicKey" + } + } + ] + } + }, { "name": "HashedAssetV1", "type": { @@ -2251,6 +2786,84 @@ ] } }, + { + "name": "AgentIdentity", + "type": { + "kind": "struct", + "fields": [ + { + "name": "uri", + "type": "string" + } + ] + } + }, + { + "name": "AgentIdentityInitInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "uri", + "type": "string" + }, + { + "name": "initPluginAuthority", + "type": { + "option": { + "defined": "Authority" + } + } + }, + { + "name": "lifecycleChecks", + "type": { + "vec": { + "tuple": [ + { + "defined": "HookableLifecycleEvent" + }, + { + "defined": "ExternalCheckResult" + } + ] + } + } + } + ] + } + }, + { + "name": "AgentIdentityUpdateInfo", + "type": { + "kind": "struct", + "fields": [ + { + "name": "uri", + "type": { + "option": "string" + } + }, + { + "name": "lifecycleChecks", + "type": { + "option": { + "vec": { + "tuple": [ + { + "defined": "HookableLifecycleEvent" + }, + { + "defined": "ExternalCheckResult" + } + ] + } + } + } + } + ] + } + }, { "name": "AppData", "type": { @@ -2867,6 +3480,20 @@ ] } }, + { + "name": "Groups", + "type": { + "kind": "struct", + "fields": [ + { + "name": "groups", + "type": { + "vec": "publicKey" + } + } + ] + } + }, { "name": "ImmutableMetadata", "type": { @@ -3028,7 +3655,19 @@ } }, { - "name": "FreezeDelegate", + "name": "FreezeDelegate", + "type": { + "kind": "struct", + "fields": [ + { + "name": "frozen", + "type": "bool" + } + ] + } + }, + { + "name": "FreezeExecute", "type": { "kind": "struct", "fields": [ @@ -3046,6 +3685,13 @@ "fields": [] } }, + { + "name": "BubblegumV2", + "type": { + "kind": "struct", + "fields": [] + } + }, { "name": "Edition", "type": { @@ -3077,6 +3723,18 @@ ] } }, + { + "name": "PermanentFreezeExecute", + "type": { + "kind": "struct", + "fields": [ + { + "name": "frozen", + "type": "bool" + } + ] + } + }, { "name": "PermanentTransferDelegate", "type": { @@ -3173,6 +3831,20 @@ ] } }, + { + "name": "AddAssetsToGroupV1Args", + "type": { + "kind": "struct", + "fields": [] + } + }, + { + "name": "AddCollectionsToGroupV1Args", + "type": { + "kind": "struct", + "fields": [] + } + }, { "name": "AddExternalPluginAdapterV1Args", "type": { @@ -3201,6 +3873,20 @@ ] } }, + { + "name": "AddGroupsToGroupV1Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "groups", + "type": { + "vec": "publicKey" + } + } + ] + } + }, { "name": "AddPluginV1Args", "type": { @@ -3317,6 +4003,13 @@ ] } }, + { + "name": "CloseGroupV1Args", + "type": { + "kind": "struct", + "fields": [] + } + }, { "name": "CompressV1Args", "type": { @@ -3460,6 +4153,30 @@ ] } }, + { + "name": "CreateGroupV1Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "name", + "type": "string" + }, + { + "name": "uri", + "type": "string" + }, + { + "name": "relationships", + "type": { + "vec": { + "defined": "crate" + } + } + } + ] + } + }, { "name": "DecompressV1Args", "type": { @@ -3486,6 +4203,34 @@ ] } }, + { + "name": "RemoveAssetsFromGroupV1Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "assets", + "type": { + "vec": "publicKey" + } + } + ] + } + }, + { + "name": "RemoveCollectionsFromGroupV1Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "collections", + "type": { + "vec": "publicKey" + } + } + ] + } + }, { "name": "RemoveExternalPluginAdapterV1Args", "type": { @@ -3514,6 +4259,20 @@ ] } }, + { + "name": "RemoveGroupsFromGroupV1Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "groups", + "type": { + "vec": "publicKey" + } + } + ] + } + }, { "name": "RemovePluginV1Args", "type": { @@ -3662,6 +4421,24 @@ ] } }, + { + "name": "UpdateCollectionInfoV1Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "updateType", + "type": { + "defined": "UpdateType" + } + }, + { + "name": "amount", + "type": "u32" + } + ] + } + }, { "name": "UpdateExternalPluginAdapterV1Args", "type": { @@ -3702,6 +4479,26 @@ ] } }, + { + "name": "UpdateGroupV1Args", + "type": { + "kind": "struct", + "fields": [ + { + "name": "newName", + "type": { + "option": "string" + } + }, + { + "name": "newUri", + "type": { + "option": "string" + } + } + ] + } + }, { "name": "UpdatePluginV1Args", "type": { @@ -3808,6 +4605,24 @@ ] } }, + { + "name": "RelationshipEntry", + "type": { + "kind": "struct", + "fields": [ + { + "name": "kind", + "type": { + "defined": "RelationshipKind" + } + }, + { + "name": "key", + "type": "publicKey" + } + ] + } + }, { "name": "HashablePluginSchema", "type": { @@ -3984,6 +4799,38 @@ "defined": "Autograph" } ] + }, + { + "name": "BubblegumV2", + "fields": [ + { + "defined": "BubblegumV2" + } + ] + }, + { + "name": "FreezeExecute", + "fields": [ + { + "defined": "FreezeExecute" + } + ] + }, + { + "name": "PermanentFreezeExecute", + "fields": [ + { + "defined": "PermanentFreezeExecute" + } + ] + }, + { + "name": "Groups", + "fields": [ + { + "defined": "Groups" + } + ] } ] } @@ -4037,6 +4884,18 @@ }, { "name": "Autograph" + }, + { + "name": "BubblegumV2" + }, + { + "name": "FreezeExecute" + }, + { + "name": "PermanentFreezeExecute" + }, + { + "name": "Groups" } ] } @@ -4123,6 +4982,9 @@ }, { "name": "DataSection" + }, + { + "name": "AgentIdentity" } ] } @@ -4179,6 +5041,14 @@ "defined": "DataSection" } ] + }, + { + "name": "AgentIdentity", + "fields": [ + { + "defined": "AgentIdentity" + } + ] } ] } @@ -4199,6 +5069,9 @@ }, { "name": "Update" + }, + { + "name": "Execute" } ] } @@ -4421,6 +5294,14 @@ "defined": "DataSectionInitInfo" } ] + }, + { + "name": "AgentIdentity", + "fields": [ + { + "defined": "AgentIdentityInitInfo" + } + ] } ] } @@ -4469,6 +5350,14 @@ "defined": "LinkedAppDataUpdateInfo" } ] + }, + { + "name": "AgentIdentity", + "fields": [ + { + "defined": "AgentIdentityUpdateInfo" + } + ] } ] } @@ -4519,6 +5408,9 @@ "defined": "LinkedDataKey" } ] + }, + { + "name": "AgentIdentity" } ] } @@ -4609,6 +5501,23 @@ ] } }, + { + "name": "UpdateType", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Mint" + }, + { + "name": "Add" + }, + { + "name": "Remove" + } + ] + } + }, { "name": "DataState", "type": { @@ -4671,6 +5580,29 @@ }, { "name": "CollectionV1" + }, + { + "name": "GroupV1" + } + ] + } + }, + { + "name": "RelationshipKind", + "type": { + "kind": "enum", + "variants": [ + { + "name": "Collection" + }, + { + "name": "ChildGroup" + }, + { + "name": "ParentGroup" + }, + { + "name": "Asset" } ] } @@ -4952,6 +5884,41 @@ }, { "code": 50, + "name": "BlockedByBubblegumV2", + "msg": "Bubblegum V2 Plugin limits other plugins" + }, + { + "code": 51, + "name": "AgentIdentityMustSign", + "msg": "Agent Identity Program must sign" + }, + { + "code": 52, + "name": "GroupMustBeEmpty", + "msg": "Group must be empty to be closed" + }, + { + "code": 53, + "name": "DuplicateEntry", + "msg": "Duplicate entry provided when adding relationships to a group" + }, + { + "code": 54, + "name": "GroupVectorFull", + "msg": "Group vector is at maximum capacity" + }, + { + "code": 55, + "name": "GroupNestingDepthExceeded", + "msg": "Group nesting depth exceeded" + }, + { + "code": 56, + "name": "InconsistentGroupRelationship", + "msg": "Bidirectional group relationship is inconsistent" + }, + { + "code": 57, "name": "PluginNotAllowedOnAsset", "msg": "Plugin is not allowed to be added to an Asset" } diff --git a/package.json b/package.json index 5528b1c6..c7a14cbb 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,31 @@ { - "private": true, - "scripts": { - "programs:build": "./configs/scripts/program/build.sh", - "programs:test": "RUST_LOG=error ./configs/scripts/program/test.sh", - "programs:debug": "./configs/scripts/program/test.sh", - "programs:clean": "./configs/scripts/program/clean.sh", - "clients:rust:test": "./configs/scripts/client/test-rust.sh", - "clients:js:test": "./configs/scripts/client/test-js.sh", - "generate": "pnpm generate:idls && pnpm generate:clients", - "generate:idls": "node ./configs/shank.cjs", - "generate:clients": "node ./configs/kinobi.cjs", - "validator": "CI=1 amman start --config ./configs/validator.cjs", - "validator:debug": "amman start --config ./configs/validator.cjs", - "validator:logs": "CI=1 amman logs", - "validator:stop": "amman stop", - "lint:fix": "./configs/scripts/client/format-js.sh && ./configs/scripts/program/format.sh", - "format:fix": "pnpm lint:fix", - "lint": "./configs/scripts/client/lint-js.sh && ./configs/scripts/program/lint.sh", - "prepare": "husky" - }, - "devDependencies": { - "@metaplex-foundation/amman": "^0.12.1", - "@metaplex-foundation/kinobi": "0.18.8-alpha.0", - "@metaplex-foundation/shank-js": "^0.1.7", - "husky": "^9.0.11", - "typescript": "^4.9.4" - }, - "packageManager": "pnpm@8.9.0" + "private": true, + "scripts": { + "programs:build": "./configs/scripts/program/build.sh", + "programs:test": "RUST_LOG=error ./configs/scripts/program/test.sh", + "programs:debug": "./configs/scripts/program/test.sh", + "programs:clean": "./configs/scripts/program/clean.sh", + "clients:rust:test": "./configs/scripts/client/test-rust.sh", + "clients:js:test": "./configs/scripts/client/test-js.sh", + "generate": "pnpm generate:idls && pnpm generate:clients", + "generate:idls": "node ./configs/shank.cjs", + "generate:clients": "node ./configs/kinobi.cjs", + "validator": "CI=1 amman start --config ./configs/validator.cjs", + "validator:debug": "amman start --config ./configs/validator.cjs", + "validator:logs": "CI=1 amman logs", + "validator:stop": "amman stop", + "lint:fix": "./configs/scripts/client/format-js.sh && ./configs/scripts/program/format.sh", + "format:fix": "pnpm lint:fix", + "lint": "./configs/scripts/client/lint-js.sh && ./configs/scripts/program/lint.sh", + "prepare": "husky" + }, + "devDependencies": { + "@metaplex-foundation/amman": "^0.12.1", + "@metaplex-foundation/kinobi": "1.0.0-alpha.0", + "@metaplex-foundation/shank-js": "^0.1.7", + "@types/node": "^24.0.3", + "husky": "^9.0.11", + "typescript": "^4.9.4" + }, + "packageManager": "pnpm@8.9.0" } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f77ff8a..050a5833 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,15 +1,25 @@ lockfileVersion: '6.0' +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +onlyBuiltDependencies: + - '' + devDependencies: '@metaplex-foundation/amman': specifier: ^0.12.1 version: 0.12.1(typescript@4.9.4) '@metaplex-foundation/kinobi': - specifier: 0.18.8-alpha.0 - version: 0.18.8-alpha.0(fastestsmallesttextencoderdecoder@1.0.22) + specifier: 1.0.0-alpha.0 + version: 1.0.0-alpha.0(fastestsmallesttextencoderdecoder@1.0.22) '@metaplex-foundation/shank-js': specifier: ^0.1.7 version: 0.1.7 + '@types/node': + specifier: ^24.0.3 + version: 24.0.3 husky: specifier: ^9.0.11 version: 9.0.11 @@ -88,8 +98,8 @@ packages: resolution: {integrity: sha512-S9RulC2fFCFOQraz61bij+5YCHhSO9llJegK8c8Y6731fSi6snUSQJdCUqYS8AIgR0TKbQvdvgSyIIdbDFZbBA==} dev: true - /@metaplex-foundation/kinobi@0.18.8-alpha.0(fastestsmallesttextencoderdecoder@1.0.22): - resolution: {integrity: sha512-0ghdmyGnz1j6yDX52lWJOY63AvkSnxbNSYsHgn1sFnMrnnAK3O3EuaFpZdj5j0C2dRB1a+dGw2Kte7GkuPZL2A==} + /@metaplex-foundation/kinobi@1.0.0-alpha.0(fastestsmallesttextencoderdecoder@1.0.22): + resolution: {integrity: sha512-sEof4nvqjkEMENLoFnkb3yvJ5/K29zbiUhB5X0T8x+8605+++aDgiE8vCF3Ur9PRHo7A13EzfjBhrkoR/Jg5xA==} dependencies: '@noble/hashes': 1.7.1 '@prettier/sync': 0.5.2(prettier@3.5.2) @@ -271,23 +281,23 @@ packages: /@types/connect@3.4.38: resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} dependencies: - '@types/node': 12.20.55 + '@types/node': 24.0.3 dev: true /@types/cors@2.8.17: resolution: {integrity: sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==} dependencies: - '@types/node': 22.13.5 + '@types/node': 24.0.3 dev: true /@types/node@12.20.55: resolution: {integrity: sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==} dev: true - /@types/node@22.13.5: - resolution: {integrity: sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==} + /@types/node@24.0.3: + resolution: {integrity: sha512-R4I/kzCYAdRLzfiCabn9hxWfbuHS573x+r0dJMkkzThEa7pbrcDWK+9zu3e7aBOouf+rQAciqPFMnxwr0aWgKg==} dependencies: - undici-types: 6.20.0 + undici-types: 7.8.0 dev: true /@types/uuid@8.3.4: @@ -297,13 +307,13 @@ packages: /@types/ws@7.4.7: resolution: {integrity: sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==} dependencies: - '@types/node': 12.20.55 + '@types/node': 24.0.3 dev: true /@types/ws@8.5.14: resolution: {integrity: sha512-bd/YFLW+URhBzMXurx7lWByOu+xzU9+kb3RboOteXYDfW+tr+JZa99OyNmPINEGB/ahzKrEuc8rcv4gnpJmxTw==} dependencies: - '@types/node': 22.13.5 + '@types/node': 24.0.3 dev: true /JSONStream@1.3.5: @@ -397,7 +407,6 @@ packages: /bigint-buffer@1.1.5: resolution: {integrity: sha512-trfYco6AoZ+rKhKnxA0hgX0HAbVP/s808/EuDSe2JDzUnCp/xAsli35Orvk67UrTEcwuxZqYZDmfA2RXJgxVvA==} engines: {node: '>= 10.0.0'} - requiresBuild: true dependencies: bindings: 1.5.0 dev: true @@ -448,7 +457,6 @@ packages: /bufferutil@4.0.9: resolution: {integrity: sha512-WDtdLmJvAuNNPzByAYpRo2rF1Mmradw6gvWsQKf63476DDXmomT9zUiGypLcG4ibIM67vhAj8jJRdbmEws2Aqw==} engines: {node: '>=6.14.2'} - requiresBuild: true dependencies: node-gyp-build: 4.8.4 dev: true @@ -678,7 +686,7 @@ packages: engines: {node: '>=10.2.0'} dependencies: '@types/cors': 2.8.17 - '@types/node': 22.13.5 + '@types/node': 24.0.3 accepts: 1.3.8 base64id: 2.0.0 cookie: 0.7.2 @@ -1404,14 +1412,13 @@ packages: hasBin: true dev: true - /undici-types@6.20.0: - resolution: {integrity: sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==} + /undici-types@7.8.0: + resolution: {integrity: sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw==} dev: true /utf-8-validate@5.0.10: resolution: {integrity: sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==} engines: {node: '>=6.14.2'} - requiresBuild: true dependencies: node-gyp-build: 4.8.4 dev: true diff --git a/programs/mpl-core/Cargo.toml b/programs/mpl-core/Cargo.toml index f9e89769..26925283 100644 --- a/programs/mpl-core/Cargo.toml +++ b/programs/mpl-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "mpl-core-program" -version = "0.1.0" +version = "0.2.0" edition = "2021" readme = "./README.md" license-file = "../../LICENSE" @@ -13,12 +13,19 @@ crate-type = ["cdylib", "lib"] borsh = "^0.10" shank = "0.4.2" modular-bitfield = "0.11.2" +mpl-bubblegum = "2.1.0" num-derive = "^0.3" num-traits = "^0.2" -solana-program = "^1.17" +solana-program = "2.2.1" thiserror = "^1.0" bytemuck = "1.14.1" -mpl-utils = "0.3.5" -spl-noop = { version = "0.2.0", features = ["cpi"] } +mpl-utils = "0.4.1" +spl-noop = { version = "1.0.0", features = ["cpi"] } podded = "0.5.1" strum = { version = "0.26.1", features = ["derive"] } +mpl-agent-identity = "0.2.0" +mpl-agent-tools = "0.2.0" + +[dev-dependencies] +mollusk-svm = "0.5.0" +solana-sdk = "2.2.1" diff --git a/programs/mpl-core/src/error.rs b/programs/mpl-core/src/error.rs index e19da98a..b18b63a4 100644 --- a/programs/mpl-core/src/error.rs +++ b/programs/mpl-core/src/error.rs @@ -209,7 +209,35 @@ pub enum MplCoreError { #[error("Invalid Signing PDA for Asset or Collection Execute")] InvalidExecutePda, - /// 50 - Plugin is not allowed to be added to an Asset + /// 50 - Bubblegum V2 Plugin limits other plugins + #[error("Bubblegum V2 Plugin limits other plugins")] + BlockedByBubblegumV2, + + /// 51 - Agent Identity Program must sign + #[error("Agent Identity Program must sign")] + AgentIdentityMustSign, + + /// 52 - Group must be empty to be closed + #[error("Group must be empty to be closed")] + GroupMustBeEmpty, + + /// 53 - Duplicate entry provided when adding relationships to a group + #[error("Duplicate entry provided when adding relationships to a group")] + DuplicateEntry, + + /// 54 - Group vector is at maximum capacity + #[error("Group vector is at maximum capacity")] + GroupVectorFull, + + /// 55 - Group nesting depth exceeded + #[error("Group nesting depth exceeded")] + GroupNestingDepthExceeded, + + /// 56 - Bidirectional group relationship is inconsistent + #[error("Bidirectional group relationship is inconsistent")] + InconsistentGroupRelationship, + + /// 57 - Plugin is not allowed to be added to an Asset #[error("Plugin is not allowed to be added to an Asset")] PluginNotAllowedOnAsset, } diff --git a/programs/mpl-core/src/instruction.rs b/programs/mpl-core/src/instruction.rs index af7be24c..a500d745 100644 --- a/programs/mpl-core/src/instruction.rs +++ b/programs/mpl-core/src/instruction.rs @@ -3,16 +3,19 @@ use borsh::{BorshDeserialize, BorshSerialize}; use shank::{ShankContext, ShankInstruction}; use crate::processor::{ - AddCollectionExternalPluginAdapterV1Args, AddCollectionPluginV1Args, - AddExternalPluginAdapterV1Args, AddPluginV1Args, ApproveCollectionPluginAuthorityV1Args, - ApprovePluginAuthorityV1Args, BurnCollectionV1Args, BurnV1Args, CompressV1Args, - CreateCollectionV1Args, CreateCollectionV2Args, CreateV1Args, CreateV2Args, DecompressV1Args, - ExecuteV1Args, RemoveCollectionExternalPluginAdapterV1Args, RemoveCollectionPluginV1Args, - RemoveExternalPluginAdapterV1Args, RemovePluginV1Args, RevokeCollectionPluginAuthorityV1Args, - RevokePluginAuthorityV1Args, TransferV1Args, UpdateCollectionExternalPluginAdapterV1Args, + AddAssetsToGroupV1Args, AddCollectionExternalPluginAdapterV1Args, AddCollectionPluginV1Args, + AddCollectionsToGroupV1Args, AddExternalPluginAdapterV1Args, AddGroupsToGroupV1Args, + AddPluginV1Args, ApproveCollectionPluginAuthorityV1Args, ApprovePluginAuthorityV1Args, + BurnCollectionV1Args, BurnV1Args, CloseGroupV1Args, CompressV1Args, CreateCollectionV1Args, + CreateCollectionV2Args, CreateGroupV1Args, CreateV1Args, CreateV2Args, DecompressV1Args, + ExecuteV1Args, RemoveAssetsFromGroupV1Args, RemoveCollectionExternalPluginAdapterV1Args, + RemoveCollectionPluginV1Args, RemoveCollectionsFromGroupV1Args, + RemoveExternalPluginAdapterV1Args, RemoveGroupsFromGroupV1Args, RemovePluginV1Args, + RevokeCollectionPluginAuthorityV1Args, RevokePluginAuthorityV1Args, TransferV1Args, + UpdateCollectionExternalPluginAdapterV1Args, UpdateCollectionInfoV1Args, UpdateCollectionPluginV1Args, UpdateCollectionV1Args, UpdateExternalPluginAdapterV1Args, - UpdatePluginV1Args, UpdateV1Args, UpdateV2Args, WriteCollectionExternalPluginAdapterDataV1Args, - WriteExternalPluginAdapterDataV1Args, + UpdateGroupV1Args, UpdatePluginV1Args, UpdateV1Args, UpdateV2Args, + WriteCollectionExternalPluginAdapterDataV1Args, WriteExternalPluginAdapterDataV1Args, }; /// Instructions supported by the mpl-core program. @@ -297,9 +300,77 @@ pub(crate) enum MplAssetInstruction { #[account(0, writable, name="asset", desc = "The address of the asset")] #[account(1, optional, writable, name="collection", desc = "The collection to which the asset belongs")] #[account(2, name="asset_signer", desc = "The signing PDA for the asset")] - #[account(3, writable, signer, name="payer", desc = "The account paying for the storage fees")] + #[account(3, writable, optional_signer, name="payer", desc = "The account paying for the storage fees")] #[account(4, optional, signer, name="authority", desc = "The owner or delegate of the asset")] #[account(5, name="system_program", desc = "The system program")] #[account(6, name="program_id", desc = "The program id of the instruction")] ExecuteV1(ExecuteV1Args), + + /// Update mpl-core collection info (can only be called by Bubblegum program). + #[account(0, writable, name="collection", desc = "The address of the asset")] + #[account(1, signer, name="bubblegum_signer", desc = "Bubblegum PDA signer")] + UpdateCollectionInfoV1(UpdateCollectionInfoV1Args), + + /// Add collections to a group. + #[account(0, writable, name="group", desc = "The address of the group to modify")] + #[account(1, writable, signer, name="payer", desc = "The account paying for storage fees")] + #[account(2, optional, signer, name="authority", desc = "The group update authority and collection update authority or delegate")] + #[account(3, name="system_program", desc = "The system program")] + AddCollectionsToGroupV1(AddCollectionsToGroupV1Args), + + /// Remove collections from a group. + #[account(0, writable, name="group", desc = "The address of the group to modify")] + #[account(1, writable, signer, name="payer", desc = "The account paying for storage fees")] + #[account(2, optional, signer, name="authority", desc = "The group update authority and collection update authority or delegate")] + #[account(3, name="system_program", desc = "The system program")] + RemoveCollectionsFromGroupV1(RemoveCollectionsFromGroupV1Args), + + /// Add assets to a group. + #[account(0, writable, name="group", desc = "The address of the group to modify")] + #[account(1, writable, signer, name="payer", desc = "The account paying for storage fees")] + #[account(2, optional, signer, name="authority", desc = "The group update authority and asset update authority or delegate")] + #[account(3, name="system_program", desc = "The system program")] + AddAssetsToGroupV1(AddAssetsToGroupV1Args), + + /// Remove assets from a group. + #[account(0, writable, name="group", desc = "The address of the group to modify")] + #[account(1, writable, signer, name="payer", desc = "The account paying for storage fees")] + #[account(2, optional, signer, name="authority", desc = "The group update authority and asset update authority or delegate")] + #[account(3, name="system_program", desc = "The system program")] + RemoveAssetsFromGroupV1(RemoveAssetsFromGroupV1Args), + + /// Add groups to a parent group. + #[account(0, writable, name="parent_group", desc = "The address of the parent group to modify")] + #[account(1, writable, signer, name="payer", desc = "The account paying for storage fees")] + #[account(2, optional, signer, name="authority", desc = "The update authority of the parent and child groups")] + #[account(3, name="system_program", desc = "The system program")] + AddGroupsToGroupV1(AddGroupsToGroupV1Args), + + /// Remove groups from a parent group. + #[account(0, writable, name="parent_group", desc = "The address of the parent group to modify")] + #[account(1, writable, signer, name="payer", desc = "The account paying for storage fees")] + #[account(2, optional, signer, name="authority", desc = "The update authority of the parent and child groups")] + #[account(3, name="system_program", desc = "The system program")] + RemoveGroupsFromGroupV1(RemoveGroupsFromGroupV1Args), + + /// Create a new Group account. + #[account(0, writable, signer, name="group", desc = "The address of the new group")] + #[account(1, optional, signer, name="update_authority", desc = "The authority of the new group")] + #[account(2, writable, signer, name="payer", desc = "The account paying for the storage fees")] + #[account(3, name="system_program", desc = "The system program")] + CreateGroupV1(CreateGroupV1Args), + + /// Close an existing Group account. The group must have no parent or child relationships. + #[account(0, writable, name="group", desc = "The address of the group to close")] + #[account(1, writable, signer, name="payer", desc = "The account receiving reclaimed lamports")] + #[account(2, optional, signer, name="authority", desc = "The update authority of the group")] + CloseGroupV1(CloseGroupV1Args), + + /// Update an existing Group account. + #[account(0, writable, name="group", desc = "The address of the group to update")] + #[account(1, writable, signer, name="payer", desc = "The account paying for the storage fees")] + #[account(2, optional, signer, name="authority", desc = "The update authority of the group")] + #[account(3, optional, name="new_update_authority", desc = "The new update authority of the group")] + #[account(4, name="system_program", desc = "The system program")] + UpdateGroupV1(UpdateGroupV1Args), } diff --git a/programs/mpl-core/src/plugins/external/agent_identity.rs b/programs/mpl-core/src/plugins/external/agent_identity.rs new file mode 100644 index 00000000..1a309046 --- /dev/null +++ b/programs/mpl-core/src/plugins/external/agent_identity.rs @@ -0,0 +1,169 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_agent_tools::accounts::ExecutionDelegateRecordV1; +use mpl_utils::{assert_derivation, assert_signer}; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, + pubkey::Pubkey, +}; + +use crate::{ + error::MplCoreError, + plugins::{ + abstain, approve, reject, Authority, ExternalCheckResult, HookableLifecycleEvent, + PluginValidation, PluginValidationContext, ValidationResult, + }, +}; + +/// Agent Identity plugin that links to an ERC-8004 spec registration file via a URI. +/// This plugin can only be added to an asset, not a collection. There can be at most +/// one AgentIdentity plugin per asset. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct AgentIdentity { + /// URI pointing to the ERC-8004 agent registration JSON file. + pub uri: String, +} + +impl AgentIdentity { + /// Updates the agent identity with the new info. + pub fn update(&mut self, info: &AgentIdentityUpdateInfo) { + if let Some(uri) = &info.uri { + self.uri = uri.clone(); + } + } + + /// Check that the agent identity program is signing off on the addition. + pub fn verify_identity_registry( + identity_account: &AccountInfo, + asset: &Pubkey, + ) -> ProgramResult { + assert_signer(identity_account)?; + let _ = assert_derivation( + &mpl_agent_identity::ID, + identity_account, + &[b"agent_identity", asset.as_ref()], + MplCoreError::AgentIdentityMustSign, + )?; + + Ok(()) + } + + /// Verify that the Execution Delegate is valid for the asset. + pub fn verify_execution_delegate( + asset: &Pubkey, + authority: &Pubkey, + maybe_execution_delegate_record: &AccountInfo, + ) -> Result { + // If the account there is owned by the mpl-agent-tools program, then it's probably an execution delegate record. + if maybe_execution_delegate_record.owner == &mpl_agent_tools::ID + && maybe_execution_delegate_record.data_len() > 0 + && maybe_execution_delegate_record.data.borrow()[0] + == mpl_agent_tools::types::Key::ExecutionDelegateRecordV1 as u8 + { + let execution_delegate_record = + ExecutionDelegateRecordV1::try_from(maybe_execution_delegate_record)?; + if execution_delegate_record.agent_asset == *asset + && execution_delegate_record.authority == *authority + { + return approve!(); + } + } + + abstain!() + } +} + +impl PluginValidation for AgentIdentity { + fn validate_create( + &self, + ctx: &PluginValidationContext, + ) -> Result { + // Reject if being added to a collection (asset_info is None for collections). + if let Some(asset_info) = ctx.asset_info { + // Verify that the agent identity program is signing off on the addition. + // Accounts cannot be empty so the unwrap is safe. + Self::verify_identity_registry(ctx.accounts.last().unwrap(), asset_info.key)?; + abstain!() + } else { + reject!() + } + } + + fn validate_add_external_plugin_adapter( + &self, + ctx: &PluginValidationContext, + ) -> Result { + // Reject if being added to a collection (asset_info is None for collections). + if let Some(asset_info) = ctx.asset_info { + // Verify that the agent identity program is signing off on the addition. + // Accounts cannot be empty so the unwrap is safe. + Self::verify_identity_registry(ctx.accounts.last().unwrap(), asset_info.key)?; + abstain!() + } else { + reject!() + } + } + + fn validate_transfer( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + abstain!() + } + + fn validate_burn( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + abstain!() + } + + fn validate_update( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + abstain!() + } + + fn validate_execute( + &self, + ctx: &PluginValidationContext, + ) -> Result { + if ctx.asset_info.is_some() && ctx.accounts.len() > 7 { + Self::verify_execution_delegate( + ctx.asset_info.unwrap().key, + ctx.authority_info.key, + ctx.accounts.get(7).unwrap(), + ) + } else { + abstain!() + } + } +} + +impl From<&AgentIdentityInitInfo> for AgentIdentity { + fn from(init_info: &AgentIdentityInitInfo) -> Self { + Self { + uri: init_info.uri.clone(), + } + } +} + +/// Agent Identity initialization info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct AgentIdentityInitInfo { + /// URI pointing to the ERC-8004 agent registration JSON file. + pub uri: String, + /// Initial plugin authority. + pub init_plugin_authority: Option, + /// The lifecycle events for which the external plugin adapter is active. + pub lifecycle_checks: Vec<(HookableLifecycleEvent, ExternalCheckResult)>, +} + +/// Agent Identity update info. +#[derive(Clone, Debug, BorshSerialize, BorshDeserialize, Eq, PartialEq)] +pub struct AgentIdentityUpdateInfo { + /// Updated URI pointing to the ERC-8004 agent registration JSON file. + pub uri: Option, + /// The lifecycle events for which the external plugin adapter is active. + pub lifecycle_checks: Option>, +} diff --git a/programs/mpl-core/src/plugins/external/mod.rs b/programs/mpl-core/src/plugins/external/mod.rs index 063c3982..6d0916d5 100644 --- a/programs/mpl-core/src/plugins/external/mod.rs +++ b/programs/mpl-core/src/plugins/external/mod.rs @@ -1,3 +1,4 @@ +mod agent_identity; mod app_data; mod data_section; mod lifecycle_hook; @@ -5,6 +6,7 @@ mod linked_app_data; mod linked_lifecycle_hook; mod oracle; +pub use agent_identity::*; pub use app_data::*; pub use data_section::*; pub use lifecycle_hook::*; diff --git a/programs/mpl-core/src/plugins/external/oracle.rs b/programs/mpl-core/src/plugins/external/oracle.rs index bc0a20ef..99156c50 100644 --- a/programs/mpl-core/src/plugins/external/oracle.rs +++ b/programs/mpl-core/src/plugins/external/oracle.rs @@ -116,6 +116,7 @@ impl Oracle { HookableLifecycleEvent::Transfer => Ok(ValidationResult::from(transfer)), HookableLifecycleEvent::Burn => Ok(ValidationResult::from(burn)), HookableLifecycleEvent::Update => Ok(ValidationResult::from(update)), + HookableLifecycleEvent::Execute => Ok(ValidationResult::Pass), }, } } diff --git a/programs/mpl-core/src/plugins/external_plugin_adapters.rs b/programs/mpl-core/src/plugins/external_plugin_adapters.rs index 97f1b2aa..fb9661c1 100644 --- a/programs/mpl-core/src/plugins/external_plugin_adapters.rs +++ b/programs/mpl-core/src/plugins/external_plugin_adapters.rs @@ -12,11 +12,12 @@ use crate::{ }; use super::{ - AppData, AppDataInitInfo, AppDataUpdateInfo, Authority, DataSection, DataSectionInitInfo, - ExternalCheckResult, ExternalRegistryRecord, LifecycleHook, LifecycleHookInitInfo, - LifecycleHookUpdateInfo, LinkedAppData, LinkedAppDataInitInfo, LinkedAppDataUpdateInfo, - LinkedLifecycleHook, LinkedLifecycleHookInitInfo, LinkedLifecycleHookUpdateInfo, Oracle, - OracleInitInfo, OracleUpdateInfo, PluginValidation, PluginValidationContext, ValidationResult, + AgentIdentity, AgentIdentityInitInfo, AgentIdentityUpdateInfo, AppData, AppDataInitInfo, + AppDataUpdateInfo, Authority, DataSection, DataSectionInitInfo, ExternalCheckResult, + ExternalRegistryRecord, LifecycleHook, LifecycleHookInitInfo, LifecycleHookUpdateInfo, + LinkedAppData, LinkedAppDataInitInfo, LinkedAppDataUpdateInfo, LinkedLifecycleHook, + LinkedLifecycleHookInitInfo, LinkedLifecycleHookUpdateInfo, Oracle, OracleInitInfo, + OracleUpdateInfo, PluginValidation, PluginValidationContext, ValidationResult, }; /// List of third party plugin types. @@ -47,6 +48,8 @@ pub enum ExternalPluginAdapterType { LinkedAppData, /// Data Section. DataSection, + /// Agent Identity. + AgentIdentity, } impl ExternalPluginAdapterType { @@ -71,6 +74,7 @@ impl From<&ExternalPluginAdapterKey> for ExternalPluginAdapterType { ExternalPluginAdapterKey::AppData(_) => ExternalPluginAdapterType::AppData, ExternalPluginAdapterKey::LinkedAppData(_) => ExternalPluginAdapterType::LinkedAppData, ExternalPluginAdapterKey::DataSection(_) => ExternalPluginAdapterType::DataSection, + ExternalPluginAdapterKey::AgentIdentity => ExternalPluginAdapterType::AgentIdentity, } } } @@ -90,6 +94,9 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapterType { ExternalPluginAdapterType::LinkedAppData } ExternalPluginAdapterInitInfo::DataSection(_) => ExternalPluginAdapterType::DataSection, + ExternalPluginAdapterInitInfo::AgentIdentity(_) => { + ExternalPluginAdapterType::AgentIdentity + } } } } @@ -105,6 +112,7 @@ impl From<&ExternalPluginAdapter> for ExternalPluginAdapterType { } ExternalPluginAdapter::LinkedAppData(_) => ExternalPluginAdapterType::LinkedAppData, ExternalPluginAdapter::DataSection(_) => ExternalPluginAdapterType::DataSection, + ExternalPluginAdapter::AgentIdentity(_) => ExternalPluginAdapterType::AgentIdentity, } } } @@ -134,11 +142,13 @@ pub enum ExternalPluginAdapter { /// Data Section. This is a special plugin that is used to contain the data of other external /// plugins. DataSection(DataSection), + /// Asset only: Agent Identity plugin that links to an ERC-8004 spec registration file via a URI. + AgentIdentity(AgentIdentity), } impl ExternalPluginAdapter { /// Update the plugin from the update info. - pub fn update(&mut self, update_info: &ExternalPluginAdapterUpdateInfo) { + pub fn update(&mut self, update_info: &ExternalPluginAdapterUpdateInfo) -> ProgramResult { match (self, update_info) { ( ExternalPluginAdapter::LifecycleHook(lifecycle_hook), @@ -170,8 +180,16 @@ impl ExternalPluginAdapter { ) => { linked_app_data.update(update_info); } - _ => unreachable!(), + ( + ExternalPluginAdapter::AgentIdentity(agent_identity), + ExternalPluginAdapterUpdateInfo::AgentIdentity(update_info), + ) => { + agent_identity.update(update_info); + } + _ => return Err(MplCoreError::InvalidPlugin.into()), } + + Ok(()) } /// Check if a plugin is permitted to approve or deny a create action. @@ -213,6 +231,17 @@ impl ExternalPluginAdapter { } ExternalPluginAdapterInitInfo::LinkedAppData(_) => ExternalCheckResult::none(), ExternalPluginAdapterInitInfo::DataSection(_) => ExternalCheckResult::none(), + ExternalPluginAdapterInitInfo::AgentIdentity(init_info) => { + if let Some(checks) = init_info + .lifecycle_checks + .iter() + .find(|event| event.0 == HookableLifecycleEvent::Create) + { + checks.1 + } else { + ExternalCheckResult::none() + } + } } } @@ -234,6 +263,9 @@ impl ExternalPluginAdapter { ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_create(ctx), // Here we block the creation of a DataSection plugin because this is only done internally. ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Rejected), + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + agent_identity.validate_create(ctx) + } } } @@ -253,6 +285,9 @@ impl ExternalPluginAdapter { } ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_update(ctx), ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Pass), + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + agent_identity.validate_update(ctx) + } } } @@ -272,6 +307,9 @@ impl ExternalPluginAdapter { } ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_burn(ctx), ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Pass), + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + agent_identity.validate_burn(ctx) + } } } @@ -291,6 +329,9 @@ impl ExternalPluginAdapter { } ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_transfer(ctx), ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Pass), + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + agent_identity.validate_transfer(ctx) + } } } @@ -317,6 +358,9 @@ impl ExternalPluginAdapter { } // Here we block the creation of a DataSection plugin because this is only done internally. ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Rejected), + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + agent_identity.validate_add_external_plugin_adapter(ctx) + } } } @@ -358,6 +402,9 @@ impl ExternalPluginAdapter { } // Here we block the update of a DataSection plugin because this is only done internally. ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Rejected), + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + agent_identity.validate_update_external_plugin_adapter(ctx) + } }?; match (&base_result, &result) { @@ -380,6 +427,81 @@ impl ExternalPluginAdapter { } } + /// Check if a plugin is permitted to approve or deny an execute action. + pub fn check_execute(plugin: &ExternalPluginAdapterInitInfo) -> ExternalCheckResult { + match plugin { + ExternalPluginAdapterInitInfo::LifecycleHook(init_info) => { + if let Some(checks) = init_info + .lifecycle_checks + .iter() + .find(|event| event.0 == HookableLifecycleEvent::Execute) + { + checks.1 + } else { + ExternalCheckResult::none() + } + } + ExternalPluginAdapterInitInfo::Oracle(init_info) => { + if let Some(checks) = init_info + .lifecycle_checks + .iter() + .find(|event| event.0 == HookableLifecycleEvent::Execute) + { + checks.1 + } else { + ExternalCheckResult::none() + } + } + ExternalPluginAdapterInitInfo::AppData(_) => ExternalCheckResult::none(), + ExternalPluginAdapterInitInfo::LinkedLifecycleHook(init_info) => { + if let Some(checks) = init_info + .lifecycle_checks + .iter() + .find(|event| event.0 == HookableLifecycleEvent::Execute) + { + checks.1 + } else { + ExternalCheckResult::none() + } + } + ExternalPluginAdapterInitInfo::LinkedAppData(_) => ExternalCheckResult::none(), + ExternalPluginAdapterInitInfo::DataSection(_) => ExternalCheckResult::none(), + ExternalPluginAdapterInitInfo::AgentIdentity(init_info) => { + if let Some(checks) = init_info + .lifecycle_checks + .iter() + .find(|event| event.0 == HookableLifecycleEvent::Execute) + { + checks.1 + } else { + ExternalCheckResult::none() + } + } + } + } + + /// Route the validation of the execute action to the appropriate external plugin adapter. + pub(crate) fn validate_execute( + external_plugin_adapter: &ExternalPluginAdapter, + ctx: &PluginValidationContext, + ) -> Result { + match external_plugin_adapter { + ExternalPluginAdapter::LifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_execute(ctx) + } + ExternalPluginAdapter::Oracle(oracle) => oracle.validate_execute(ctx), + ExternalPluginAdapter::AppData(app_data) => app_data.validate_execute(ctx), + ExternalPluginAdapter::LinkedLifecycleHook(lifecycle_hook) => { + lifecycle_hook.validate_execute(ctx) + } + ExternalPluginAdapter::LinkedAppData(app_data) => app_data.validate_execute(ctx), + ExternalPluginAdapter::DataSection(_) => Ok(ValidationResult::Pass), + ExternalPluginAdapter::AgentIdentity(agent_identity) => { + agent_identity.validate_execute(ctx) + } + } + } + /// Load and deserialize a plugin from an offset in the account. pub fn load(account: &AccountInfo, offset: usize) -> Result { let mut bytes: &[u8] = &(*account.data).borrow()[offset..]; @@ -419,6 +541,9 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapter { ExternalPluginAdapterInitInfo::DataSection(init_info) => { ExternalPluginAdapter::DataSection(DataSection::from(init_info)) } + ExternalPluginAdapterInitInfo::AgentIdentity(init_info) => { + ExternalPluginAdapter::AgentIdentity(AgentIdentity::from(init_info)) + } } } } @@ -439,6 +564,8 @@ pub enum HookableLifecycleEvent { Burn, /// Update an Asset or a Collection. Update, + /// Execute an instruction on behalf of the Asset. + Execute, } impl HookableLifecycleEvent { @@ -679,6 +806,8 @@ pub enum ExternalPluginAdapterInitInfo { LinkedAppData(LinkedAppDataInitInfo), /// Data Section. DataSection(DataSectionInitInfo), + /// Agent Identity. + AgentIdentity(AgentIdentityInitInfo), } /// Information needed to update an external plugin adapter. @@ -695,6 +824,8 @@ pub enum ExternalPluginAdapterUpdateInfo { LinkedLifecycleHook(LinkedLifecycleHookUpdateInfo), /// Linked App Data. LinkedAppData(LinkedAppDataUpdateInfo), + /// Agent Identity. + AgentIdentity(AgentIdentityUpdateInfo), } /// Key used to uniquely specify an external plugin adapter after it is created. @@ -715,6 +846,8 @@ pub enum ExternalPluginAdapterKey { LinkedAppData(Authority), /// Data Section. DataSection(LinkedDataKey), + /// Agent Identity. Only one per asset so no discriminator needed. + AgentIdentity, } /// Key to point to the plugin that manages this data section. @@ -773,6 +906,7 @@ impl ExternalPluginAdapterKey { )?; Ok(Self::DataSection(linked_data_key)) } + ExternalPluginAdapterType::AgentIdentity => Ok(Self::AgentIdentity), } } } @@ -798,6 +932,9 @@ impl From<&ExternalPluginAdapterInitInfo> for ExternalPluginAdapterKey { ExternalPluginAdapterInitInfo::DataSection(init_info) => { ExternalPluginAdapterKey::DataSection(init_info.parent_key) } + ExternalPluginAdapterInitInfo::AgentIdentity(_) => { + ExternalPluginAdapterKey::AgentIdentity + } } } } @@ -834,4 +971,42 @@ mod test { ); } } + + #[test] + fn test_external_plugin_adapter_update_rejects_mismatched_variant() { + let mut plugin = ExternalPluginAdapter::AppData(AppData { + data_authority: Authority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Binary, + }); + let update_info = ExternalPluginAdapterUpdateInfo::Oracle(OracleUpdateInfo { + lifecycle_checks: None, + base_address_config: None, + results_offset: None, + }); + + let error = plugin.update(&update_info).unwrap_err(); + + assert_eq!(error, MplCoreError::InvalidPlugin.into()); + } + + #[test] + fn test_external_plugin_adapter_update_applies_matching_variant() { + let mut plugin = ExternalPluginAdapter::AppData(AppData { + data_authority: Authority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Binary, + }); + let update_info = ExternalPluginAdapterUpdateInfo::AppData(AppDataUpdateInfo { + schema: Some(ExternalPluginAdapterSchema::Json), + }); + + plugin.update(&update_info).unwrap(); + + assert_eq!( + plugin, + ExternalPluginAdapter::AppData(AppData { + data_authority: Authority::UpdateAuthority, + schema: ExternalPluginAdapterSchema::Json, + }) + ); + } } diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/groups.rs b/programs/mpl-core/src/plugins/internal/authority_managed/groups.rs new file mode 100644 index 00000000..894c436f --- /dev/null +++ b/programs/mpl-core/src/plugins/internal/authority_managed/groups.rs @@ -0,0 +1,39 @@ +use crate::{ + plugins::{abstain, reject, PluginValidation, PluginValidationContext, ValidationResult}, + state::DataBlob, +}; +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::{program_error::ProgramError, pubkey::Pubkey}; + +/// Groups plugin for collections. Stores the immediate parent group accounts this collection +/// belongs to. Relationship updates are handled by specialized group instructions, and this +/// plugin overrides `validate_burn` to reject burns while the group set is non-empty. +#[repr(C)] +#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq, Default)] +pub struct Groups { + /// The list of parent group accounts for this collection. + pub groups: Vec, // 4 + len * 32 +} + +impl Groups { + const BASE_LEN: usize = 4; // length of the groups vector +} + +impl DataBlob for Groups { + fn len(&self) -> usize { + Self::BASE_LEN + self.groups.len() * 32 + } +} + +impl PluginValidation for Groups { + fn validate_burn( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + if !self.groups.is_empty() { + reject!() + } else { + abstain!() + } + } +} diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/mod.rs b/programs/mpl-core/src/plugins/internal/authority_managed/mod.rs index 55ecd552..0925ae3f 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/mod.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/mod.rs @@ -1,5 +1,6 @@ mod add_blocker; mod attributes; +mod groups; mod immutable_metadata; mod master_edition; mod royalties; @@ -8,6 +9,7 @@ mod verified_creators; pub use add_blocker::*; pub use attributes::*; +pub use groups::*; pub use immutable_metadata::*; pub use master_edition::*; pub use royalties::*; diff --git a/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs b/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs index a14c34b9..09767897 100644 --- a/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs +++ b/programs/mpl-core/src/plugins/internal/authority_managed/update_delegate.rs @@ -141,15 +141,19 @@ impl PluginValidation for UpdateDelegate { ) -> Result { let plugin = ctx.target_plugin.ok_or(MplCoreError::InvalidPlugin)?; - // If the plugin authority is the authority signing. - if (ctx.resolved_authorities.is_some() + // SECURITY FIX: Added explicit parentheses to fix operator precedence. + // Previously, `&& plugin.manager() == Authority::UpdateAuthority` only bound + // to the additional_delegates branch due to && having higher precedence than ||. + // This allowed UpdateDelegate to revoke authority on owner-managed plugins + // (FreezeDelegate, TransferDelegate) which it should not control. + if ((ctx.resolved_authorities.is_some() && ctx .resolved_authorities .unwrap() .contains(ctx.self_authority)) // Or the authority is one of the additional delegates. - || (self.additional_delegates.contains(ctx.authority_info.key) && PluginType::from(plugin) != PluginType::UpdateDelegate) - // And it's an authority-managed plugin. + || (self.additional_delegates.contains(ctx.authority_info.key) && PluginType::from(plugin) != PluginType::UpdateDelegate)) + // And it's an authority-managed plugin (applies to BOTH branches). && plugin.manager() == Authority::UpdateAuthority { approve!() diff --git a/programs/mpl-core/src/plugins/internal/owner_managed/freeze_execute.rs b/programs/mpl-core/src/plugins/internal/owner_managed/freeze_execute.rs new file mode 100644 index 00000000..2c4ff772 --- /dev/null +++ b/programs/mpl-core/src/plugins/internal/owner_managed/freeze_execute.rs @@ -0,0 +1,117 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::program_error::ProgramError; + +use crate::{ + plugins::{ + abstain, approve, reject, Plugin, PluginValidation, PluginValidationContext, + ValidationResult, + }, + state::DataBlob, +}; + +/// The FreezeExecute plugin allows any authority to lock the asset so its **Execute** lifecycle +/// event can be conditionally blocked. The default authority for this plugin is the asset owner. +#[repr(C)] +#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq)] +pub struct FreezeExecute { + /// Indicates whether the asset's Execute lifecycle event is currently frozen. + pub frozen: bool, // 1 +} + +impl FreezeExecute { + const BASE_LEN: usize = 1; // The frozen boolean + + /// Initialize the plugin; assets are unfrozen by default. + pub fn new() -> Self { + Self { frozen: false } + } +} + +impl Default for FreezeExecute { + fn default() -> Self { + Self::new() + } +} + +impl DataBlob for FreezeExecute { + fn len(&self) -> usize { + Self::BASE_LEN + } +} + +impl PluginValidation for FreezeExecute { + /// Validate the execute lifecycle action. + /// If the asset is frozen, reject the Execute operation; otherwise abstain. + fn validate_execute( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + if self.frozen { + reject!() + } else { + abstain!() + } + } + + /// Validate the approve plugin authority lifecycle action. + /// If the target FreezeExecute is frozen, reject authority changes. + fn validate_approve_plugin_authority( + &self, + ctx: &PluginValidationContext, + ) -> Result { + if let Some(Plugin::FreezeExecute(freeze)) = ctx.target_plugin { + if freeze.frozen { + return reject!(); + } + } + abstain!() + } + + /// Validate the revoke plugin authority lifecycle action. + /// If the target FreezeExecute is frozen, reject revocation. + /// If unfrozen and the caller is a resolved authority, approve. + fn validate_revoke_plugin_authority( + &self, + ctx: &PluginValidationContext, + ) -> Result { + if let Some(Plugin::FreezeExecute(freeze)) = ctx.target_plugin { + if freeze.frozen { + return reject!(); + } else if ctx.resolved_authorities.is_some() + && ctx + .resolved_authorities + .unwrap() + .contains(ctx.self_authority) + { + return approve!(); + } + } + abstain!() + } + + /// Validate the remove plugin lifecycle action. + /// If the target FreezeExecute is frozen, reject its removal. + fn validate_remove_plugin( + &self, + ctx: &PluginValidationContext, + ) -> Result { + if let Some(Plugin::FreezeExecute(freeze)) = ctx.target_plugin { + if freeze.frozen { + return reject!(); + } + } + abstain!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_freeze_execute_len() { + let freeze_execute = FreezeExecute::default(); + let serialized = freeze_execute.try_to_vec().unwrap(); + assert_eq!(serialized.len(), freeze_execute.len()); + } +} diff --git a/programs/mpl-core/src/plugins/internal/owner_managed/mod.rs b/programs/mpl-core/src/plugins/internal/owner_managed/mod.rs index 7545e168..4e90f470 100644 --- a/programs/mpl-core/src/plugins/internal/owner_managed/mod.rs +++ b/programs/mpl-core/src/plugins/internal/owner_managed/mod.rs @@ -1,9 +1,11 @@ mod autograph; mod burn_delegate; mod freeze_delegate; +mod freeze_execute; mod transfer_delegate; pub use autograph::*; pub use burn_delegate::*; pub use freeze_delegate::*; +pub use freeze_execute::*; pub use transfer_delegate::*; diff --git a/programs/mpl-core/src/plugins/internal/permanent/bubblegum_v2.rs b/programs/mpl-core/src/plugins/internal/permanent/bubblegum_v2.rs new file mode 100644 index 00000000..cca2ed02 --- /dev/null +++ b/programs/mpl-core/src/plugins/internal/permanent/bubblegum_v2.rs @@ -0,0 +1,100 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::program_error::ProgramError; + +use crate::{ + plugins::{ + abstain, reject, Plugin, PluginType, PluginValidation, PluginValidationContext, + ValidationResult, + }, + state::DataBlob, +}; + +/// The Bubblegum V2 plugin allows a Core collection to contain Compressed NFTs (cNFTs) +/// from the Bubblegum program. The authority for this plugin can only be the Bubblegum +/// program. +#[repr(C)] +#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, Debug, Default, PartialEq, Eq)] +pub struct BubblegumV2 {} + +impl BubblegumV2 { + /// List of other plugins allowed on collections with the Bubblegum V2 plugin. + /// The BubblegumV2 plugin limits what can be on the collection to plugins that are + /// supported and validated at runtime by the Bubblegum program. Other plugins may + /// be added in the future but for now this subset was chosen. + pub(crate) const ALLOW_LIST: [PluginType; 6] = [ + PluginType::Attributes, + PluginType::PermanentFreezeDelegate, + PluginType::PermanentTransferDelegate, + PluginType::PermanentBurnDelegate, + PluginType::Royalties, + PluginType::UpdateDelegate, + ]; +} + +impl DataBlob for BubblegumV2 { + fn len(&self) -> usize { + // Stateless data blob + 0 + } +} + +impl PluginValidation for BubblegumV2 { + fn validate_add_plugin( + &self, + ctx: &PluginValidationContext, + ) -> Result { + if let Some(target_plugin) = ctx.target_plugin { + let plugin_type = PluginType::from(target_plugin); + if Self::ALLOW_LIST.contains(&plugin_type) { + abstain!() + } else if plugin_type == PluginType::BubblegumV2 { + // This plugin can only be added at creation time, so we + // always reject it. + reject!() + } else { + // All other plugins are not allowed on Bubblegum + // collections. + reject!() + } + } else { + abstain!() + } + } + + fn validate_remove_plugin( + &self, + ctx: &PluginValidationContext, + ) -> Result { + // This plugin cannot be removed so always reject it. + match ctx.target_plugin { + Some(Plugin::BubblegumV2(_)) => { + reject!() + } + _ => abstain!(), + } + } + + fn validate_add_external_plugin_adapter( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + // If the BubblegumV2 plugin is present, no external plugin adapters + // can be added. The BubblegumV2 plugin limits what can be on the + // collection to plugins that are supported and validated at runtime + // by the Bubblegum program. External plugin adapters may be added + // in the future but for now this subset was chosen. + reject!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_bubblegum_v2_len() { + let bubblegum_v2 = BubblegumV2::default(); + let serialized = bubblegum_v2.try_to_vec().unwrap(); + assert_eq!(serialized.len(), bubblegum_v2.len()); + } +} diff --git a/programs/mpl-core/src/plugins/internal/permanent/mod.rs b/programs/mpl-core/src/plugins/internal/permanent/mod.rs index a40dc28b..2fd37f23 100644 --- a/programs/mpl-core/src/plugins/internal/permanent/mod.rs +++ b/programs/mpl-core/src/plugins/internal/permanent/mod.rs @@ -1,9 +1,13 @@ +mod bubblegum_v2; mod edition; mod permanent_burn_delegate; mod permanent_freeze_delegate; +mod permanent_freeze_execute; mod permanent_transfer_delegate; +pub use bubblegum_v2::*; pub use edition::*; pub use permanent_burn_delegate::*; pub use permanent_freeze_delegate::*; +pub use permanent_freeze_execute::*; pub use permanent_transfer_delegate::*; diff --git a/programs/mpl-core/src/plugins/internal/permanent/permanent_freeze_execute.rs b/programs/mpl-core/src/plugins/internal/permanent/permanent_freeze_execute.rs new file mode 100644 index 00000000..7a97bdaa --- /dev/null +++ b/programs/mpl-core/src/plugins/internal/permanent/permanent_freeze_execute.rs @@ -0,0 +1,95 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::program_error::ProgramError; + +use crate::{ + plugins::{reject, Plugin, PluginType}, + state::DataBlob, +}; + +use crate::plugins::{abstain, PluginValidation, PluginValidationContext, ValidationResult}; + +/// The permanent freeze execute plugin allows any authority to lock the asset so its **Execute** lifecycle +/// event can be conditionally blocked. The default authority for this plugin is the update authority. +#[repr(C)] +#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, Debug, PartialEq, Eq)] +pub struct PermanentFreezeExecute { + /// Indicates whether the asset's Execute lifecycle event is currently frozen. + pub frozen: bool, // 1 +} + +impl PermanentFreezeExecute { + const BASE_LEN: usize = 1; // The frozen boolean + + /// Initialize the PermanentFreezeExecute plugin, unfrozen by default. + pub fn new() -> Self { + Self { frozen: false } + } +} + +impl Default for PermanentFreezeExecute { + fn default() -> Self { + Self::new() + } +} + +impl DataBlob for PermanentFreezeExecute { + fn len(&self) -> usize { + Self::BASE_LEN + } +} + +impl PluginValidation for PermanentFreezeExecute { + /// Validate the execute lifecycle action. + /// If the asset is frozen, reject the Execute operation; otherwise abstain. + fn validate_execute( + &self, + _ctx: &PluginValidationContext, + ) -> Result { + if self.frozen { + reject!() + } else { + abstain!() + } + } + + fn validate_add_plugin( + &self, + ctx: &PluginValidationContext, + ) -> Result { + // This plugin can only be added at creation time, so we + // always reject it. + if ctx.target_plugin.is_some() + && PluginType::from(ctx.target_plugin.unwrap()) == PluginType::PermanentFreezeExecute + { + reject!() + } else { + abstain!() + } + } + + /// Validate the remove plugin lifecycle action. + fn validate_remove_plugin( + &self, + ctx: &PluginValidationContext, + ) -> Result { + if let Some(Plugin::PermanentFreezeExecute(stored)) = ctx.target_plugin { + // Only block removal if the stored plugin is frozen. + if stored.frozen { + return reject!(); + } + } + abstain!() + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_permanent_freeze_execute_len() { + let permanent_freeze_execute = PermanentFreezeExecute::default(); + let serialized = permanent_freeze_execute.try_to_vec().unwrap(); + assert_eq!(serialized.len(), permanent_freeze_execute.len()); + } +} diff --git a/programs/mpl-core/src/plugins/lifecycle.rs b/programs/mpl-core/src/plugins/lifecycle.rs index f80e12b9..f9bb7040 100644 --- a/programs/mpl-core/src/plugins/lifecycle.rs +++ b/programs/mpl-core/src/plugins/lifecycle.rs @@ -92,6 +92,8 @@ impl PluginType { PluginType::Autograph => CheckResult::CanReject, PluginType::VerifiedCreators => CheckResult::CanReject, PluginType::MasterEdition => CheckResult::CanReject, + PluginType::BubblegumV2 => CheckResult::CanReject, + PluginType::PermanentFreezeExecute => CheckResult::CanReject, _ => CheckResult::None, } } @@ -104,6 +106,8 @@ impl PluginType { PluginType::FreezeDelegate => CheckResult::CanReject, PluginType::PermanentFreezeDelegate => CheckResult::CanReject, PluginType::Edition => CheckResult::CanReject, + PluginType::BubblegumV2 => CheckResult::CanReject, + PluginType::PermanentFreezeExecute => CheckResult::CanReject, // We default to CanReject because Plugins with Authority::None cannot be removed. _ => CheckResult::CanReject, } @@ -165,6 +169,7 @@ impl PluginType { PluginType::BurnDelegate => CheckResult::CanApprove, PluginType::PermanentFreezeDelegate => CheckResult::CanReject, PluginType::PermanentBurnDelegate => CheckResult::CanApprove, + PluginType::Groups => CheckResult::CanReject, _ => CheckResult::None, } } @@ -201,6 +206,8 @@ impl PluginType { pub fn check_execute(plugin_type: &PluginType) -> CheckResult { #[allow(clippy::match_single_binding)] match plugin_type { + PluginType::FreezeExecute => CheckResult::CanReject, + PluginType::PermanentFreezeExecute => CheckResult::CanReject, _ => CheckResult::None, } } @@ -209,6 +216,7 @@ impl PluginType { pub fn check_add_external_plugin_adapter(plugin_type: &PluginType) -> CheckResult { #[allow(clippy::match_single_binding)] match plugin_type { + PluginType::BubblegumV2 => CheckResult::CanReject, _ => CheckResult::None, } } @@ -663,7 +671,6 @@ pub(crate) trait PluginValidation { /// The STRONGEST result is returned. #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub(crate) fn validate_plugin_checks<'a>( - key: Key, accounts: &'a [AccountInfo<'a>], checks: &BTreeMap, authority: &'a AccountInfo<'a>, @@ -685,13 +692,11 @@ pub(crate) fn validate_plugin_checks<'a>( let mut approved = false; let mut rejected = false; for (check_key, check_result, registry_record) in checks.values() { - if *check_key == key - && matches!( - check_result, - CheckResult::CanApprove | CheckResult::CanReject - ) - { - let account = match key { + if matches!( + check_result, + CheckResult::CanApprove | CheckResult::CanReject + ) { + let account = match check_key { Key::CollectionV1 => collection.ok_or(MplCoreError::InvalidCollection)?, Key::AssetV1 => asset.ok_or(MplCoreError::InvalidAsset)?, _ => unreachable!(), @@ -740,7 +745,6 @@ pub(crate) fn validate_plugin_checks<'a>( /// The STRONGEST result is returned. #[allow(clippy::too_many_arguments, clippy::type_complexity)] pub(crate) fn validate_external_plugin_adapter_checks<'a>( - key: Key, accounts: &'a [AccountInfo<'a>], external_checks: &BTreeMap< ExternalPluginAdapterKey, @@ -764,12 +768,8 @@ pub(crate) fn validate_external_plugin_adapter_checks<'a>( ) -> Result { let mut approved = false; for (check_key, check_result, external_registry_record) in external_checks.values() { - if *check_key == key - && (check_result.can_listen() - || check_result.can_approve() - || check_result.can_reject()) - { - let account = match key { + if check_result.can_listen() || check_result.can_approve() || check_result.can_reject() { + let account = match check_key { Key::CollectionV1 => collection.ok_or(MplCoreError::InvalidCollection)?, Key::AssetV1 => asset.ok_or(MplCoreError::InvalidAsset)?, _ => unreachable!(), diff --git a/programs/mpl-core/src/plugins/mod.rs b/programs/mpl-core/src/plugins/mod.rs index deda88f2..95cb9983 100644 --- a/programs/mpl-core/src/plugins/mod.rs +++ b/programs/mpl-core/src/plugins/mod.rs @@ -60,8 +60,15 @@ pub enum Plugin { VerifiedCreators(VerifiedCreators), /// Autograph plugin allows anybody to add their signature to the asset with an optional message Autograph(Autograph), + /// The Bubblegum V2 plugin allows a Core collection to contain Compressed NFTs (cNFTs) from the Bubblegum program. + BubblegumV2(BubblegumV2), + /// Freeze Execute plugin. + FreezeExecute(FreezeExecute), + /// Permanent Freeze Execute plugin allows the authority to freeze the execute lifecycle event. + PermanentFreezeExecute(PermanentFreezeExecute), + /// Groups plugin stores parent group memberships of a collection for taxonomy purposes + Groups(Groups), } - impl Plugin { /// Get the default authority for a plugin which defines who must allow the plugin to be created. pub fn manager(&self) -> Authority { @@ -103,6 +110,10 @@ impl Plugin { Plugin::ImmutableMetadata(inner) => inner, Plugin::VerifiedCreators(inner) => inner, Plugin::Autograph(inner) => inner, + Plugin::BubblegumV2(inner) => inner, + Plugin::FreezeExecute(inner) => inner, + Plugin::PermanentFreezeExecute(inner) => inner, + Plugin::Groups(inner) => inner, } } } @@ -134,6 +145,12 @@ impl DataBlob for Plugin { Plugin::ImmutableMetadata(immutable_metadata) => immutable_metadata.len(), Plugin::VerifiedCreators(verified_creators) => verified_creators.len(), Plugin::Autograph(autograph) => autograph.len(), + Plugin::BubblegumV2(bubblegum_v2) => bubblegum_v2.len(), + Plugin::FreezeExecute(freeze_execute) => freeze_execute.len(), + Plugin::PermanentFreezeExecute(permanent_freeze_execute) => { + permanent_freeze_execute.len() + }, + Plugin::Groups(groups) => groups.len(), } } } @@ -186,6 +203,14 @@ pub enum PluginType { VerifiedCreators, /// Autograph plugin. Autograph, + /// Bubblegum V2 plugin. + BubblegumV2, + /// Freeze Execute plugin. + FreezeExecute, + /// Permanent Freeze Execute plugin. + PermanentFreezeExecute, + /// Groups plugin. + Groups, } impl PluginType { @@ -194,10 +219,11 @@ impl PluginType { } /// The list of permanent delegate types. -pub const PERMANENT_DELEGATES: [PluginType; 3] = [ +pub const PERMANENT_DELEGATES: [PluginType; 4] = [ PluginType::PermanentFreezeDelegate, PluginType::PermanentTransferDelegate, PluginType::PermanentBurnDelegate, + PluginType::PermanentFreezeExecute, ]; impl DataBlob for PluginType { @@ -224,6 +250,10 @@ impl From<&Plugin> for PluginType { Plugin::MasterEdition(_) => PluginType::MasterEdition, Plugin::VerifiedCreators(_) => PluginType::VerifiedCreators, Plugin::Autograph(_) => PluginType::Autograph, + Plugin::BubblegumV2(_) => PluginType::BubblegumV2, + Plugin::FreezeExecute(_) => PluginType::FreezeExecute, + Plugin::PermanentFreezeExecute(_) => PluginType::PermanentFreezeExecute, + Plugin::Groups(_) => PluginType::Groups, } } } @@ -247,6 +277,12 @@ impl PluginType { PluginType::MasterEdition => Authority::UpdateAuthority, PluginType::VerifiedCreators => Authority::UpdateAuthority, PluginType::Autograph => Authority::Owner, + PluginType::BubblegumV2 => Authority::Address { + address: mpl_bubblegum::ID, + }, + PluginType::FreezeExecute => Authority::Owner, + PluginType::PermanentFreezeExecute => Authority::UpdateAuthority, + PluginType::Groups => Authority::UpdateAuthority, } } } @@ -297,6 +333,10 @@ mod test { Plugin::ImmutableMetadata(ImmutableMetadata {}), Plugin::VerifiedCreators(VerifiedCreators { signatures: vec![] }), Plugin::Autograph(Autograph { signatures: vec![] }), + Plugin::BubblegumV2(BubblegumV2 {}), + Plugin::FreezeExecute(FreezeExecute { frozen: false }), + Plugin::PermanentFreezeExecute(PermanentFreezeExecute { frozen: false }), + Plugin::Groups(Groups { groups: vec![] }), ]; assert_eq!( @@ -412,6 +452,14 @@ mod test { message: "test".to_string(), }], })], + vec![Plugin::BubblegumV2(BubblegumV2 {})], + vec![Plugin::FreezeExecute(FreezeExecute { frozen: true })], + vec![Plugin::Groups(Groups { + groups: vec![Pubkey::default()], + })], + vec![Plugin::PermanentFreezeExecute(PermanentFreezeExecute { + frozen: true, + })], ]; assert_eq!( diff --git a/programs/mpl-core/src/plugins/plugin_registry.rs b/programs/mpl-core/src/plugins/plugin_registry.rs index c559db9d..41d92553 100644 --- a/programs/mpl-core/src/plugins/plugin_registry.rs +++ b/programs/mpl-core/src/plugins/plugin_registry.rs @@ -85,26 +85,27 @@ impl PluginRegistryV1 { record.offset = (record.offset as isize) .checked_add(size_diff) .ok_or(MplCoreError::NumericalOverflow)? - as usize; + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; } } for record in &mut self.external_registry { if record.offset > offset { - solana_program::msg!("Bumping Record: {:?}", record); record.offset = (record.offset as isize) .checked_add(size_diff) .ok_or(MplCoreError::NumericalOverflow)? - as usize; + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; if let Some(data_offset) = record.data_offset { if data_offset > offset { - solana_program::msg!("Bumping Data: {:?}", record); record.data_offset = Some( (data_offset as isize) .checked_add(size_diff) .ok_or(MplCoreError::NumericalOverflow)? - as usize, + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?, ); } } @@ -198,6 +199,13 @@ impl ExternalRegistryRecord { .clone_from(&update_info.lifecycle_checks) } } + ExternalPluginAdapterUpdateInfo::AgentIdentity(update_info) => { + if let Some(checks) = &update_info.lifecycle_checks { + validate_lifecycle_checks(checks, false)?; + self.lifecycle_checks + .clone_from(&update_info.lifecycle_checks) + } + } _ => (), } diff --git a/programs/mpl-core/src/plugins/utils.rs b/programs/mpl-core/src/plugins/utils.rs index c585cadc..d1a6a2b1 100644 --- a/programs/mpl-core/src/plugins/utils.rs +++ b/programs/mpl-core/src/plugins/utils.rs @@ -383,6 +383,13 @@ pub fn initialize_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( }) => (*init_plugin_authority, None), // The DataSection is only updated via its managing plugin so it has no authority. ExternalPluginAdapterInitInfo::DataSection(_) => (Some(Authority::None), None), + ExternalPluginAdapterInitInfo::AgentIdentity(init_info) => { + validate_lifecycle_checks(&init_info.lifecycle_checks, false)?; + ( + init_info.init_plugin_authority, + Some(init_info.lifecycle_checks.clone()), + ) + } }; let old_registry_offset = plugin_header.plugin_registry_offset; @@ -478,30 +485,43 @@ pub fn update_external_plugin_adapter_data<'a, T: DataBlob + SolanaAccount>( let data_offset = record.data_offset.ok_or(MplCoreError::InvalidPlugin)?; let data_len = record.data_len.ok_or(MplCoreError::InvalidPlugin)?; let new_data_len = data.len(); + let old_registry_offset = plugin_header.plugin_registry_offset; let size_diff = (new_data_len as isize) .checked_sub(data_len as isize) .ok_or(MplCoreError::NumericalOverflow)?; + let next_plugin_offset = data_offset + .checked_add(data_len) + .ok_or(MplCoreError::NumericalOverflow)?; + let new_next_plugin_offset: usize = (next_plugin_offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; + // Update any offsets that will change. plugin_registry.bump_offsets(record.offset, size_diff)?; - let new_registry_offset = (plugin_header.plugin_registry_offset as isize) + let new_registry_offset: usize = (old_registry_offset as isize) .checked_add(size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; - plugin_header.plugin_registry_offset = new_registry_offset as usize; + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; + plugin_header.plugin_registry_offset = new_registry_offset; - let new_size = (account.data_len() as isize) + let new_size: usize = (account.data_len() as isize) .checked_add(size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; - resize_or_reallocate_account(account, payer, system_program, new_size as usize)?; + // Capture old data length before any realloc, as realloc changes data_len(). + let old_data_len = account.data_len(); - let next_plugin_offset = data_offset - .checked_add(data_len) - .ok_or(MplCoreError::NumericalOverflow)?; - let new_next_plugin_offset = (next_plugin_offset as isize) - .checked_add(size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; + if size_diff > 0 { + // Growing: realloc first to make room for the rightward shift. + resize_or_reallocate_account(account, payer, system_program, new_size)?; + } // SAFETY: `borrow_mut` will always return a valid pointer. // new_next_plugin_offset is derived from next_plugin_offset and size_diff using @@ -510,12 +530,17 @@ pub fn update_external_plugin_adapter_data<'a, T: DataBlob + SolanaAccount>( unsafe { let base = account.data.borrow_mut().as_mut_ptr(); sol_memmove( - base.add(new_next_plugin_offset as usize), + base.add(new_next_plugin_offset), base.add(next_plugin_offset), - account.data_len().saturating_sub(next_plugin_offset), + old_data_len.saturating_sub(next_plugin_offset), ) } + if size_diff < 0 { + // Shrinking: realloc after memmove to preserve data before truncation. + resize_or_reallocate_account(account, payer, system_program, new_size)?; + } + sol_memcpy( &mut account.data.borrow_mut()[data_offset..], data, @@ -530,7 +555,7 @@ pub fn update_external_plugin_adapter_data<'a, T: DataBlob + SolanaAccount>( .ok_or(MplCoreError::InvalidPlugin)?; plugin_registry.external_registry[record_index].data_len = Some(new_data_len); - plugin_registry.save(account, new_registry_offset as usize)?; + plugin_registry.save(account, new_registry_offset)?; plugin_header.save(account, core.map_or(0, |core| core.len()))?; Ok(()) @@ -747,15 +772,23 @@ pub fn approve_authority_on_plugin<'a, T: CoreAsset>( .find(|record| record.plugin_type == *plugin_type) .ok_or(MplCoreError::PluginNotFound)?; - registry_record.authority = *new_authority; + let old_authority_bytes = registry_record.authority.try_to_vec()?; + let new_authority_bytes = new_authority.try_to_vec()?; + let size_diff = (new_authority_bytes.len() as isize) + .checked_sub(old_authority_bytes.len() as isize) + .ok_or(MplCoreError::NumericalOverflow)?; - let authority_bytes = new_authority.try_to_vec()?; + registry_record.authority = *new_authority; - let new_size = account - .data_len() - .checked_add(authority_bytes.len()) - .ok_or(MplCoreError::NumericalOverflow)?; - resize_or_reallocate_account(account, payer, system_program, new_size)?; + if size_diff != 0 { + let new_size = (account.data_len() as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)?; + let new_size: usize = new_size + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; + resize_or_reallocate_account(account, payer, system_program, new_size)?; + } plugin_registry.save(account, plugin_header.plugin_registry_offset)?; @@ -873,6 +906,8 @@ fn check_plugin_key( Err(_) => return Err(MplCoreError::DeserializationError.into()), } } + // AgentIdentity is a unit variant - only one per asset, so type match is sufficient. + ExternalPluginAdapterKey::AgentIdentity => true, }) { Ok(true) diff --git a/programs/mpl-core/src/processor/add_assets_to_group.rs b/programs/mpl-core/src/processor/add_assets_to_group.rs new file mode 100644 index 00000000..fd3f509b --- /dev/null +++ b/programs/mpl-core/src/processor/add_assets_to_group.rs @@ -0,0 +1,114 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, +}; + +use super::groups_plugin_utils::process_asset_groups_plugin_add; +use crate::{ + error::MplCoreError, + instruction::accounts::AddAssetsToGroupV1Accounts, + instruction::accounts::Context, + state::{GroupV1, Key, SolanaAccount, MAX_GROUP_VECTOR_SIZE}, + utils::{ + is_valid_asset_authority, is_valid_group_authority, load_key, resolve_authority, + save_flat_group, + }, +}; + +/// Arguments for the `AddAssetsToGroupV1` instruction. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct AddAssetsToGroupV1Args {} + +/// Processor for the `AddAssetsToGroupV1` instruction. +/// +/// Remaining accounts: one or more `AssetV1` accounts to add, optionally +/// followed by (or interleaved with) read-only `CollectionV1` accounts that +/// are needed for authority resolution when an asset's update authority is +/// `UpdateAuthority::Collection`. Accounts are classified by their on-chain +/// key discriminator; only `AssetV1` accounts are processed as group members. +#[allow(clippy::too_many_arguments)] +pub(crate) fn add_assets_to_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + _args: AddAssetsToGroupV1Args, +) -> ProgramResult { + let ctx: Context = AddAssetsToGroupV1Accounts::context(accounts)?; + + let group_info = ctx.accounts.group; + let payer_info = ctx.accounts.payer; + let authority_info_opt = ctx.accounts.authority; + let system_program_info = ctx.accounts.system_program; + let remaining_accounts = ctx.remaining_accounts; + + assert_signer(payer_info)?; + let authority_info = resolve_authority(payer_info, authority_info_opt)?; + if authority_info.key != payer_info.key { + assert_signer(authority_info)?; + } + + if system_program_info.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !group_info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + let mut group = GroupV1::load(group_info, 0)?; + + if !is_valid_group_authority(group_info, authority_info)? { + msg!("Error: Invalid authority for group"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Remaining accounts may include supplemental collection accounts used for + // authority resolution when assets are collection-managed. + let mut asset_accounts: Vec<&AccountInfo> = Vec::with_capacity(remaining_accounts.len()); + for account_info in remaining_accounts.iter() { + match load_key(account_info, 0)? { + Key::AssetV1 => asset_accounts.push(account_info), + Key::CollectionV1 => {} + _ => { + msg!("Error: Expected remaining account to be AssetV1 or CollectionV1"); + return Err(MplCoreError::IncorrectAccount.into()); + } + } + } + if asset_accounts.is_empty() && !remaining_accounts.is_empty() { + msg!("Error: No asset accounts provided in remaining accounts"); + return Err(MplCoreError::IncorrectAccount.into()); + } + + for asset_info in asset_accounts { + if !asset_info.is_writable { + msg!("Error: Asset account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + if !is_valid_asset_authority(asset_info, authority_info, accounts)? { + return Err(MplCoreError::InvalidAuthority.into()); + } + + if group.assets.contains(asset_info.key) { + return Err(MplCoreError::DuplicateEntry.into()); + } + + if group.assets.len() >= MAX_GROUP_VECTOR_SIZE { + return Err(MplCoreError::GroupVectorFull.into()); + } + + group.assets.push(*asset_info.key); + + process_asset_groups_plugin_add( + asset_info, + *group_info.key, + payer_info, + system_program_info, + )?; + } + + save_flat_group(group_info, &group, payer_info, system_program_info)?; + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/add_collections_to_group.rs b/programs/mpl-core/src/processor/add_collections_to_group.rs new file mode 100644 index 00000000..c10249c6 --- /dev/null +++ b/programs/mpl-core/src/processor/add_collections_to_group.rs @@ -0,0 +1,105 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, +}; + +use super::groups_plugin_utils::process_collection_groups_plugin_add; +use crate::{ + error::MplCoreError, + instruction::accounts::{AddCollectionsToGroupV1Accounts, Context}, + state::{CollectionV1, GroupV1, SolanaAccount, MAX_GROUP_VECTOR_SIZE}, + utils::{ + is_valid_collection_authority, is_valid_group_authority, resolve_authority, save_flat_group, + }, +}; + +/// Arguments for the `AddCollectionsToGroupV1` instruction. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct AddCollectionsToGroupV1Args {} + +/// Processor for the `AddCollectionsToGroupV1` instruction. +#[allow(clippy::too_many_arguments)] +pub(crate) fn add_collections_to_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + _args: AddCollectionsToGroupV1Args, +) -> ProgramResult { + // Use generated context to access fixed and remaining accounts. + let ctx: Context = + AddCollectionsToGroupV1Accounts::context(accounts)?; + + let group_info = ctx.accounts.group; + let payer_info = ctx.accounts.payer; + let authority_info_opt = ctx.accounts.authority; + let system_program_info = ctx.accounts.system_program; + + // Dynamic list of collection accounts passed after the fixed accounts. + let remaining_accounts = ctx.remaining_accounts; + + // Basic guards. + assert_signer(payer_info)?; + let authority_info = resolve_authority(payer_info, authority_info_opt)?; + if authority_info.key != payer_info.key { + assert_signer(authority_info)?; + } + + if system_program_info.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !group_info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + // Deserialize group. + let mut group = GroupV1::load(group_info, 0)?; + + // Authority check: must be the group's update authority. + if !is_valid_group_authority(group_info, authority_info)? { + msg!("Error: Invalid authority for group account"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Process each collection. + for collection_info in remaining_accounts.iter() { + // Verify collection is writable. + if !collection_info.is_writable { + msg!("Error: Collection account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + // Deserialize collection. + let _collection_core = CollectionV1::load(collection_info, 0)?; + + // Authority must be update authority of the collection as well. + if !is_valid_collection_authority(collection_info, authority_info)? { + msg!("Error: Signer is not collection update authority/delegate"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + if group.collections.contains(collection_info.key) { + return Err(MplCoreError::DuplicateEntry.into()); + } + + if group.collections.len() >= MAX_GROUP_VECTOR_SIZE { + return Err(MplCoreError::GroupVectorFull.into()); + } + + group.collections.push(*collection_info.key); + + // 2. Update or create Groups plugin on the collection. + process_collection_groups_plugin_add( + collection_info, + *group_info.key, + payer_info, + system_program_info, + )?; + + // The collection core itself does not change; no reserialization needed. + } + + save_flat_group(group_info, &group, payer_info, system_program_info)?; + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/add_external_plugin_adapter.rs b/programs/mpl-core/src/processor/add_external_plugin_adapter.rs index 4d68474f..2509ce69 100644 --- a/programs/mpl-core/src/processor/add_external_plugin_adapter.rs +++ b/programs/mpl-core/src/processor/add_external_plugin_adapter.rs @@ -51,7 +51,7 @@ pub(crate) fn add_external_plugin_adapter<'a>( } // TODO: This should be handled in the validate call. - match args.init_info { + match &args.init_info { ExternalPluginAdapterInitInfo::LinkedLifecycleHook(_) | ExternalPluginAdapterInitInfo::LinkedAppData(_) => { return Err(MplCoreError::InvalidPluginAdapterTarget.into()) @@ -74,6 +74,9 @@ pub(crate) fn add_external_plugin_adapter<'a>( } ExternalPluginAdapterInitInfo::LinkedAppData(app_data) => app_data.init_plugin_authority, ExternalPluginAdapterInitInfo::DataSection(_) => unreachable!(), + ExternalPluginAdapterInitInfo::AgentIdentity(agent_identity) => { + agent_identity.init_plugin_authority + } } .unwrap_or(Authority::UpdateAuthority); let validation_ctx = PluginValidationContext { @@ -161,8 +164,14 @@ pub(crate) fn add_collection_external_plugin_adapter<'a>( } } - if let ExternalPluginAdapterInitInfo::DataSection(_) = args.init_info { - return Err(MplCoreError::CannotAddDataSection.into()); + match &args.init_info { + ExternalPluginAdapterInitInfo::DataSection(_) => { + return Err(MplCoreError::CannotAddDataSection.into()); + } + ExternalPluginAdapterInitInfo::AgentIdentity(_) => { + return Err(MplCoreError::InvalidPluginAdapterTarget.into()); + } + _ => {} } let external_plugin_adapter = ExternalPluginAdapter::from(&args.init_info); @@ -176,7 +185,8 @@ pub(crate) fn add_collection_external_plugin_adapter<'a>( lifecycle_hook.init_plugin_authority } ExternalPluginAdapterInitInfo::LinkedAppData(app_data) => app_data.init_plugin_authority, - ExternalPluginAdapterInitInfo::DataSection(_) => unreachable!(), + ExternalPluginAdapterInitInfo::DataSection(_) + | ExternalPluginAdapterInitInfo::AgentIdentity(_) => unreachable!(), } .unwrap_or(Authority::UpdateAuthority); let validation_ctx = PluginValidationContext { diff --git a/programs/mpl-core/src/processor/add_groups_to_group.rs b/programs/mpl-core/src/processor/add_groups_to_group.rs new file mode 100644 index 00000000..310b2db5 --- /dev/null +++ b/programs/mpl-core/src/processor/add_groups_to_group.rs @@ -0,0 +1,136 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, + pubkey::Pubkey, +}; + +use crate::{ + error::MplCoreError, + instruction::accounts::{AddGroupsToGroupV1Accounts, Context}, + state::{GroupV1, SolanaAccount, MAX_GROUP_NESTING_DEPTH, MAX_GROUP_VECTOR_SIZE}, + utils::{is_valid_group_authority, resolve_authority, save_flat_group}, +}; + +/// Arguments for the `AddGroupsToGroupV1` instruction. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct AddGroupsToGroupV1Args { + /// The list of child groups to add to the parent group. + pub(crate) groups: Vec, +} + +/// Processor for the `AddGroupsToGroupV1` instruction. +#[allow(clippy::too_many_arguments)] +pub(crate) fn add_groups_to_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + args: AddGroupsToGroupV1Args, +) -> ProgramResult { + // Expected account layout: + // 0. [writable] Parent group account + // 1. [writable, signer] Payer account (also default authority) + // 2. [signer] Optional authority (group update authority) + // 3. [] System program + // 4..N [writable] Child group accounts, one for each pubkey in args.groups + let ctx: Context = AddGroupsToGroupV1Accounts::context(accounts)?; + let parent_group_info = ctx.accounts.parent_group; + let payer_info = ctx.accounts.payer; + let authority_info_opt = ctx.accounts.authority; + let system_program_info = ctx.accounts.system_program; + let child_group_accounts = ctx.remaining_accounts; + + // Basic guards. + assert_signer(payer_info)?; + let authority_info = resolve_authority(payer_info, authority_info_opt)?; + if authority_info.key != payer_info.key { + assert_signer(authority_info)?; + } + + if system_program_info.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !parent_group_info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + // Validate arg count matches remaining accounts. + if child_group_accounts.len() != args.groups.len() { + msg!( + "Error: Number of group accounts ({}) does not match number of pubkeys in args ({}).", + child_group_accounts.len(), + args.groups.len() + ); + return Err(ProgramError::NotEnoughAccountKeys); + } + + // Deserialize parent group. + let mut parent_group = GroupV1::load(parent_group_info, 0)?; + + // Authority check: must be the parent group's update authority. + if !is_valid_group_authority(parent_group_info, authority_info)? { + msg!("Error: Invalid authority for parent group account"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Process each child group account. + for (i, child_info) in child_group_accounts.iter().enumerate() { + // Ensure account key matches expected pubkey. + if child_info.key != &args.groups[i] { + msg!( + "Error: Child group account at position {} does not match provided pubkey list", + i + ); + return Err(MplCoreError::IncorrectAccount.into()); + } + + // Ensure child group account is writable. + if !child_info.is_writable { + msg!("Error: Child group account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + if child_info.key == parent_group_info.key { + msg!("Error: Parent group cannot be added as its own child group"); + return Err(MplCoreError::IncorrectAccount.into()); + } + + // Deserialize child group. + let mut child_group = GroupV1::load(child_info, 0)?; + + // Authority must also be the child group's update authority. + if !is_valid_group_authority(child_info, authority_info)? { + msg!("Error: Signer is not child group update authority"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + if parent_group.groups.contains(child_info.key) { + return Err(MplCoreError::DuplicateEntry.into()); + } + + if parent_group.groups.len() >= MAX_GROUP_VECTOR_SIZE { + return Err(MplCoreError::GroupVectorFull.into()); + } + + if child_group.parent_groups.len() >= MAX_GROUP_NESTING_DEPTH { + msg!("Error: Child group has reached maximum nesting depth"); + return Err(MplCoreError::GroupNestingDepthExceeded.into()); + } + + parent_group.groups.push(*child_info.key); + + if !child_group.parent_groups.contains(parent_group_info.key) { + child_group.parent_groups.push(*parent_group_info.key); + save_flat_group(child_info, &child_group, payer_info, system_program_info)?; + } + } + + save_flat_group( + parent_group_info, + &parent_group, + payer_info, + system_program_info, + )?; + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/add_plugin.rs b/programs/mpl-core/src/processor/add_plugin.rs index 95a46db1..736f9526 100644 --- a/programs/mpl-core/src/processor/add_plugin.rs +++ b/programs/mpl-core/src/processor/add_plugin.rs @@ -47,6 +47,13 @@ pub(crate) fn add_plugin<'a>( return Err(MplCoreError::NotAvailable.into()); } + // TODO move into plugin validation when asset/collection is part of validation context + let plugin_type = PluginType::from(&args.plugin); + if plugin_type == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + + let target_plugin_authority = args.init_authority.unwrap_or(args.plugin.manager()); // TODO: Seed with Rejected @@ -132,6 +139,12 @@ pub(crate) fn add_collection_plugin<'a>( } let target_plugin_authority = args.init_authority.unwrap_or(args.plugin.manager()); + // Reject attempts to add a Groups plugin via the generic collection plugin pathway. + // Groups plugins must be managed exclusively by the dedicated Group instructions + // (Add/Remove Collections To/From Group, etc.). + if PluginType::from(&args.plugin) == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } let validation_ctx = PluginValidationContext { accounts, asset_info: None, diff --git a/programs/mpl-core/src/processor/approve_plugin_authority.rs b/programs/mpl-core/src/processor/approve_plugin_authority.rs index 715c0de3..da5c86ae 100644 --- a/programs/mpl-core/src/processor/approve_plugin_authority.rs +++ b/programs/mpl-core/src/processor/approve_plugin_authority.rs @@ -47,6 +47,11 @@ pub(crate) fn approve_plugin_authority<'a>( return Err(MplCoreError::NotAvailable.into()); } + // Groups plugins must be managed only via Group-specific instructions; approve is not allowed. + if args.plugin_type == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (plugin_authority, plugin) = fetch_wrapped_plugin::(ctx.accounts.asset, None, args.plugin_type)?; @@ -111,6 +116,11 @@ pub(crate) fn approve_collection_plugin_authority<'a>( } } + // Groups plugins must be managed only via Group-specific instructions; approve is not allowed. + if args.plugin_type == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (plugin_authority, plugin) = fetch_wrapped_plugin::(ctx.accounts.collection, None, args.plugin_type)?; diff --git a/programs/mpl-core/src/processor/burn.rs b/programs/mpl-core/src/processor/burn.rs index fe61bde8..a7dd6d84 100644 --- a/programs/mpl-core/src/processor/burn.rs +++ b/programs/mpl-core/src/processor/burn.rs @@ -9,7 +9,7 @@ use crate::{ state::{AssetV1, CollectionV1, CompressionProof, Key, SolanaAccount, Wrappable}, utils::{ close_program_account, load_key, rebuild_account_state_from_proof_data, resolve_authority, - validate_asset_permissions, verify_proof, + validate_asset_permissions, validate_collection_permissions, verify_proof, }, }; @@ -144,6 +144,27 @@ pub(crate) fn burn_collection<'a>( return Err(MplCoreError::InvalidAuthority.into()); } + // Validate collection/plugin permissions for burn. We intentionally keep + // the core authority semantics aligned with previous behavior (update + // authority only) while enabling burn-time plugin rejection checks such as + // the Groups plugin. + let _ = validate_collection_permissions( + accounts, + authority, + ctx.accounts.collection, + None, + None, + None, + None, + None, + CollectionV1::check_update, + PluginType::check_burn, + CollectionV1::validate_update, + Plugin::validate_burn, + Some(ExternalPluginAdapter::validate_burn), + Some(HookableLifecycleEvent::Burn), + )?; + process_burn(ctx.accounts.collection, ctx.accounts.payer) } diff --git a/programs/mpl-core/src/processor/close_group.rs b/programs/mpl-core/src/processor/close_group.rs new file mode 100644 index 00000000..9da1c2ac --- /dev/null +++ b/programs/mpl-core/src/processor/close_group.rs @@ -0,0 +1,58 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, +}; + +use crate::{ + error::MplCoreError, + instruction::accounts::CloseGroupV1Accounts, + state::{GroupV1, SolanaAccount}, + utils::{close_program_account, is_valid_group_authority, resolve_authority}, +}; + +/// Arguments for the `CloseGroupV1` instruction. +/// +/// Currently, no arguments are required but the struct is kept for +/// forward-compatibility and to mirror the pattern used by other +/// processors in the codebase. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone, Default)] +pub(crate) struct CloseGroupV1Args {} + +/// Processor for the `CloseGroupV1` instruction. +pub(crate) fn close_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + _args: CloseGroupV1Args, +) -> ProgramResult { + // Derive the typed account context from the raw slice. + let ctx = CloseGroupV1Accounts::context(accounts)?; + + // Basic guards. + assert_signer(ctx.accounts.payer)?; + let authority = resolve_authority(ctx.accounts.payer, ctx.accounts.authority)?; + + if !ctx.accounts.group.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + // Deserialize the group account. + let group = GroupV1::load(ctx.accounts.group, 0)?; + + // Ensure the signer is the update authority of the group. + if !is_valid_group_authority(ctx.accounts.group, authority)? { + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Ensure the group has no children, parents, or assets. + if !(group.collections.is_empty() + && group.groups.is_empty() + && group.parent_groups.is_empty() + && group.assets.is_empty()) + { + return Err(MplCoreError::GroupMustBeEmpty.into()); + } + + // Close the group account, transferring rent-exempt lamports back to the payer. + close_program_account(ctx.accounts.group, ctx.accounts.payer) +} diff --git a/programs/mpl-core/src/processor/create.rs b/programs/mpl-core/src/processor/create.rs index e585a01a..49f3206a 100644 --- a/programs/mpl-core/src/processor/create.rs +++ b/programs/mpl-core/src/processor/create.rs @@ -183,6 +183,13 @@ pub(crate) fn process_create<'a>( ctx.accounts.system_program, )?; for plugin in &plugins { + // TODO move into plugin validation when asset/collection is part of validation context + let plugin_type = PluginType::from(&plugin.plugin); + if plugin_type == PluginType::BubblegumV2 + || plugin_type == PluginType::Groups + { + return Err(MplCoreError::InvalidPlugin.into()); + } if PluginType::check_create(&PluginType::from(&plugin.plugin)) != CheckResult::None { diff --git a/programs/mpl-core/src/processor/create_collection.rs b/programs/mpl-core/src/processor/create_collection.rs index c084452f..3c8e3bcf 100644 --- a/programs/mpl-core/src/processor/create_collection.rs +++ b/programs/mpl-core/src/processor/create_collection.rs @@ -4,14 +4,15 @@ use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, program::invoke, program_memory::sol_memcpy, rent::Rent, system_instruction, system_program, sysvar::Sysvar, }; +use std::collections::HashSet; use crate::{ error::MplCoreError, instruction::accounts::CreateCollectionV2Accounts, plugins::{ create_meta_idempotent, create_plugin_meta, initialize_external_plugin_adapter, - initialize_plugin, CheckResult, ExternalPluginAdapterInitInfo, Plugin, PluginAuthorityPair, - PluginType, PluginValidationContext, ValidationResult, + initialize_plugin, BubblegumV2, CheckResult, ExternalPluginAdapterInitInfo, Plugin, + PluginAuthorityPair, PluginType, PluginValidationContext, ValidationResult, }, state::{Authority, CollectionV1, Key}, }; @@ -111,6 +112,7 @@ pub(crate) fn process_create_collection<'a>( let mut approved = true; let mut force_approved = false; + let mut has_bubblegum_v2 = false; if let Some(plugins) = args.plugins { if !plugins.is_empty() { let (header_offset, mut plugin_header, mut plugin_registry) = @@ -120,6 +122,20 @@ pub(crate) fn process_create_collection<'a>( ctx.accounts.payer, ctx.accounts.system_program, )?; + + // See if the new collection will have the Bubblegum V2 plugin. + has_bubblegum_v2 = plugins + .iter() + .any(|p| PluginType::from(&p.plugin) == PluginType::BubblegumV2); + + // If the Bubblegum V2 plugin is present, only a limited set of other plugins is + // allowed on the collection. + let bubblegum_v2_allow_list: Option> = if has_bubblegum_v2 { + Some(BubblegumV2::ALLOW_LIST.iter().cloned().collect()) + } else { + None + }; + for plugin in &plugins { // Cannot have owner-managed plugins on collection. if plugin.plugin.manager() == Authority::Owner { @@ -128,10 +144,18 @@ pub(crate) fn process_create_collection<'a>( // TODO move into plugin validation when asset/collection is part of validation context let plugin_type = PluginType::from(&plugin.plugin); - if plugin_type == PluginType::Edition { + if plugin_type == PluginType::Edition || plugin_type == PluginType::Groups { return Err(MplCoreError::InvalidPlugin.into()); } + // Validate against the Bubblegum V2 allow list. + if let Some(allow_list) = &bubblegum_v2_allow_list { + if plugin_type != PluginType::BubblegumV2 && !allow_list.contains(&plugin_type) + { + return Err(MplCoreError::BlockedByBubblegumV2.into()); + } + } + if PluginType::check_create(&plugin_type) != CheckResult::None { let validation_ctx = PluginValidationContext { accounts, @@ -154,9 +178,22 @@ pub(crate) fn process_create_collection<'a>( _ => (), }; } + + // Bubblegum V2 plugin always has a fixed authority. + let authority = if plugin_type == PluginType::BubblegumV2 { + if let Some(supplied) = &plugin.authority { + if supplied != &plugin.plugin.manager() { + return Err(MplCoreError::InvalidAuthority.into()); + } + } + plugin.plugin.manager() + } else { + plugin.authority.unwrap_or(plugin.plugin.manager()) + }; + initialize_plugin::( &plugin.plugin, - &plugin.authority.unwrap_or(plugin.plugin.manager()), + &authority, header_offset, &mut plugin_header, &mut plugin_registry, @@ -170,6 +207,10 @@ pub(crate) fn process_create_collection<'a>( if let Some(plugins) = args.external_plugin_adapters { if !plugins.is_empty() { + if has_bubblegum_v2 { + return Err(MplCoreError::BlockedByBubblegumV2.into()); + } + let (_, header_offset, mut plugin_header, mut plugin_registry) = create_meta_idempotent::( ctx.accounts.collection, @@ -177,8 +218,14 @@ pub(crate) fn process_create_collection<'a>( ctx.accounts.system_program, )?; for plugin_init_info in &plugins { - if let ExternalPluginAdapterInitInfo::DataSection(_) = plugin_init_info { - return Err(MplCoreError::CannotAddDataSection.into()); + match plugin_init_info { + ExternalPluginAdapterInitInfo::DataSection(_) => { + return Err(MplCoreError::CannotAddDataSection.into()); + } + ExternalPluginAdapterInitInfo::AgentIdentity(_) => { + return Err(MplCoreError::InvalidPluginAdapterTarget.into()); + } + _ => (), } initialize_external_plugin_adapter::( diff --git a/programs/mpl-core/src/processor/create_group.rs b/programs/mpl-core/src/processor/create_group.rs new file mode 100644 index 00000000..f5438803 --- /dev/null +++ b/programs/mpl-core/src/processor/create_group.rs @@ -0,0 +1,322 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program::invoke, + program_error::ProgramError, pubkey::Pubkey, rent::Rent, system_instruction, system_program, + sysvar::Sysvar, +}; + +use super::groups_plugin_utils::{ + process_asset_groups_plugin_add, process_collection_groups_plugin_add, +}; +use crate::{ + error::MplCoreError, + instruction::accounts::CreateGroupV1Accounts, + state::{GroupV1, Key, SolanaAccount, MAX_GROUP_NESTING_DEPTH, MAX_GROUP_VECTOR_SIZE}, + utils::{ + is_valid_asset_authority, is_valid_collection_authority, is_valid_group_authority, + load_key, resolve_authority, save_flat_group, + }, +}; + +use crate::state::RelationshipKind; +use std::collections::HashSet; + +/// Arguments for the `CreateGroupV1` instruction. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct CreateGroupV1Args { + /// Human-readable display name for the group. + pub(crate) name: String, + /// URI pointing to off-chain JSON describing the group. + pub(crate) uri: String, + /// Relationships (collections, child groups, parent groups, assets) to link at creation. + pub(crate) relationships: Vec, +} + +/// Processor for the `CreateGroupV1` instruction. +/// +/// Remaining accounts: relationship accounts in category order (collections, +/// child groups, parent groups, assets), then optionally any read-only +/// `CollectionV1` accounts needed for authority resolution of +/// collection-managed assets. +pub(crate) fn create_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + args: CreateGroupV1Args, +) -> ProgramResult { + // Derive the typed account context from the raw slice. + let ctx = CreateGroupV1Accounts::context(accounts)?; + let rent = Rent::get()?; + + // Basic guards. + assert_signer(ctx.accounts.group)?; + assert_signer(ctx.accounts.payer)?; + let authority_info = resolve_authority(ctx.accounts.payer, ctx.accounts.update_authority)?; + + // Ensure the canonical system program is provided. + if *ctx.accounts.system_program.key != system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !ctx.accounts.group.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + // --- PREP INPUT VECTORS ------------------------------------------------- + let CreateGroupV1Args { + name, + uri, + relationships, + } = args; + + let mut collections_vec: Vec = Vec::new(); + let mut child_groups_vec: Vec = Vec::new(); + let mut parent_groups_vec: Vec = Vec::new(); + let mut assets_vec: Vec = Vec::new(); + + // Track all relationship keys we have already seen to prevent duplicates across + // categories (e.g., the same account referenced twice or in two different + // categories). If a duplicate is detected, abort early with an error. + let mut seen: HashSet = HashSet::new(); + + for rel in relationships.into_iter() { + // If insert returns false, the value was already present – duplicate detected. + if !seen.insert(rel.key) { + return Err(MplCoreError::DuplicateEntry.into()); + } + + if rel.key == *ctx.accounts.group.key + && matches!( + rel.kind, + RelationshipKind::ChildGroup | RelationshipKind::ParentGroup + ) + { + msg!("Error: Group cannot reference itself as child or parent group"); + return Err(MplCoreError::IncorrectAccount.into()); + } + + match rel.kind { + RelationshipKind::Collection => collections_vec.push(rel.key), + RelationshipKind::ChildGroup => child_groups_vec.push(rel.key), + RelationshipKind::ParentGroup => parent_groups_vec.push(rel.key), + RelationshipKind::Asset => assets_vec.push(rel.key), + } + } + + if collections_vec.len() > MAX_GROUP_VECTOR_SIZE + || child_groups_vec.len() > MAX_GROUP_VECTOR_SIZE + || assets_vec.len() > MAX_GROUP_VECTOR_SIZE + { + return Err(MplCoreError::GroupVectorFull.into()); + } + + if parent_groups_vec.len() > MAX_GROUP_NESTING_DEPTH { + return Err(MplCoreError::GroupNestingDepthExceeded.into()); + } + + let new_group = GroupV1::new( + *authority_info.key, + name.clone(), + uri.clone(), + collections_vec.clone(), + child_groups_vec.clone(), + parent_groups_vec.clone(), + assets_vec.clone(), + ); + + let serialized_data = new_group.try_to_vec()?; + let lamports = rent.minimum_balance(serialized_data.len()); + + // Create the on-chain account for the group via CPI to System Program. + invoke( + &system_instruction::create_account( + ctx.accounts.payer.key, + ctx.accounts.group.key, + lamports, + serialized_data.len() as u64, + &crate::ID, + ), + &[ + ctx.accounts.payer.clone(), + ctx.accounts.group.clone(), + ctx.accounts.system_program.clone(), + ], + )?; + + save_flat_group( + ctx.accounts.group, + &new_group, + ctx.accounts.payer, + ctx.accounts.system_program, + )?; + + // ---------------------------------------------------------------------- + // POST-CREATION LINKING LOGIC + // ---------------------------------------------------------------------- + let remaining_accounts = ctx.remaining_accounts; + let expected_accounts = + collections_vec.len() + child_groups_vec.len() + parent_groups_vec.len() + assets_vec.len(); + + if remaining_accounts.len() < expected_accounts { + msg!( + "Error: Incorrect number of remaining accounts (expected {}, got {}).", + expected_accounts, + remaining_accounts.len() + ); + return Err(ProgramError::NotEnoughAccountKeys); + } + + // Extra accounts are allowed so collection-managed assets can provide the + // referenced collection account for authority checks. Restrict extras to + // collections only. + for supplemental_info in remaining_accounts.iter().skip(expected_accounts) { + if load_key(supplemental_info, 0)? != Key::CollectionV1 { + msg!("Error: unexpected supplemental remaining account"); + return Err(MplCoreError::IncorrectAccount.into()); + } + } + + // Offsets into remaining_accounts slice + let mut cursor: usize = 0; + + // ----------------- LINK COLLECTIONS ----------------------------------- + for (i, collection_key) in collections_vec.iter().enumerate() { + let collection_info = &remaining_accounts[cursor + i]; + + // Account correctness checks + if collection_info.key != collection_key { + msg!("Error: Collection account mismatch at index {}", i); + return Err(MplCoreError::IncorrectAccount.into()); + } + + if !collection_info.is_writable { + msg!("Error: Collection account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + // Authority check (collection update authority or delegate) + if !is_valid_collection_authority(collection_info, authority_info)? { + msg!("Error: Signer is not collection update authority/delegate"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Add Groups plugin entry. + process_collection_groups_plugin_add( + collection_info, + *ctx.accounts.group.key, + ctx.accounts.payer, + ctx.accounts.system_program, + )?; + } + + cursor += collections_vec.len(); + + // ----------------- LINK CHILD GROUPS ---------------------------------- + for (i, child_key) in child_groups_vec.iter().enumerate() { + let child_info = &remaining_accounts[cursor + i]; + + if child_info.key != child_key { + msg!("Error: Child group account mismatch at index {}", i); + return Err(MplCoreError::IncorrectAccount.into()); + } + + if !child_info.is_writable { + msg!("Error: Child group account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + let mut child_group = GroupV1::load(child_info, 0)?; + + if !is_valid_group_authority(child_info, authority_info)? { + msg!("Error: Signer is not child group update authority"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + if !child_group.parent_groups.contains(ctx.accounts.group.key) { + if child_group.parent_groups.len() >= MAX_GROUP_NESTING_DEPTH { + msg!("Error: Child group has reached maximum nesting depth"); + return Err(MplCoreError::GroupNestingDepthExceeded.into()); + } + + child_group.parent_groups.push(*ctx.accounts.group.key); + save_flat_group( + child_info, + &child_group, + ctx.accounts.payer, + ctx.accounts.system_program, + )?; + } + } + + cursor += child_groups_vec.len(); + + // ----------------- LINK PARENT GROUPS --------------------------------- + for (i, parent_key) in parent_groups_vec.iter().enumerate() { + let parent_info = &remaining_accounts[cursor + i]; + + if parent_info.key != parent_key { + msg!("Error: Parent group account mismatch at index {}", i); + return Err(MplCoreError::IncorrectAccount.into()); + } + + if !parent_info.is_writable { + msg!("Error: Parent group account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + let mut parent_group = GroupV1::load(parent_info, 0)?; + + if !is_valid_group_authority(parent_info, authority_info)? { + msg!("Error: Signer is not parent group update authority"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + if !parent_group.groups.contains(ctx.accounts.group.key) { + if parent_group.groups.len() >= MAX_GROUP_VECTOR_SIZE { + msg!("Error: Parent group has reached maximum child groups"); + return Err(MplCoreError::GroupVectorFull.into()); + } + + parent_group.groups.push(*ctx.accounts.group.key); + save_flat_group( + parent_info, + &parent_group, + ctx.accounts.payer, + ctx.accounts.system_program, + )?; + } + } + + cursor += parent_groups_vec.len(); + + // ----------------- LINK ASSETS ----------------------------------------- + for (i, asset_key) in assets_vec.iter().enumerate() { + let asset_info = &remaining_accounts[cursor + i]; + + if asset_info.key != asset_key { + msg!("Error: Asset account mismatch at index {}", i); + return Err(MplCoreError::IncorrectAccount.into()); + } + + if !asset_info.is_writable { + msg!("Error: Asset account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + // Authority check (asset update authority or delegate) + if !is_valid_asset_authority(asset_info, authority_info, accounts)? { + msg!("Error: Signer is not asset update authority/delegate"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Add Assets plugin entry. + process_asset_groups_plugin_add( + asset_info, + *ctx.accounts.group.key, + ctx.accounts.payer, + ctx.accounts.system_program, + )?; + } + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/execute.rs b/programs/mpl-core/src/processor/execute.rs index f4923dfa..d25f0085 100644 --- a/programs/mpl-core/src/processor/execute.rs +++ b/programs/mpl-core/src/processor/execute.rs @@ -1,5 +1,5 @@ use borsh::{BorshDeserialize, BorshSerialize}; -use mpl_utils::assert_signer; +use mpl_utils::{assert_derivation, assert_signer}; use solana_program::{ account_info::AccountInfo, entrypoint::ProgramResult, @@ -13,7 +13,7 @@ use solana_program::{ use crate::{ error::MplCoreError, instruction::accounts::ExecuteV1Accounts, - plugins::{Plugin, PluginType}, + plugins::{ExternalPluginAdapter, HookableLifecycleEvent, Plugin, PluginType}, state::{get_execute_fee, AssetV1, CollectionV1, Key}, utils::{load_key, resolve_authority, validate_asset_permissions}, }; @@ -35,8 +35,23 @@ pub(crate) fn execute<'a>(accounts: &'a [AccountInfo<'a>], args: ExecuteV1Args) return Err(MplCoreError::InvalidAsset.into()); } - assert_signer(ctx.accounts.payer)?; - let authority = resolve_authority(ctx.accounts.payer, ctx.accounts.authority)?; + let bump = assert_derivation( + &crate::ID, + ctx.accounts.asset_signer, + &[PREFIX.as_bytes(), ctx.accounts.asset.key.as_ref()], + MplCoreError::InvalidExecutePda, + )?; + + let payer_is_pda = ctx.accounts.payer.key == ctx.accounts.asset_signer.key; + + let authority = if payer_is_pda { + let authority = ctx.accounts.authority.ok_or(MplCoreError::MissingSigner)?; + assert_signer(authority)?; + authority + } else { + assert_signer(ctx.accounts.payer)?; + resolve_authority(ctx.accounts.payer, ctx.accounts.authority)? + }; if *ctx.accounts.system_program.key != system_program::ID { return Err(MplCoreError::InvalidSystemProgram.into()); @@ -64,28 +79,55 @@ pub(crate) fn execute<'a>(accounts: &'a [AccountInfo<'a>], args: ExecuteV1Args) AssetV1::validate_execute, CollectionV1::validate_execute, Plugin::validate_execute, - None, - None, + Some(ExternalPluginAdapter::validate_execute), + Some(HookableLifecycleEvent::Execute), )?; // Increment sequence number and save only if it is `Some(_)`. asset.increment_seq_and_save(ctx.accounts.asset)?; - invoke( - &system_instruction::transfer( - ctx.accounts.payer.key, - ctx.accounts.asset.key, - get_execute_fee()?, - ), - &[ctx.accounts.payer.clone(), ctx.accounts.asset.clone()], - )?; + let fee = get_execute_fee()?; + let transfer_ix = + system_instruction::transfer(ctx.accounts.payer.key, ctx.accounts.asset.key, fee); + + if payer_is_pda { + // Payer is the asset signer PDA -- use invoke_signed so the PDA can + // pay the execute fee from its own lamports. + invoke_signed( + &transfer_ix, + &[ctx.accounts.payer.clone(), ctx.accounts.asset.clone()], + &[&[PREFIX.as_bytes(), ctx.accounts.asset.key.as_ref(), &[bump]]], + )?; + } else { + invoke( + &transfer_ix, + &[ctx.accounts.payer.clone(), ctx.accounts.asset.clone()], + )?; + } + + // If the first remaining account is an ExecutionDelegateRecordV1, strip it + // before passing to the CPI -- it was only needed for plugin validation. + let cpi_accounts = if let Some(first) = ctx.remaining_accounts.first() { + if first.owner == &mpl_agent_tools::ID + && first.data_len() > 0 + && first.data.borrow()[0] + == mpl_agent_tools::types::Key::ExecutionDelegateRecordV1 as u8 + { + &ctx.remaining_accounts[1..] + } else { + ctx.remaining_accounts + } + } else { + ctx.remaining_accounts + }; process_execute( ctx.accounts.asset.key, ctx.accounts.asset_signer.key, ctx.accounts.program_id.key, args.instruction_data, - ctx.remaining_accounts, + cpi_accounts, + bump, ) } @@ -95,14 +137,8 @@ fn process_execute( program_id: &Pubkey, instruction_data: Vec, remaining_accounts: &[AccountInfo], + bump: u8, ) -> ProgramResult { - let (pda, bump) = - Pubkey::find_program_address(&[PREFIX.as_bytes(), asset_key.as_ref()], &crate::ID); - - if pda != *asset_signer { - return Err(MplCoreError::InvalidExecutePda.into()); - } - invoke_signed( &Instruction { program_id: *program_id, diff --git a/programs/mpl-core/src/processor/groups_plugin_utils.rs b/programs/mpl-core/src/processor/groups_plugin_utils.rs new file mode 100644 index 00000000..20bb05e2 --- /dev/null +++ b/programs/mpl-core/src/processor/groups_plugin_utils.rs @@ -0,0 +1,223 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_memory::sol_memmove, + pubkey::Pubkey, +}; + +use crate::{ + error::MplCoreError, + plugins::{ + create_meta_idempotent, initialize_plugin, Groups, Plugin, PluginHeaderV1, + PluginRegistryV1, PluginType, RegistryRecord, + }, + state::{AssetV1, CollectionV1, SolanaAccount}, + utils::resize_or_reallocate_account, +}; + +/// Add the parent group pubkey to the collection's Groups plugin, creating the plugin if necessary. +pub(crate) fn process_collection_groups_plugin_add<'a>( + collection_info: &AccountInfo<'a>, + parent_group: Pubkey, + payer_info: &AccountInfo<'a>, + system_program_info: &AccountInfo<'a>, +) -> ProgramResult { + // Ensure plugin metadata exists or create. + let (_collection_core, header_offset, mut plugin_header, mut plugin_registry) = + create_meta_idempotent::(collection_info, payer_info, system_program_info)?; + + // Attempt to fetch existing Groups plugin. + let plugin_record_opt = plugin_registry + .registry + .iter() + .find(|r| r.plugin_type == PluginType::Groups) + .cloned(); + + match plugin_record_opt { + None => { + // Plugin does not exist; create it. + let groups_plugin = Groups { + groups: vec![parent_group], + }; + let plugin = Plugin::Groups(groups_plugin); + initialize_plugin::( + &plugin, + &plugin.manager(), + header_offset, + &mut plugin_header, + &mut plugin_registry, + collection_info, + payer_info, + system_program_info, + )? + } + Some(record) => { + // Plugin exists, load, modify, and update. + let mut plugin = Plugin::load(collection_info, record.offset)?; + if let Plugin::Groups(inner) = &mut plugin { + if inner.groups.contains(&parent_group) { + return Ok(()); + } + inner.groups.push(parent_group); + } else { + return Err(MplCoreError::InvalidPlugin.into()); + } + + save_updated_groups_plugin( + collection_info, + payer_info, + system_program_info, + &plugin, + &record, + &mut plugin_header, + &mut plugin_registry, + header_offset, + )?; + } + } + + Ok(()) +} + +/// Add the parent group pubkey to the asset's Groups plugin, creating the plugin if necessary. +pub(crate) fn process_asset_groups_plugin_add<'a>( + asset_info: &AccountInfo<'a>, + parent_group: Pubkey, + payer_info: &AccountInfo<'a>, + system_program_info: &AccountInfo<'a>, +) -> ProgramResult { + let (_asset_core, header_offset, mut plugin_header, mut plugin_registry) = + create_meta_idempotent::(asset_info, payer_info, system_program_info)?; + + let plugin_record_opt = plugin_registry + .registry + .iter() + .find(|r| r.plugin_type == PluginType::Groups) + .cloned(); + + match plugin_record_opt { + None => { + let plugin = Plugin::Groups(Groups { + groups: vec![parent_group], + }); + initialize_plugin::( + &plugin, + &plugin.manager(), + header_offset, + &mut plugin_header, + &mut plugin_registry, + asset_info, + payer_info, + system_program_info, + )?; + } + Some(record) => { + let mut plugin = Plugin::load(asset_info, record.offset)?; + if let Plugin::Groups(inner) = &mut plugin { + if inner.groups.contains(&parent_group) { + return Ok(()); + } + inner.groups.push(parent_group); + } else { + return Err(MplCoreError::InvalidPlugin.into()); + } + + save_updated_groups_plugin( + asset_info, + payer_info, + system_program_info, + &plugin, + &record, + &mut plugin_header, + &mut plugin_registry, + header_offset, + )?; + } + } + Ok(()) +} + +/// Shared helper that persists a modified Groups plugin back to an account, +/// handling the resize, memmove, and registry offset bump when the serialized +/// size changes. Uses shrink-before-move / grow-after-move ordering so that +/// source bytes are always valid during `sol_memmove`. +pub(crate) fn save_updated_groups_plugin<'a>( + account_info: &AccountInfo<'a>, + payer_info: &AccountInfo<'a>, + system_program_info: &AccountInfo<'a>, + plugin: &Plugin, + record: &RegistryRecord, + plugin_header: &mut PluginHeaderV1, + plugin_registry: &mut PluginRegistryV1, + header_offset: usize, +) -> ProgramResult { + let old_plugin_data = + Plugin::deserialize(&mut &account_info.data.borrow()[record.offset..])?.try_to_vec()?; + let new_plugin_data = plugin.try_to_vec()?; + let size_diff = (new_plugin_data.len() as isize) + .checked_sub(old_plugin_data.len() as isize) + .ok_or(MplCoreError::NumericalOverflow)?; + + if size_diff != 0 { + let old_registry_offset = plugin_header.plugin_registry_offset; + let next_plugin_offset = record + .offset + .checked_add(old_plugin_data.len()) + .ok_or(MplCoreError::NumericalOverflow)?; + let new_next_plugin_offset: usize = (next_plugin_offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; + + plugin_registry.bump_offsets(record.offset, size_diff)?; + plugin_header.plugin_registry_offset = (old_registry_offset as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; + + let new_size: usize = (account_info.data_len() as isize) + .checked_add(size_diff) + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; + + let copy_len = old_registry_offset + .checked_sub(next_plugin_offset) + .ok_or(MplCoreError::NumericalOverflow)?; + + // When shrinking, move data first while the full source region is still valid. + if size_diff < 0 && copy_len > 0 { + unsafe { + let mut data = account_info.data.borrow_mut(); + let base_ptr = data.as_mut_ptr(); + sol_memmove( + base_ptr.add(new_next_plugin_offset), + base_ptr.add(next_plugin_offset), + copy_len, + ); + } + } + + resize_or_reallocate_account(account_info, payer_info, system_program_info, new_size)?; + + // When growing, move data after reallocation so the destination region exists. + if size_diff > 0 && copy_len > 0 { + unsafe { + let mut data = account_info.data.borrow_mut(); + let base_ptr = data.as_mut_ptr(); + sol_memmove( + base_ptr.add(new_next_plugin_offset), + base_ptr.add(next_plugin_offset), + copy_len, + ); + } + } + } + + plugin_header.save(account_info, header_offset)?; + plugin_registry.save(account_info, plugin_header.plugin_registry_offset)?; + plugin.save(account_info, record.offset)?; + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/mod.rs b/programs/mpl-core/src/processor/mod.rs index 0f8ea0ee..f9b777e2 100644 --- a/programs/mpl-core/src/processor/mod.rs +++ b/programs/mpl-core/src/processor/mod.rs @@ -1,38 +1,59 @@ +mod add_assets_to_group; +mod add_collections_to_group; mod add_external_plugin_adapter; +mod add_groups_to_group; mod add_plugin; mod approve_plugin_authority; mod burn; +mod close_group; mod collect; mod compress; mod create; mod create_collection; +mod create_group; mod decompress; mod execute; +mod groups_plugin_utils; +mod remove_assets_from_group; +mod remove_collections_from_group; mod remove_external_plugin_adapter; +mod remove_groups_from_group; mod remove_plugin; mod revoke_plugin_authority; mod transfer; mod update; +mod update_collection_info; mod update_external_plugin_adapter; +mod update_group; mod update_plugin; mod write_external_plugin_adapter_data; +pub(crate) use add_assets_to_group::*; +pub(crate) use add_collections_to_group::*; pub(crate) use add_external_plugin_adapter::*; +pub(crate) use add_groups_to_group::*; pub(crate) use add_plugin::*; pub(crate) use approve_plugin_authority::*; pub(crate) use burn::*; +pub(crate) use close_group::*; pub(crate) use collect::*; pub(crate) use compress::*; pub(crate) use create::*; pub(crate) use create_collection::*; +pub(crate) use create_group::*; pub(crate) use decompress::*; pub(crate) use execute::*; +pub(crate) use remove_assets_from_group::*; +pub(crate) use remove_collections_from_group::*; pub(crate) use remove_external_plugin_adapter::*; +pub(crate) use remove_groups_from_group::*; pub(crate) use remove_plugin::*; pub(crate) use revoke_plugin_authority::*; pub(crate) use transfer::*; pub(crate) use update::*; +pub(crate) use update_collection_info::*; pub(crate) use update_external_plugin_adapter::*; +pub(crate) use update_group::*; pub(crate) use update_plugin::*; pub(crate) use write_external_plugin_adapter_data::*; @@ -150,14 +171,6 @@ pub fn process_instruction<'a>( msg!("Instruction: RemoveCollectionExternalPluginAdapter"); remove_collection_external_plugin_adapter(accounts, args) } - MplAssetInstruction::UpdateExternalPluginAdapterV1(args) => { - msg!("Instruction: UpdateExternalPluginAdapter"); - update_external_plugin_adapter(accounts, args) - } - MplAssetInstruction::UpdateCollectionExternalPluginAdapterV1(args) => { - msg!("Instruction: UpdateCollectionExternalPluginAdapter"); - update_collection_external_plugin_adapter(accounts, args) - } MplAssetInstruction::WriteExternalPluginAdapterDataV1(args) => { msg!("Instruction: WriteExternalPluginAdapterDataV1"); write_external_plugin_adapter_data(accounts, args) @@ -170,9 +183,60 @@ pub fn process_instruction<'a>( msg!("Instruction: UpdateV2"); update_v2(accounts, args) } + MplAssetInstruction::ExecuteV1(args) => { msg!("Instruction: Execute"); execute(accounts, args) } + + MplAssetInstruction::UpdateCollectionInfoV1(args) => { + msg!("Instruction: UpdateCollectionInfoV1"); + update_collection_info(accounts, args) + } + + MplAssetInstruction::CreateGroupV1(args) => { + msg!("Instruction: CreateGroup"); + create_group_v1(accounts, args) + } + MplAssetInstruction::CloseGroupV1(args) => { + msg!("Instruction: CloseGroup"); + close_group_v1(accounts, args) + } + MplAssetInstruction::UpdateGroupV1(args) => { + msg!("Instruction: UpdateGroup"); + update_group_v1(accounts, args) + } + MplAssetInstruction::AddCollectionsToGroupV1(args) => { + msg!("Instruction: AddCollectionsToGroup"); + add_collections_to_group_v1(accounts, args) + } + MplAssetInstruction::RemoveCollectionsFromGroupV1(args) => { + msg!("Instruction: RemoveCollectionsFromGroup"); + remove_collections_from_group_v1(accounts, args) + } + MplAssetInstruction::AddGroupsToGroupV1(args) => { + msg!("Instruction: AddGroupsToGroup"); + add_groups_to_group_v1(accounts, args) + } + MplAssetInstruction::RemoveGroupsFromGroupV1(args) => { + msg!("Instruction: RemoveGroupsFromGroup"); + remove_groups_from_group_v1(accounts, args) + } + MplAssetInstruction::UpdateExternalPluginAdapterV1(args) => { + msg!("Instruction: UpdateExternalPluginAdapter"); + update_external_plugin_adapter(accounts, args) + } + MplAssetInstruction::UpdateCollectionExternalPluginAdapterV1(args) => { + msg!("Instruction: UpdateCollectionExternalPluginAdapter"); + update_collection_external_plugin_adapter(accounts, args) + } + MplAssetInstruction::AddAssetsToGroupV1(args) => { + msg!("Instruction: AddAssetsToGroup"); + add_assets_to_group_v1(accounts, args) + } + MplAssetInstruction::RemoveAssetsFromGroupV1(args) => { + msg!("Instruction: RemoveAssetsFromGroup"); + remove_assets_from_group_v1(accounts, args) + } } } diff --git a/programs/mpl-core/src/processor/remove_assets_from_group.rs b/programs/mpl-core/src/processor/remove_assets_from_group.rs new file mode 100644 index 00000000..bf059269 --- /dev/null +++ b/programs/mpl-core/src/processor/remove_assets_from_group.rs @@ -0,0 +1,146 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, + pubkey::Pubkey, +}; + +use super::groups_plugin_utils::save_updated_groups_plugin; +use crate::{ + error::MplCoreError, + instruction::accounts::{Context, RemoveAssetsFromGroupV1Accounts}, + plugins::{create_meta_idempotent, Plugin, PluginType}, + state::{AssetV1, GroupV1, Key, SolanaAccount}, + utils::{ + is_valid_asset_authority, is_valid_group_authority, load_key, resolve_authority, + save_flat_group, + }, +}; + +/// Args for RemoveAssetsFromGroupV1 +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct RemoveAssetsFromGroupV1Args { + pub(crate) assets: Vec, +} + +/// Remaining accounts: first the `AssetV1` accounts matching `args.assets` in +/// order, then optionally any read-only `CollectionV1` accounts needed for +/// authority resolution of collection-managed assets. +pub(crate) fn remove_assets_from_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + args: RemoveAssetsFromGroupV1Args, +) -> ProgramResult { + let ctx: Context = + RemoveAssetsFromGroupV1Accounts::context(accounts)?; + let group_info = ctx.accounts.group; + let payer_info = ctx.accounts.payer; + let authority_info_opt = ctx.accounts.authority; + let system_program_info = ctx.accounts.system_program; + let asset_accounts = ctx.remaining_accounts; + + assert_signer(payer_info)?; + let authority_info = resolve_authority(payer_info, authority_info_opt)?; + + if system_program_info.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !group_info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + if asset_accounts.len() < args.assets.len() { + msg!("Error: account/pubkey mismatch"); + return Err(ProgramError::NotEnoughAccountKeys); + } + + // Supplemental remaining accounts (after the explicit asset list) are + // allowed, but they must be collections. These are used when validating + // collection-managed asset authority. + for supplemental_info in asset_accounts.iter().skip(args.assets.len()) { + if load_key(supplemental_info, 0)? != Key::CollectionV1 { + msg!("Error: unexpected supplemental remaining account"); + return Err(MplCoreError::IncorrectAccount.into()); + } + } + + let mut group = GroupV1::load(group_info, 0)?; + if !is_valid_group_authority(group_info, authority_info)? { + return Err(MplCoreError::InvalidAuthority.into()); + } + + for (i, asset_key) in args.assets.iter().enumerate() { + let asset_info = &asset_accounts[i]; + + if asset_info.key != asset_key { + return Err(MplCoreError::IncorrectAccount.into()); + } + if !asset_info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + if !is_valid_asset_authority(asset_info, authority_info, accounts)? { + return Err(MplCoreError::InvalidAuthority.into()); + } + + // remove asset from group list + if let Some(pos) = group.assets.iter().position(|pk| pk == asset_info.key) { + group.assets.remove(pos); + } else { + msg!("Error: Asset is not a child of the provided group"); + return Err(MplCoreError::IncorrectAccount.into()); + } + + process_asset_groups_plugin_remove( + asset_info, + *group_info.key, + payer_info, + system_program_info, + )?; + } + + save_flat_group(group_info, &group, payer_info, system_program_info)?; + Ok(()) +} + +fn process_asset_groups_plugin_remove<'a>( + asset_info: &AccountInfo<'a>, + parent_group: Pubkey, + payer_info: &AccountInfo<'a>, + system_program_info: &AccountInfo<'a>, +) -> ProgramResult { + let (_asset_core, header_offset, mut plugin_header, mut plugin_registry) = + create_meta_idempotent::(asset_info, payer_info, system_program_info)?; + + let record_index_opt = plugin_registry + .registry + .iter() + .position(|r| r.plugin_type == PluginType::Groups); + + if let Some(index) = record_index_opt { + let record = plugin_registry.registry[index].clone(); + let mut plugin = Plugin::load(asset_info, record.offset)?; + if let Plugin::Groups(inner) = &mut plugin { + if let Some(pos) = inner.groups.iter().position(|pk| pk == &parent_group) { + inner.groups.remove(pos); + } else { + return Ok(()); + } + } else { + return Err(MplCoreError::InvalidPlugin.into()); + } + + save_updated_groups_plugin( + asset_info, + payer_info, + system_program_info, + &plugin, + &record, + &mut plugin_header, + &mut plugin_registry, + header_offset, + )?; + } + Ok(()) +} diff --git a/programs/mpl-core/src/processor/remove_collections_from_group.rs b/programs/mpl-core/src/processor/remove_collections_from_group.rs new file mode 100644 index 00000000..9e62b78a --- /dev/null +++ b/programs/mpl-core/src/processor/remove_collections_from_group.rs @@ -0,0 +1,164 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, + pubkey::Pubkey, +}; + +use super::groups_plugin_utils::save_updated_groups_plugin; +use crate::{ + error::MplCoreError, + instruction::accounts::{Context, RemoveCollectionsFromGroupV1Accounts}, + plugins::{create_meta_idempotent, Plugin, PluginType}, + state::{CollectionV1, GroupV1, SolanaAccount}, + utils::{ + is_valid_collection_authority, is_valid_group_authority, resolve_authority, save_flat_group, + }, +}; + +/// Arguments for the `RemoveCollectionsFromGroupV1` instruction. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct RemoveCollectionsFromGroupV1Args { + /// The list of collections to remove from the group. + pub(crate) collections: Vec, +} + +/// Processor for the `RemoveCollectionsFromGroupV1` instruction. +#[allow(clippy::too_many_arguments)] +pub(crate) fn remove_collections_from_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + args: RemoveCollectionsFromGroupV1Args, +) -> ProgramResult { + // Expected account layout: + // 0. [writable] Group account + // 1. [writable, signer] Payer account (also default authority) + // 2. [signer] Optional authority (group update authority) + // 3. [] System program + // 4..N [writable] Collection accounts, one for each pubkey in args.collections + let ctx: Context = + RemoveCollectionsFromGroupV1Accounts::context(accounts)?; + let group_info = ctx.accounts.group; + let payer_info = ctx.accounts.payer; + let authority_info_opt = ctx.accounts.authority; + let system_program_info = ctx.accounts.system_program; + let collection_accounts = ctx.remaining_accounts; + + // Basic guards + assert_signer(payer_info)?; + let authority_info = resolve_authority(payer_info, authority_info_opt)?; + + if system_program_info.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !group_info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + if collection_accounts.len() != args.collections.len() { + msg!( + "Error: Number of collection accounts ({}) does not match number of pubkeys in args ({}).", + collection_accounts.len(), + args.collections.len() + ); + return Err(ProgramError::NotEnoughAccountKeys); + } + + // Deserialize group. + let mut group = GroupV1::load(group_info, 0)?; + + // Authority check: must be the group's update authority. + if !is_valid_group_authority(group_info, authority_info)? { + msg!("Error: Invalid authority for group account"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + for (i, collection_info) in collection_accounts.iter().enumerate() { + if collection_info.key != &args.collections[i] { + msg!( + "Error: Collection account at position {} does not match provided pubkey list", + i + ); + return Err(MplCoreError::IncorrectAccount.into()); + } + + if !collection_info.is_writable { + msg!("Error: Collection account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + let _collection_core = CollectionV1::load(collection_info, 0)?; + + if !is_valid_collection_authority(collection_info, authority_info)? { + msg!("Error: Signer is not collection update authority/delegate"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Remove from group.collections if present. + if let Some(pos) = group + .collections + .iter() + .position(|pk| pk == collection_info.key) + { + group.collections.remove(pos); + } else { + msg!("Error: Collection is not a child of the provided group"); + return Err(MplCoreError::IncorrectAccount.into()); + } + + // Remove group from collection's Groups plugin. + process_collection_groups_plugin_remove( + collection_info, + *group_info.key, + payer_info, + system_program_info, + )?; + } + + save_flat_group(group_info, &group, payer_info, system_program_info)?; + + Ok(()) +} + +fn process_collection_groups_plugin_remove<'a>( + collection_info: &AccountInfo<'a>, + parent_group: Pubkey, + payer_info: &AccountInfo<'a>, + system_program_info: &AccountInfo<'a>, +) -> ProgramResult { + let (_collection_core, header_offset, mut plugin_header, mut plugin_registry) = + create_meta_idempotent::(collection_info, payer_info, system_program_info)?; + + let record_index_opt = plugin_registry + .registry + .iter() + .position(|r| r.plugin_type == PluginType::Groups); + + if let Some(index) = record_index_opt { + let record = plugin_registry.registry[index].clone(); + let mut plugin = Plugin::load(collection_info, record.offset)?; + if let Plugin::Groups(inner) = &mut plugin { + if let Some(pos) = inner.groups.iter().position(|pk| pk == &parent_group) { + inner.groups.remove(pos); + } else { + return Ok(()); + } + } else { + return Err(MplCoreError::InvalidPlugin.into()); + } + + save_updated_groups_plugin( + collection_info, + payer_info, + system_program_info, + &plugin, + &record, + &mut plugin_header, + &mut plugin_registry, + header_offset, + )?; + } + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/remove_groups_from_group.rs b/programs/mpl-core/src/processor/remove_groups_from_group.rs new file mode 100644 index 00000000..7d1d0fa2 --- /dev/null +++ b/programs/mpl-core/src/processor/remove_groups_from_group.rs @@ -0,0 +1,133 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, + pubkey::Pubkey, +}; + +use crate::{ + error::MplCoreError, + instruction::accounts::{Context, RemoveGroupsFromGroupV1Accounts}, + state::{GroupV1, SolanaAccount}, + utils::{is_valid_group_authority, resolve_authority, save_flat_group}, +}; + +/// Arguments for the `RemoveGroupsFromGroupV1` instruction. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct RemoveGroupsFromGroupV1Args { + /// The list of child groups to remove from the parent group. + pub(crate) groups: Vec, +} + +/// Processor for the `RemoveGroupsFromGroupV1` instruction. +#[allow(clippy::too_many_arguments)] +pub(crate) fn remove_groups_from_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + args: RemoveGroupsFromGroupV1Args, +) -> ProgramResult { + // Expected account layout: + // 0. [writable] Parent group account + // 1. [writable, signer] Payer account (also default authority) + // 2. [signer] Optional authority (group update authority) + // 3. [] System program + // 4..N [writable] Child group accounts, one for each pubkey in args.groups + let ctx: Context = + RemoveGroupsFromGroupV1Accounts::context(accounts)?; + let parent_group_info = ctx.accounts.parent_group; + let payer_info = ctx.accounts.payer; + let authority_info_opt = ctx.accounts.authority; + let system_program_info = ctx.accounts.system_program; + let child_group_accounts = ctx.remaining_accounts; + + // Basic guards. + assert_signer(payer_info)?; + let authority_info = resolve_authority(payer_info, authority_info_opt)?; + if authority_info.key != payer_info.key { + assert_signer(authority_info)?; + } + + if system_program_info.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !parent_group_info.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + // Validate arg count. + if child_group_accounts.len() != args.groups.len() { + msg!( + "Error: Number of group accounts ({}) does not match number of pubkeys in args ({}).", + child_group_accounts.len(), + args.groups.len() + ); + return Err(ProgramError::NotEnoughAccountKeys); + } + + // Deserialize parent group. + let mut parent_group = GroupV1::load(parent_group_info, 0)?; + + // Authority check: must be the parent group's update authority. + if !is_valid_group_authority(parent_group_info, authority_info)? { + msg!("Error: Invalid authority for parent group account"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Iterate child groups. + for (i, child_info) in child_group_accounts.iter().enumerate() { + if child_info.key != &args.groups[i] { + msg!( + "Error: Child group account at position {} does not match provided pubkey list", + i + ); + return Err(MplCoreError::IncorrectAccount.into()); + } + + if !child_info.is_writable { + msg!("Error: Child group account must be writable"); + return Err(ProgramError::InvalidAccountData); + } + + let mut child_group = GroupV1::load(child_info, 0)?; + + // Authority must also be the child group's update authority. + if !is_valid_group_authority(child_info, authority_info)? { + msg!("Error: Signer is not child group update authority"); + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Remove child from parent list if present. + if let Some(pos) = parent_group + .groups + .iter() + .position(|pk| pk == child_info.key) + { + parent_group.groups.remove(pos); + } else { + msg!("Error: Child group is not linked to the parent group"); + return Err(MplCoreError::IncorrectAccount.into()); + } + + if let Some(pos) = child_group + .parent_groups + .iter() + .position(|pk| pk == parent_group_info.key) + { + child_group.parent_groups.remove(pos); + save_flat_group(child_info, &child_group, payer_info, system_program_info)?; + } else { + msg!("Error: Bidirectional relationship inconsistent — parent not found in child's parent_groups"); + return Err(MplCoreError::InconsistentGroupRelationship.into()); + } + } + + save_flat_group( + parent_group_info, + &parent_group, + payer_info, + system_program_info, + )?; + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/remove_plugin.rs b/programs/mpl-core/src/processor/remove_plugin.rs index 9ad623c6..71c3a3e2 100644 --- a/programs/mpl-core/src/processor/remove_plugin.rs +++ b/programs/mpl-core/src/processor/remove_plugin.rs @@ -44,6 +44,11 @@ pub(crate) fn remove_plugin<'a>( return Err(MplCoreError::NotAvailable.into()); } + // Groups plugins can only be removed via specialized Group instructions. + if args.plugin_type == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (mut asset, plugin_header, plugin_registry) = fetch_core_data::(ctx.accounts.asset)?; @@ -115,6 +120,11 @@ pub(crate) fn remove_collection_plugin<'a>( } } + // Groups plugins can only be removed via specialized Group instructions. + if args.plugin_type == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (collection, plugin_header, plugin_registry) = fetch_core_data::(ctx.accounts.collection)?; diff --git a/programs/mpl-core/src/processor/revoke_plugin_authority.rs b/programs/mpl-core/src/processor/revoke_plugin_authority.rs index a5e8bfc3..5b344505 100644 --- a/programs/mpl-core/src/processor/revoke_plugin_authority.rs +++ b/programs/mpl-core/src/processor/revoke_plugin_authority.rs @@ -50,6 +50,11 @@ pub(crate) fn revoke_plugin_authority<'a>( return Err(MplCoreError::NotAvailable.into()); } + // Groups plugins must be managed only via Group-specific instructions; revoke is not allowed. + if args.plugin_type == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (mut asset, plugin_header, mut plugin_registry) = fetch_core_data::(ctx.accounts.asset)?; @@ -125,6 +130,11 @@ pub(crate) fn revoke_collection_plugin_authority<'a>( } } + // Groups plugins must be managed only via Group-specific instructions; revoke is not allowed. + if args.plugin_type == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (collection, plugin_header, mut plugin_registry) = fetch_core_data::(ctx.accounts.collection)?; diff --git a/programs/mpl-core/src/processor/update.rs b/programs/mpl-core/src/processor/update.rs index 99728da6..8e34eb84 100644 --- a/programs/mpl-core/src/processor/update.rs +++ b/programs/mpl-core/src/processor/update.rs @@ -385,17 +385,17 @@ fn process_update<'a, T: DataBlob + SolanaAccount>( resize_or_reallocate_account(account, payer, system_program, new_size as usize)?; - // SAFETY: `borrow_mut` will always return a valid pointer. - // new_plugin_offset is derived from plugin_offset and size_diff using - // checked arithmetic, so it will always be less than or equal to account.data_len(). - // This will fail and revert state if there is a memory violation. - unsafe { - let base = account.data.borrow_mut().as_mut_ptr(); - sol_memmove( - base.add(new_plugin_offset as usize), - base.add(plugin_offset as usize), - registry_offset - plugin_offset as usize, - ); + let copy_len = (registry_offset as usize).saturating_sub(plugin_offset as usize); + + if copy_len > 0 { + unsafe { + let base = account.data.borrow_mut().as_mut_ptr(); + sol_memmove( + base.add(new_plugin_offset as usize), + base.add(plugin_offset as usize), + copy_len, + ); + } } plugin_header.save(account, new_core_size as usize)?; diff --git a/programs/mpl-core/src/processor/update_collection_info.rs b/programs/mpl-core/src/processor/update_collection_info.rs new file mode 100644 index 00000000..965ba837 --- /dev/null +++ b/programs/mpl-core/src/processor/update_collection_info.rs @@ -0,0 +1,66 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{account_info::AccountInfo, entrypoint::ProgramResult, pubkey::Pubkey}; + +use crate::{ + error::MplCoreError, + instruction::accounts::UpdateCollectionInfoV1Accounts, + state::{CollectionV1, SolanaAccount}, + utils::fetch_core_data, +}; + +pub const BUBBLEGUM_SIGNER: Pubkey = + solana_program::pubkey!("CbNY3JiXdXNE9tPNEk1aRZVEkWdj2v7kfJLNQwZZgpXk"); + +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) enum UpdateType { + /// Update collection details due to minting assets to collection. + Mint, + /// Update collection details due to adding assets to collection. + Add, + /// Update collection details due to removing assets from collection. + Remove, +} + +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct UpdateCollectionInfoV1Args { + update_type: UpdateType, + amount: u32, +} + +pub(crate) fn update_collection_info<'a>( + accounts: &'a [AccountInfo<'a>], + args: UpdateCollectionInfoV1Args, +) -> ProgramResult { + // Accounts. + let ctx = UpdateCollectionInfoV1Accounts::context(accounts)?; + + // Guards. + assert_signer(ctx.accounts.bubblegum_signer)?; + + // This instruction can only be called by the Bubblegum program. + if *ctx.accounts.bubblegum_signer.key != BUBBLEGUM_SIGNER { + return Err(MplCoreError::InvalidAuthority.into()); + } + + let (mut collection, _, _) = fetch_core_data::(ctx.accounts.collection)?; + + match args.update_type { + UpdateType::Mint => { + collection.num_minted = collection.num_minted.saturating_add(args.amount); + collection.current_size = collection.current_size.saturating_add(args.amount); + } + UpdateType::Add => { + collection.current_size = collection.current_size.saturating_add(args.amount); + } + UpdateType::Remove => { + collection.current_size = collection.current_size.saturating_sub(args.amount); + } + } + + collection.save(ctx.accounts.collection, 0)?; + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs index 829e5a58..0b645776 100644 --- a/programs/mpl-core/src/processor/update_external_plugin_adapter.rs +++ b/programs/mpl-core/src/processor/update_external_plugin_adapter.rs @@ -62,6 +62,8 @@ pub(crate) fn update_external_plugin_adapter<'a>( resolve_pubkey_to_authorities(authority, ctx.accounts.collection, &asset)?; let (external_registry_record, external_plugin_adapter) = fetch_wrapped_external_plugin_adapter::(ctx.accounts.asset, None, &args.key)?; + let mut incoming_external_plugin_adapter = external_plugin_adapter.clone(); + incoming_external_plugin_adapter.update(&args.update_info)?; let validation_ctx = PluginValidationContext { accounts, @@ -75,7 +77,7 @@ pub(crate) fn update_external_plugin_adapter<'a>( new_collection_authority: None, target_plugin: None, target_plugin_authority: None, - target_external_plugin: Some(&external_plugin_adapter), + target_external_plugin: Some(&incoming_external_plugin_adapter), target_external_plugin_authority: Some(&external_registry_record.authority), }; @@ -143,6 +145,8 @@ pub(crate) fn update_collection_external_plugin_adapter<'a>( None, &args.key, )?; + let mut incoming_external_plugin_adapter = external_plugin_adapter.clone(); + incoming_external_plugin_adapter.update(&args.update_info)?; let validation_ctx = PluginValidationContext { accounts, @@ -156,7 +160,7 @@ pub(crate) fn update_collection_external_plugin_adapter<'a>( new_collection_authority: None, target_plugin: None, target_plugin_authority: None, - target_external_plugin: Some(&external_plugin_adapter), + target_external_plugin: Some(&incoming_external_plugin_adapter), target_external_plugin_authority: Some(&external_registry_record.authority), }; @@ -211,7 +215,7 @@ fn process_update_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( let registry_record = registry_record.clone(); let mut new_plugin = plugin.clone(); - new_plugin.update(&update_info); + new_plugin.update(&update_info)?; let plugin_data = plugin.try_to_vec()?; let new_plugin_data = new_plugin.try_to_vec()?; @@ -228,44 +232,69 @@ fn process_update_external_plugin_adapter<'a, T: DataBlob + SolanaAccount>( .ok_or(MplCoreError::NumericalOverflow)? .checked_add(registry_record_size_diff) .ok_or(MplCoreError::NumericalOverflow)?; + let new_size: usize = new_size + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; // The new offset of the plugin registry is the old offset plus the size difference. let registry_offset = plugin_header.plugin_registry_offset; - let new_registry_offset = (registry_offset as isize) + let new_registry_offset: usize = (registry_offset as isize) .checked_add(plugin_size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; - plugin_header.plugin_registry_offset = new_registry_offset as usize; + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; // The offset of the first plugin is the plugin offset plus the size of the plugin. - let next_plugin_offset = (registry_record.offset as isize) + let next_plugin_offset: usize = (registry_record.offset as isize) .checked_add(plugin_size) - .ok_or(MplCoreError::NumericalOverflow)?; + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; - let new_next_plugin_offset = next_plugin_offset + let new_next_plugin_offset: usize = (next_plugin_offset as isize) .checked_add(plugin_size_diff) - .ok_or(MplCoreError::NumericalOverflow)?; + .ok_or(MplCoreError::NumericalOverflow)? + .try_into() + .map_err(|_| MplCoreError::NumericalOverflow)?; + + // Move only the bytes between the updated plugin and the original registry start. + // This must be computed from the old registry offset, not the new one. + let copy_len = registry_offset.saturating_sub(next_plugin_offset); + + // When shrinking, shift trailing bytes before account reallocation so the source + // region is still fully available. + if plugin_size_diff < 0 && copy_len > 0 { + unsafe { + let base = account.data.borrow_mut().as_mut_ptr(); + sol_memmove( + base.add(new_next_plugin_offset), + base.add(next_plugin_offset), + copy_len, + ); + } + } - resize_or_reallocate_account(account, payer, system_program, new_size as usize)?; - - // SAFETY: `borrow_mut` will always return a valid pointer. - // new_next_plugin_offset is derived from next_plugin_offset and size_diff using - // checked arithmetic, so it will always be less than or equal to account.data_len(). - // This will fail and revert state if there is a memory violation. - unsafe { - let base = account.data.borrow_mut().as_mut_ptr(); - sol_memmove( - base.add(new_next_plugin_offset as usize), - base.add(next_plugin_offset as usize), - registry_offset - next_plugin_offset as usize, - ); + resize_or_reallocate_account(account, payer, system_program, new_size)?; + + // When growing, reallocate first so the destination region exists. + if plugin_size_diff > 0 && copy_len > 0 { + unsafe { + let base = account.data.borrow_mut().as_mut_ptr(); + sol_memmove( + base.add(new_next_plugin_offset), + base.add(next_plugin_offset), + copy_len, + ); + } } + plugin_header.plugin_registry_offset = new_registry_offset; plugin_header.save(account, core.len())?; // Move offsets for existing registry records. plugin_registry.bump_offsets(registry_record.offset, plugin_size_diff)?; - plugin_registry.save(account, new_registry_offset as usize)?; + plugin_registry.save(account, new_registry_offset)?; new_plugin.save(account, registry_record.offset)?; Ok(()) diff --git a/programs/mpl-core/src/processor/update_group.rs b/programs/mpl-core/src/processor/update_group.rs new file mode 100644 index 00000000..3b63fc59 --- /dev/null +++ b/programs/mpl-core/src/processor/update_group.rs @@ -0,0 +1,85 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use mpl_utils::assert_signer; +use solana_program::{ + account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, +}; + +use crate::{ + error::MplCoreError, + instruction::accounts::UpdateGroupV1Accounts, + state::{GroupV1, SolanaAccount}, + utils::{is_valid_group_authority, resolve_authority, save_flat_group}, +}; + +/// Arguments for the `UpdateGroupV1` instruction. +#[repr(C)] +#[derive(BorshSerialize, BorshDeserialize, PartialEq, Eq, Debug, Clone)] +pub(crate) struct UpdateGroupV1Args { + /// New display name for the group (optional). + pub(crate) new_name: Option, + /// New URI for the group (optional). + pub(crate) new_uri: Option, +} + +/// Processor for the `UpdateGroupV1` instruction. +#[allow(clippy::too_many_arguments)] +pub(crate) fn update_group_v1<'a>( + accounts: &'a [AccountInfo<'a>], + args: UpdateGroupV1Args, +) -> ProgramResult { + // Derive the typed account context from the raw slice. + let ctx = UpdateGroupV1Accounts::context(accounts)?; + + // Basic guards. + assert_signer(ctx.accounts.payer)?; + let authority = resolve_authority(ctx.accounts.payer, ctx.accounts.authority)?; + + // Ensure the canonical system program is provided. + if ctx.accounts.system_program.key != &solana_program::system_program::ID { + return Err(MplCoreError::InvalidSystemProgram.into()); + } + + if !ctx.accounts.group.is_writable { + return Err(ProgramError::InvalidAccountData); + } + + // Deserialize the group account. + let mut group = GroupV1::load(ctx.accounts.group, 0)?; + + // Ensure the signer is the update authority of the group. + if !is_valid_group_authority(ctx.accounts.group, authority)? { + return Err(MplCoreError::InvalidAuthority.into()); + } + + // Track if any field is modified. + let mut dirty = false; + + // Apply a new update authority if supplied as an account. + if let Some(new_update_authority) = ctx.accounts.new_update_authority { + group.update_authority = *new_update_authority.key; + dirty = true; + } + + // Apply inline argument changes. + if let Some(new_name) = &args.new_name { + group.name.clone_from(new_name); + dirty = true; + } + + if let Some(new_uri) = &args.new_uri { + group.uri.clone_from(new_uri); + dirty = true; + } + + // Persist state changes if anything was updated. + if dirty { + save_flat_group( + ctx.accounts.group, + &group, + ctx.accounts.payer, + ctx.accounts.system_program, + )?; + } + + Ok(()) +} diff --git a/programs/mpl-core/src/processor/update_plugin.rs b/programs/mpl-core/src/processor/update_plugin.rs index 91bd7329..d6033a3a 100644 --- a/programs/mpl-core/src/processor/update_plugin.rs +++ b/programs/mpl-core/src/processor/update_plugin.rs @@ -47,6 +47,11 @@ pub(crate) fn update_plugin<'a>( return Err(MplCoreError::NotAvailable.into()); } + // Groups plugins must be mutated only through dedicated Group instructions. + if PluginType::from(&args.plugin) == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (target_plugin_authority, _) = fetch_wrapped_plugin::(ctx.accounts.asset, None, PluginType::from(&args.plugin))?; @@ -112,6 +117,11 @@ pub(crate) fn update_collection_plugin<'a>( } } + // Groups plugins must be mutated only through dedicated Group instructions. + if PluginType::from(&args.plugin) == PluginType::Groups { + return Err(MplCoreError::InvalidPlugin.into()); + } + let (target_plugin_authority, _) = fetch_wrapped_plugin::( ctx.accounts.collection, None, @@ -198,19 +208,28 @@ fn process_update_plugin<'a, T: DataBlob + SolanaAccount>( .checked_add(size_diff) .ok_or(MplCoreError::NumericalOverflow)?; - resize_or_reallocate_account(account, payer, system_program, new_size as usize)?; - - // SAFETY: `borrow_mut` will always return a valid pointer. - // new_next_plugin_offset is derived from next_plugin_offset and size_diff using - // checked arithmetic, so it will always be less than or equal to account.data_len(). - // This will fail and revert state if there is a memory violation. - unsafe { - let base = account.data.borrow_mut().as_mut_ptr(); - sol_memmove( - base.add(new_next_plugin_offset as usize), - base.add(next_plugin_offset as usize), - registry_offset - (next_plugin_offset as usize), - ); + if size_diff > 0 { + // Growing: realloc first to make room for the rightward shift. + resize_or_reallocate_account(account, payer, system_program, new_size as usize)?; + } + + let copy_len = (registry_offset) + .checked_sub(next_plugin_offset as usize) + .ok_or(MplCoreError::NumericalOverflow)?; + if copy_len > 0 { + unsafe { + let base = account.data.borrow_mut().as_mut_ptr(); + sol_memmove( + base.add(new_next_plugin_offset as usize), + base.add(next_plugin_offset as usize), + copy_len, + ); + } + } + + if size_diff < 0 { + // Shrinking: realloc after memmove to preserve data before truncation. + resize_or_reallocate_account(account, payer, system_program, new_size as usize)?; } plugin_header.save(account, core.len())?; diff --git a/programs/mpl-core/src/state/group.rs b/programs/mpl-core/src/state/group.rs new file mode 100644 index 00000000..42e49cbb --- /dev/null +++ b/programs/mpl-core/src/state/group.rs @@ -0,0 +1,160 @@ +use borsh::{BorshDeserialize, BorshSerialize}; +use shank::ShankAccount; +use solana_program::pubkey::Pubkey; + +use super::{CoreAsset, DataBlob, Key, SolanaAccount, UpdateAuthority}; + +/// Maximum number of entries per vector in a `GroupV1` account (collections, groups, +/// parent_groups, assets). Prevents unbounded growth that could cause compute +/// budget exhaustion on subsequent operations. +pub const MAX_GROUP_VECTOR_SIZE: usize = 256; + +/// Maximum number of parent groups a single group may belong to. Acts as a +/// practical depth limit for group nesting since on-chain traversal is not +/// feasible. +pub const MAX_GROUP_NESTING_DEPTH: usize = 8; + +/// The representation of a taxonomy group which can reference collections and other groups. +#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, ShankAccount)] +pub struct GroupV1 { + /// The account discriminator. + pub key: Key, // 1 + /// The update authority for the group. + pub update_authority: Pubkey, // 32 + /// The display name of the group. + pub name: String, // 4 + /// The URI that links to the off-chain JSON describing the group. + /// Same semantics as collection URI. + pub uri: String, // 4 + /// Collections that are direct children of this group. + pub collections: Vec, // 4 + 32 * N + /// Groups that are direct children of this group. + pub groups: Vec, // 4 + 32 * N + /// Groups that this group is a child of. + pub parent_groups: Vec, // 4 + 32 * N + /// Assets that are direct members of this group. + pub assets: Vec, // 4 + 32 * N +} + +impl GroupV1 { + /// The base length of a group with empty name/uri and no relationships. + const BASE_LEN: usize = 1 // Key + + 32 // Update Authority + + 4 // Name length + + 4 // URI length + + 4 // collections vec length + + 4 // groups vec length + + 4 // parent_groups vec length + + 4; // assets vec length + + /// Create a new GroupV1 instance. + pub fn new( + update_authority: Pubkey, + name: String, + uri: String, + collections: Vec, + groups: Vec, + parent_groups: Vec, + assets: Vec, + ) -> Self { + Self { + key: Key::GroupV1, + update_authority, + name, + uri, + collections, + groups, + parent_groups, + assets, + } + } +} + +impl DataBlob for GroupV1 { + fn len(&self) -> usize { + Self::BASE_LEN + + self.name.len() + + self.uri.len() + + 32 * self.collections.len() + + 32 * self.groups.len() + + 32 * self.parent_groups.len() + + 32 * self.assets.len() + } +} + +impl SolanaAccount for GroupV1 { + fn key() -> Key { + Key::GroupV1 + } +} + +impl CoreAsset for GroupV1 { + fn update_authority(&self) -> UpdateAuthority { + UpdateAuthority::Address(self.update_authority) + } + + fn owner(&self) -> &Pubkey { + &self.update_authority + } +} + +/// Specifies the category of relationship a `Group` account has with another +/// account. This enum is used only for instruction input (not stored on chain) +/// to keep the `CreateGroup` API compact. +#[repr(u8)] +#[derive(Clone, Copy, BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)] +pub enum RelationshipKind { + /// Relationship to a `Collection` account the group directly contains. + Collection, + /// Relationship to a child `Group` that this group directly contains. + ChildGroup, + /// Relationship to a parent `Group` that contains this group. + ParentGroup, + /// Relationship to an `Asset` account that is a direct member of the group. + Asset, +} + +/// Compact representation of a single relationship passed into +/// `CreateGroupV1Args`. +#[derive(Clone, BorshSerialize, BorshDeserialize, Debug, Eq, PartialEq)] +pub struct RelationshipEntry { + /// The kind of relationship. + pub kind: RelationshipKind, + /// The public key of the related account. + pub key: Pubkey, +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_group_len() { + let groups = vec![ + GroupV1 { + key: Key::GroupV1, + update_authority: Pubkey::default(), + name: "".to_string(), + uri: "".to_string(), + collections: vec![], + groups: vec![], + parent_groups: vec![], + assets: vec![], + }, + GroupV1 { + key: Key::GroupV1, + update_authority: Pubkey::default(), + name: "test".to_string(), + uri: "test".to_string(), + collections: vec![Pubkey::new_unique(), Pubkey::new_unique()], + groups: vec![Pubkey::new_unique()], + parent_groups: vec![], + assets: vec![], + }, + ]; + for group in groups { + let serialized = group.try_to_vec().unwrap(); + assert_eq!(serialized.len(), group.len()); + } + } +} diff --git a/programs/mpl-core/src/state/mod.rs b/programs/mpl-core/src/state/mod.rs index a3a469e7..8cd1a838 100644 --- a/programs/mpl-core/src/state/mod.rs +++ b/programs/mpl-core/src/state/mod.rs @@ -26,6 +26,9 @@ pub use traits::*; mod update_authority; pub use update_authority::*; +mod group; +pub use group::*; + use borsh::{BorshDeserialize, BorshSerialize}; use num_derive::{FromPrimitive, ToPrimitive}; use solana_program::pubkey::Pubkey; @@ -100,6 +103,8 @@ pub enum Key { PluginRegistryV1, /// A discriminator indicating the collection. CollectionV1, + /// A discriminator indicating the group. + GroupV1, } impl Key { diff --git a/programs/mpl-core/src/state/traits.rs b/programs/mpl-core/src/state/traits.rs index 15aa726f..20e88c25 100644 --- a/programs/mpl-core/src/state/traits.rs +++ b/programs/mpl-core/src/state/traits.rs @@ -27,6 +27,10 @@ pub trait SolanaAccount: BorshSerialize + BorshDeserialize { return Err(MplCoreError::DeserializationError.into()); } + if account.owner != &crate::ID { + return Err(ProgramError::InvalidAccountOwner); + } + let mut bytes: &[u8] = &(*account.data).borrow()[offset..]; Self::deserialize(&mut bytes).map_err(|error| { msg!("Error: {}", error); diff --git a/programs/mpl-core/src/utils/mod.rs b/programs/mpl-core/src/utils/mod.rs index 21577551..5c2dd182 100644 --- a/programs/mpl-core/src/utils/mod.rs +++ b/programs/mpl-core/src/utils/mod.rs @@ -7,19 +7,20 @@ pub(crate) use compression::*; use crate::{ error::MplCoreError, plugins::{ - validate_external_plugin_adapter_checks, validate_plugin_checks, CheckResult, - ExternalCheckResultBits, ExternalPluginAdapter, ExternalPluginAdapterKey, + fetch_wrapped_plugin, validate_external_plugin_adapter_checks, validate_plugin_checks, + CheckResult, ExternalCheckResultBits, ExternalPluginAdapter, ExternalPluginAdapterKey, ExternalRegistryRecord, HookableLifecycleEvent, Plugin, PluginHeaderV1, PluginRegistryV1, PluginType, PluginValidationContext, RegistryRecord, ValidationResult, }, state::{ - AssetV1, Authority, CollectionV1, CoreAsset, DataBlob, Key, SolanaAccount, UpdateAuthority, + AssetV1, Authority, CollectionV1, CoreAsset, DataBlob, GroupV1, Key, SolanaAccount, + UpdateAuthority, }, }; use mpl_utils::assert_signer; use num_traits::FromPrimitive; use solana_program::{ - account_info::AccountInfo, entrypoint::ProgramResult, program_error::ProgramError, + account_info::AccountInfo, entrypoint::ProgramResult, msg, program_error::ProgramError, pubkey::Pubkey, }; use std::collections::BTreeMap; @@ -100,6 +101,24 @@ pub fn fetch_core_data( } } +/// Persist a mutated `GroupV1` as flat Borsh data only. +pub(crate) fn save_flat_group<'a>( + group_info: &AccountInfo<'a>, + group: &GroupV1, + payer_info: &AccountInfo<'a>, + system_program_info: &AccountInfo<'a>, +) -> ProgramResult { + let serialized_len = group.len(); + + if serialized_len != group_info.data_len() { + resize_or_reallocate_account(group_info, payer_info, system_program_info, serialized_len)?; + } + + group.save(group_info, 0)?; + + Ok(()) +} + #[allow(clippy::too_many_arguments, clippy::type_complexity)] /// Validate asset permissions using lifecycle validations for asset, collection, and plugins. pub(crate) fn validate_asset_permissions<'a>( @@ -243,32 +262,6 @@ pub(crate) fn validate_asset_permissions<'a>( }; match validate_plugin_checks( - Key::CollectionV1, - accounts, - &checks, - authority_info, - new_owner, - new_authority, - None, - new_plugin, - new_plugin_authority, - new_external_plugin_adapter, - new_external_plugin_adapter_authority, - Some(asset), - collection, - &resolved_authorities, - plugin_validate_fp, - )? { - ValidationResult::Approved => approved = true, - ValidationResult::Rejected => rejected = true, - ValidationResult::Pass => (), - ValidationResult::ForceApproved => { - return Ok((deserialized_asset, plugin_header, plugin_registry)) - } - }; - - match validate_plugin_checks( - Key::AssetV1, accounts, &checks, authority_info, @@ -294,31 +287,6 @@ pub(crate) fn validate_asset_permissions<'a>( if let Some(external_plugin_adapter_validate_fp) = external_plugin_adapter_validate_fp { match validate_external_plugin_adapter_checks( - Key::CollectionV1, - accounts, - &external_checks, - authority_info, - new_owner, - new_authority, - None, - new_plugin, - new_plugin_authority, - new_external_plugin_adapter, - new_external_plugin_adapter_authority, - Some(asset), - collection, - &resolved_authorities, - external_plugin_adapter_validate_fp, - )? { - ValidationResult::Approved => approved = true, - ValidationResult::Rejected => rejected = true, - ValidationResult::Pass => (), - // Force approved will not be possible from external plugin adapters. - ValidationResult::ForceApproved => unreachable!(), - }; - - match validate_external_plugin_adapter_checks( - Key::AssetV1, accounts, &external_checks, authority_info, @@ -450,7 +418,6 @@ pub(crate) fn validate_collection_permissions<'a>( }; match validate_plugin_checks( - Key::CollectionV1, accounts, &checks, authority_info, @@ -476,7 +443,6 @@ pub(crate) fn validate_collection_permissions<'a>( if let Some(external_plugin_adapter_validate_fp) = external_plugin_adapter_validate_fp { match validate_external_plugin_adapter_checks( - Key::CollectionV1, accounts, &external_checks, authority_info, @@ -575,3 +541,108 @@ pub(crate) fn resolve_authority<'a>( None => Ok(payer), } } + +/// Returns true if the `authority_info` represents either the update authority of the asset +/// or a valid update delegate (defined by an `UpdateDelegate` plugin on the asset). +/// +/// When the asset's update authority is `UpdateAuthority::Collection`, the signer is +/// validated against the collection's update authority (and its update delegates) by +/// locating the collection `AccountInfo` in `all_accounts`. Callers must ensure the +/// collection account is present in the transaction when operating on collection-bound +/// assets. +pub fn is_valid_asset_authority<'a>( + asset_info: &AccountInfo<'a>, + authority_info: &AccountInfo<'a>, + all_accounts: &'a [AccountInfo<'a>], +) -> Result { + let asset_core = AssetV1::load(asset_info, 0)?; + + match &asset_core.update_authority { + UpdateAuthority::Address(addr) => { + if addr == authority_info.key { + return Ok(true); + } + } + UpdateAuthority::Collection(collection_addr) => { + match all_accounts.iter().find(|a| a.key == collection_addr) { + Some(collection_info) => { + if is_valid_collection_authority(collection_info, authority_info)? { + return Ok(true); + } + } + None => { + msg!( + "Asset has UpdateAuthority::Collection but the collection \ + account {} was not provided in the transaction", + collection_addr + ); + } + } + } + UpdateAuthority::None => {} + } + + // Attempt to locate an UpdateDelegate plugin on the asset itself. + match fetch_wrapped_plugin::(asset_info, Some(&asset_core), PluginType::UpdateDelegate) + { + Ok((_plugin_authority, Plugin::UpdateDelegate(update_delegate))) => { + if update_delegate + .additional_delegates + .contains(authority_info.key) + { + return Ok(true); + } + } + Ok(_) => return Err(MplCoreError::InvalidPlugin.into()), + Err(ProgramError::Custom(code)) + if code == MplCoreError::PluginNotFound as u32 + || code == MplCoreError::PluginsNotInitialized as u32 => {} + Err(err) => return Err(err), + } + + Ok(false) +} + +/// Returns true if the `authority_info` represents the group's update authority. +pub fn is_valid_group_authority( + group_info: &AccountInfo, + authority_info: &AccountInfo, +) -> Result { + let group_core = GroupV1::load(group_info, 0)?; + Ok(authority_info.key == &group_core.update_authority) +} + +/// Returns true if the `authority_info` represents either the update authority of the collection +/// or a valid update delegate (defined by an `UpdateDelegate` plugin on the collection). +pub fn is_valid_collection_authority( + collection_info: &AccountInfo, + authority_info: &AccountInfo, +) -> Result { + let collection_core = CollectionV1::load(collection_info, 0)?; + if authority_info.key == &collection_core.update_authority { + return Ok(true); + } + + // Attempt to locate an UpdateDelegate plugin on the collection. + match fetch_wrapped_plugin::( + collection_info, + Some(&collection_core), + PluginType::UpdateDelegate, + ) { + Ok((_plugin_authority, Plugin::UpdateDelegate(update_delegate))) => { + if update_delegate + .additional_delegates + .contains(authority_info.key) + { + return Ok(true); + } + } + Ok(_) => return Err(MplCoreError::InvalidPlugin.into()), + Err(ProgramError::Custom(code)) + if code == MplCoreError::PluginNotFound as u32 + || code == MplCoreError::PluginsNotInitialized as u32 => {} + Err(err) => return Err(err), + } + + Ok(false) +} diff --git a/programs/mpl-core/tests/account_ownership.rs b/programs/mpl-core/tests/account_ownership.rs new file mode 100644 index 00000000..a2d4caba --- /dev/null +++ b/programs/mpl-core/tests/account_ownership.rs @@ -0,0 +1,1264 @@ +// Account Ownership Tests for mpl-core +// +// These tests use Mollusk to verify that mpl-core instructions properly reject +// accounts owned by other programs, even when those accounts contain valid +// mpl-core discriminator bytes and correctly serialized data. +// +// The tests prove that the existing defense layers (discriminator checks, +// authority validation, and Solana's runtime write protection) already prevent +// exploitation of fake accounts. The explicit owner check in SolanaAccount::load +// is a defense-in-depth measure that provides clearer error messages and +// earlier rejection. + +#[allow(deprecated)] +use { + borsh::BorshSerialize, + mollusk_svm::Mollusk, + mpl_core_program::{ + plugins::{ + FreezeDelegate, PermanentBurnDelegate, PermanentFreezeDelegate, + PermanentTransferDelegate, Plugin, PluginHeaderV1, PluginRegistryV1, PluginType, + RegistryRecord, + }, + state::{AssetV1, Authority, CollectionV1, DataBlob, Key, UpdateAuthority}, + ID as MPL_CORE_ID, + }, + solana_sdk::{ + account::Account, + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_program, + }, +}; + +// --------------------------------------------------------------------------- +// Constants +// --------------------------------------------------------------------------- + +/// A fake program ID representing an attacker's program. +const FAKE_PROGRAM_ID: Pubkey = Pubkey::new_from_array([0xAA; 32]); + +/// Minimum lamports for accounts to be rent-exempt-ish in tests. +const ACCOUNT_LAMPORTS: u64 = 1_000_000_000; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// Creates a Mollusk instance for the mpl-core program. +fn core_mollusk() -> Mollusk { + Mollusk::new(&MPL_CORE_ID, "mpl_core_program") +} + +/// Serializes an AssetV1 into an Account owned by the given program. +fn fake_asset_account(owner_pubkey: &Pubkey, program_owner: &Pubkey) -> Account { + let asset = AssetV1::new( + *owner_pubkey, + UpdateAuthority::Address(*owner_pubkey), + "Fake Asset".to_string(), + "https://example.com/fake".to_string(), + ); + let data = asset.try_to_vec().unwrap(); + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: *program_owner, + executable: false, + rent_epoch: 0, + } +} + +/// Serializes a CollectionV1 into an Account owned by the given program. +fn fake_collection_account(update_authority: &Pubkey, program_owner: &Pubkey) -> Account { + let collection = CollectionV1::new( + *update_authority, + "Fake".to_string(), + "https://example.com".to_string(), + 0, + 0, + ); + let data = collection.try_to_vec().unwrap(); + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: *program_owner, + executable: false, + rent_epoch: 0, + } +} + +/// Creates a valid asset account owned by the mpl-core program. +fn valid_asset_account(owner_pubkey: &Pubkey) -> Account { + fake_asset_account(owner_pubkey, &MPL_CORE_ID) +} + +/// Creates a payer account with lamports. +fn payer_account() -> Account { + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + } +} + +/// Builds a TransferV1 instruction with the collection account set to a real pubkey. +fn transfer_v1_with_collection_instruction( + asset: Pubkey, + collection: Pubkey, + payer: Pubkey, + new_owner: Pubkey, +) -> Instruction { + let data = vec![14u8, 0u8]; // TransferV1 discriminator + None compression_proof + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, false), // 0: asset (writable) + AccountMeta::new_readonly(collection, false), // 1: collection + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 3: authority (signer) + AccountMeta::new_readonly(new_owner, false), // 4: new_owner + AccountMeta::new_readonly(system_program::ID, false), // 5: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 6: log_wrapper (optional) + ], + ) +} + +/// Constructs an Account with valid AssetV1 data + serialized plugins, owned by `program_owner`. +/// +/// The account data layout is: +/// [AssetV1 data][PluginHeaderV1][Plugin data...][PluginRegistryV1] +fn build_asset_with_plugins( + owner: &Pubkey, + program_owner: &Pubkey, + plugins: &[(Plugin, Authority)], +) -> Account { + let asset = AssetV1::new( + *owner, + UpdateAuthority::Address(*owner), + "Fake Asset".to_string(), + "https://example.com/fake".to_string(), + ); + let asset_data = asset.try_to_vec().unwrap(); + let asset_len = asset.len(); + + // Build plugin data and registry records. + let header_offset = asset_len; + let plugins_start = header_offset + 9; // PluginHeaderV1 is 9 bytes (Key + usize) + + let mut plugin_data = Vec::new(); + let mut registry_records = Vec::new(); + + for (plugin, authority) in plugins { + let offset = plugins_start + plugin_data.len(); + let plugin_bytes = plugin.try_to_vec().unwrap(); + plugin_data.extend_from_slice(&plugin_bytes); + + let plugin_type = match plugin { + Plugin::FreezeDelegate(_) => PluginType::FreezeDelegate, + Plugin::PermanentFreezeDelegate(_) => PluginType::PermanentFreezeDelegate, + Plugin::PermanentTransferDelegate(_) => PluginType::PermanentTransferDelegate, + Plugin::PermanentBurnDelegate(_) => PluginType::PermanentBurnDelegate, + _ => panic!("Unsupported plugin type in test helper"), + }; + + registry_records.push(RegistryRecord { + plugin_type, + authority: *authority, + offset, + }); + } + + let registry_offset = plugins_start + plugin_data.len(); + + let header = PluginHeaderV1 { + key: Key::PluginHeaderV1, + plugin_registry_offset: registry_offset, + }; + + let registry = PluginRegistryV1 { + key: Key::PluginRegistryV1, + registry: registry_records, + external_registry: vec![], + }; + + let header_bytes = header.try_to_vec().unwrap(); + let registry_bytes = registry.try_to_vec().unwrap(); + + let mut data = Vec::new(); + data.extend_from_slice(&asset_data); + data.extend_from_slice(&header_bytes); + data.extend_from_slice(&plugin_data); + data.extend_from_slice(®istry_bytes); + + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: *program_owner, + executable: false, + rent_epoch: 0, + } +} + +/// Constructs an Account with valid CollectionV1 data + serialized plugins, owned by `program_owner`. +fn build_collection_with_plugins( + update_authority: &Pubkey, + program_owner: &Pubkey, + plugins: &[(Plugin, Authority)], +) -> Account { + let collection = CollectionV1::new( + *update_authority, + "Fake Collection".to_string(), + "https://example.com".to_string(), + 0, + 0, + ); + let collection_data = collection.try_to_vec().unwrap(); + let collection_len = collection.len(); + + let header_offset = collection_len; + let plugins_start = header_offset + 9; + + let mut plugin_data = Vec::new(); + let mut registry_records = Vec::new(); + + for (plugin, authority) in plugins { + let offset = plugins_start + plugin_data.len(); + let plugin_bytes = plugin.try_to_vec().unwrap(); + plugin_data.extend_from_slice(&plugin_bytes); + + let plugin_type = match plugin { + Plugin::FreezeDelegate(_) => PluginType::FreezeDelegate, + Plugin::PermanentFreezeDelegate(_) => PluginType::PermanentFreezeDelegate, + Plugin::PermanentTransferDelegate(_) => PluginType::PermanentTransferDelegate, + Plugin::PermanentBurnDelegate(_) => PluginType::PermanentBurnDelegate, + _ => panic!("Unsupported plugin type in test helper"), + }; + + registry_records.push(RegistryRecord { + plugin_type, + authority: *authority, + offset, + }); + } + + let registry_offset = plugins_start + plugin_data.len(); + + let header = PluginHeaderV1 { + key: Key::PluginHeaderV1, + plugin_registry_offset: registry_offset, + }; + + let registry = PluginRegistryV1 { + key: Key::PluginRegistryV1, + registry: registry_records, + external_registry: vec![], + }; + + let header_bytes = header.try_to_vec().unwrap(); + let registry_bytes = registry.try_to_vec().unwrap(); + + let mut data = Vec::new(); + data.extend_from_slice(&collection_data); + data.extend_from_slice(&header_bytes); + data.extend_from_slice(&plugin_data); + data.extend_from_slice(®istry_bytes); + + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: *program_owner, + executable: false, + rent_epoch: 0, + } +} + +/// Builds a TransferV1 instruction. +/// Discriminator 14, with Option::None compression_proof. +fn transfer_v1_instruction(asset: Pubkey, payer: Pubkey, new_owner: Pubkey) -> Instruction { + let data = vec![14u8, 0u8]; // TransferV1 discriminator + None compression_proof + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, false), // 0: asset (writable) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: collection (optional, use program ID) + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 3: authority (signer) + AccountMeta::new_readonly(new_owner, false), // 4: new_owner + AccountMeta::new_readonly(system_program::ID, false), // 5: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 6: log_wrapper (optional) + ], + ) +} + +/// Builds a BurnV1 instruction. +/// Discriminator 12, with Option::None compression_proof. +fn burn_v1_instruction(asset: Pubkey, payer: Pubkey) -> Instruction { + let data = vec![12u8, 0u8]; // BurnV1 discriminator + None compression_proof + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, false), // 0: asset (writable) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: collection (optional) + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 3: authority (signer) + AccountMeta::new_readonly(system_program::ID, false), // 4: system_program (optional) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 5: log_wrapper (optional) + ], + ) +} + +/// Builds an UpdateV1 instruction that changes the name to "X". +/// Discriminator 15, with Some(name) and None for the rest. +fn update_v1_instruction(asset: Pubkey, payer: Pubkey) -> Instruction { + // UpdateV1Args { new_name: Some("X"), new_uri: None, new_update_authority: None } + let mut data = vec![15u8]; // discriminator + data.push(1); // Option::Some for new_name + data.extend_from_slice(&1u32.to_le_bytes()); // string length = 1 + data.push(b'X'); // "X" + data.push(0); // Option::None for new_uri + data.push(0); // Option::None for new_update_authority + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, false), // 0: asset (writable) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: collection (optional) + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 3: authority (signer) + AccountMeta::new_readonly(system_program::ID, false), // 4: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 5: log_wrapper (optional) + ], + ) +} + +/// Builds an UpdateCollectionV1 instruction that changes the name to "X". +/// Discriminator 16, with Some(name) and None uri. +fn update_collection_v1_instruction(collection: Pubkey, payer: Pubkey) -> Instruction { + // UpdateCollectionV1Args { new_name: Some("X"), new_uri: None } + let mut data = vec![16u8]; // discriminator + data.push(1); // Option::Some for new_name + data.extend_from_slice(&1u32.to_le_bytes()); // string length = 1 + data.push(b'X'); // "X" + data.push(0); // Option::None for new_uri + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(collection, false), // 0: collection (writable) + AccountMeta::new(payer, true), // 1: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 2: authority (signer) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 3: new_update_authority (optional) + AccountMeta::new_readonly(system_program::ID, false), // 4: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 5: log_wrapper (optional) + ], + ) +} + +/// Converts accounts Vec into the shared data format Mollusk expects. +fn to_mollusk_accounts(accounts: Vec<(Pubkey, Account)>) -> Vec<(Pubkey, Account)> { + let mut result = accounts; + + // System program account must be present and executable. + if let Some(pos) = result.iter().position(|(k, _)| *k == system_program::ID) { + result.remove(pos); + } + let (sys_key, sys_account) = mollusk_svm::program::keyed_account_for_system_program(); + result.push((sys_key, sys_account)); + + result +} + +/// Asserts the instruction failed (any error). +fn assert_failure(result: &mollusk_svm::result::InstructionResult) { + assert!( + !matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Expected instruction to fail, but it succeeded" + ); +} + +// =========================================================================== +// Section 1: Fake assets owned by a different program +// +// These tests create accounts with valid mpl-core AssetV1 data (correct +// discriminator byte, valid Borsh-serialized fields) but owned by a +// different program. They verify that mpl-core instructions reject these +// fake accounts. +// =========================================================================== + +#[test] +fn transfer_rejects_fake_asset_owned_by_different_program() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Create a fake asset owned by FAKE_PROGRAM_ID with payer as the asset owner. + let fake_asset = fake_asset_account(&payer, &FAKE_PROGRAM_ID); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn burn_rejects_fake_asset_owned_by_different_program() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let fake_asset = fake_asset_account(&payer, &FAKE_PROGRAM_ID); + + let instruction = burn_v1_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn update_rejects_fake_asset_owned_by_different_program() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let fake_asset = fake_asset_account(&payer, &FAKE_PROGRAM_ID); + + let instruction = update_v1_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 2: Fake collections owned by a different program +// =========================================================================== + +#[test] +fn update_collection_rejects_fake_collection_owned_by_different_program() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let collection_key = Pubkey::new_unique(); + + let fake_collection = fake_collection_account(&payer, &FAKE_PROGRAM_ID); + + let instruction = update_collection_v1_instruction(collection_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (collection_key, fake_collection), + (payer, payer_account()), + (MPL_CORE_ID, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 3: Accounts with wrong discriminator +// +// Even with valid Borsh data, an account with the wrong discriminator byte +// should be rejected immediately. +// =========================================================================== + +#[test] +fn transfer_rejects_account_with_wrong_discriminator() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Create account data with CollectionV1 discriminator (5) instead of AssetV1 (1). + let collection = CollectionV1::new( + payer, + "Wrong".to_string(), + "https://wrong.com".to_string(), + 0, + 0, + ); + let data = collection.try_to_vec().unwrap(); + let wrong_disc_account = Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_CORE_ID, // Even with correct owner! + executable: false, + rent_epoch: 0, + }; + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, wrong_disc_account), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn burn_rejects_account_with_wrong_discriminator() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + // Use Uninitialized key (0) - completely wrong discriminator. + let mut data = vec![0u8; 100]; // Key::Uninitialized = 0 + data[0] = Key::Uninitialized as u8; + let wrong_disc_account = Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + }; + + let instruction = burn_v1_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, wrong_disc_account), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 4: Random / garbage data accounts +// +// Accounts with completely random data should fail at deserialization. +// =========================================================================== + +#[test] +fn transfer_rejects_random_data_account() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + let garbage_account = Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![0xFF; 200], + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + }; + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, garbage_account), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 5: Empty accounts +// +// Completely empty accounts should fail immediately. +// =========================================================================== + +#[test] +fn transfer_rejects_empty_account() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + let empty_account = Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + }; + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, empty_account), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 6: Valid accounts work correctly (sanity checks) +// +// Ensure that properly owned mpl-core accounts ARE accepted so we know +// our test harness works correctly. +// =========================================================================== + +#[test] +fn transfer_succeeds_with_valid_asset() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + let asset = valid_asset_account(&payer); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + // This should succeed because the asset is owned by mpl-core, the + // discriminator matches, and the payer is the asset owner. + assert!( + matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Expected transfer to succeed with valid asset, got: {:?}", + result.program_result + ); +} + +// =========================================================================== +// Section 7: System-program-owned accounts (uninitialized) +// +// A system-program-owned account with an AssetV1 discriminator should fail. +// This simulates someone trying to use an unrelated system account. +// =========================================================================== + +#[test] +fn transfer_rejects_system_owned_account_with_asset_discriminator() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Create account with valid AssetV1 data but owned by system program. + let fake_asset = fake_asset_account(&payer, &system_program::ID); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn update_rejects_system_owned_account_with_asset_discriminator() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let fake_asset = fake_asset_account(&payer, &system_program::ID); + + let instruction = update_v1_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 8: Fake asset with mismatched authority +// +// Even if an account has valid AssetV1 data and is owned by mpl-core, +// the authority check should reject unauthorized callers. +// =========================================================================== + +#[test] +fn transfer_rejects_unauthorized_caller_on_valid_asset() { + let mollusk = core_mollusk(); + let actual_owner = Pubkey::new_unique(); + let attacker = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Asset is owned by actual_owner, but attacker is trying to transfer. + let asset = valid_asset_account(&actual_owner); + + let instruction = transfer_v1_instruction(asset_key, attacker, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset), + (MPL_CORE_ID, Account::default()), + (attacker, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn burn_rejects_unauthorized_caller_on_valid_asset() { + let mollusk = core_mollusk(); + let actual_owner = Pubkey::new_unique(); + let attacker = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let asset = valid_asset_account(&actual_owner); + + let instruction = burn_v1_instruction(asset_key, attacker); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset), + (MPL_CORE_ID, Account::default()), + (attacker, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 9: Fake assets with freeze plugins (owned by different program) +// +// These tests create accounts with valid AssetV1 data AND embedded +// FreezeDelegate plugin data, but owned by FAKE_PROGRAM_ID. They verify +// that mpl-core rejects these fake accounts regardless of freeze state. +// =========================================================================== + +#[test] +fn transfer_rejects_fake_frozen_asset_owned_by_different_program() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Fake asset with FreezeDelegate{frozen: true}, owned by attacker's program. + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::FreezeDelegate(FreezeDelegate { frozen: true }), + Authority::Owner, + )], + ); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn transfer_rejects_fake_unfrozen_asset_owned_by_different_program() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Fake asset with FreezeDelegate{frozen: false} -- even an "unfrozen" fake must fail. + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::FreezeDelegate(FreezeDelegate { frozen: false }), + Authority::Owner, + )], + ); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn burn_rejects_fake_frozen_asset_owned_by_different_program() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::FreezeDelegate(FreezeDelegate { frozen: true }), + Authority::Owner, + )], + ); + + let instruction = burn_v1_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 10: Fake assets with permanent delegate plugins +// +// Permanent delegates can force-approve transfers/burns. These tests verify +// that even with PermanentTransferDelegate or PermanentBurnDelegate embedded +// in a fake account, the instruction is still rejected because the account +// is not owned by mpl-core. +// =========================================================================== + +#[test] +fn transfer_rejects_fake_asset_with_permanent_transfer_delegate() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // PermanentTransferDelegate allows anyone to transfer -- but not on a fake account. + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::PermanentTransferDelegate(PermanentTransferDelegate {}), + Authority::Owner, + )], + ); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn burn_rejects_fake_asset_with_permanent_burn_delegate() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + // PermanentBurnDelegate allows anyone to burn -- but not on a fake account. + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::PermanentBurnDelegate(PermanentBurnDelegate {}), + Authority::Owner, + )], + ); + + let instruction = burn_v1_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn transfer_rejects_fake_asset_with_permanent_freeze_frozen() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // PermanentFreezeDelegate{frozen: true} on a fake account. + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::PermanentFreezeDelegate(PermanentFreezeDelegate { frozen: true }), + Authority::Owner, + )], + ); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 11: Fake assets with multiple conflicting plugins +// +// Tests that even with "favorable" plugin combinations (e.g., frozen but +// with PermanentTransferDelegate), fake accounts are still rejected. +// =========================================================================== + +#[test] +fn transfer_rejects_fake_asset_frozen_but_with_permanent_transfer() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // FreezeDelegate{frozen:true} + PermanentTransferDelegate -- the permanent + // delegate would normally force-approve, but the fake account fails first. + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[ + ( + Plugin::FreezeDelegate(FreezeDelegate { frozen: true }), + Authority::Owner, + ), + ( + Plugin::PermanentTransferDelegate(PermanentTransferDelegate {}), + Authority::Owner, + ), + ], + ); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn burn_rejects_fake_asset_unfrozen_with_permanent_burn() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + // PermanentBurnDelegate + FreezeDelegate{frozen:false} -- all favorable + // plugin state, but fake account ownership means rejection. + let fake_asset = build_asset_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[ + ( + Plugin::FreezeDelegate(FreezeDelegate { frozen: false }), + Authority::Owner, + ), + ( + Plugin::PermanentBurnDelegate(PermanentBurnDelegate {}), + Authority::Owner, + ), + ], + ); + + let instruction = burn_v1_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, fake_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 12: Fake collections with plugins +// +// Valid assets that reference a fake collection (owned by FAKE_PROGRAM_ID) +// with favorable plugin data. The owner check in SolanaAccount::load +// rejects the fake collection with InvalidAccountOwner before any plugin +// data is even evaluated. +// =========================================================================== + +#[test] +fn transfer_rejects_when_fake_collection_has_permanent_freeze() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let collection_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Valid asset that belongs to a collection. + let asset = AssetV1::new( + payer, + UpdateAuthority::Collection(collection_key), + "Real Asset".to_string(), + "https://example.com/real".to_string(), + ); + let asset_account = Account { + lamports: ACCOUNT_LAMPORTS, + data: asset.try_to_vec().unwrap(), + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + }; + + // Fake collection with PermanentFreezeDelegate{frozen: false}, owned by + // FAKE_PROGRAM_ID. The owner check rejects this before plugins are evaluated. + let fake_collection = build_collection_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::PermanentFreezeDelegate(PermanentFreezeDelegate { frozen: false }), + Authority::UpdateAuthority, + )], + ); + + let instruction = + transfer_v1_with_collection_instruction(asset_key, collection_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (collection_key, fake_collection), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +#[test] +fn transfer_rejects_when_fake_collection_has_permanent_transfer_delegate() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let collection_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + let asset = AssetV1::new( + payer, + UpdateAuthority::Collection(collection_key), + "Real Asset".to_string(), + "https://example.com/real".to_string(), + ); + let asset_account = Account { + lamports: ACCOUNT_LAMPORTS, + data: asset.try_to_vec().unwrap(), + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + }; + + // Fake collection with PermanentTransferDelegate -- owned by FAKE_PROGRAM_ID. + // The owner check rejects this before plugins are evaluated. + let fake_collection = build_collection_with_plugins( + &payer, + &FAKE_PROGRAM_ID, + &[( + Plugin::PermanentTransferDelegate(PermanentTransferDelegate {}), + Authority::UpdateAuthority, + )], + ); + + let instruction = + transfer_v1_with_collection_instruction(asset_key, collection_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (collection_key, fake_collection), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + assert_failure(&result); +} + +// =========================================================================== +// Section 13: Valid frozen asset sanity checks +// +// Verify that plugin enforcement actually works on valid mpl-core-owned +// accounts: frozen assets should reject transfer, unfrozen assets with +// freeze plugin should allow transfer. +// =========================================================================== + +#[test] +fn transfer_rejects_valid_frozen_asset() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Valid mpl-core-owned asset with FreezeDelegate{frozen: true}. + let frozen_asset = build_asset_with_plugins( + &payer, + &MPL_CORE_ID, + &[( + Plugin::FreezeDelegate(FreezeDelegate { frozen: true }), + Authority::Owner, + )], + ); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, frozen_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + // A valid frozen asset should reject transfer due to freeze plugin. + assert_failure(&result); +} + +#[test] +fn transfer_succeeds_valid_unfrozen_asset_with_freeze_plugin() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let new_owner = Pubkey::new_unique(); + + // Valid mpl-core-owned asset with FreezeDelegate{frozen: false}. + let unfrozen_asset = build_asset_with_plugins( + &payer, + &MPL_CORE_ID, + &[( + Plugin::FreezeDelegate(FreezeDelegate { frozen: false }), + Authority::Owner, + )], + ); + + let instruction = transfer_v1_instruction(asset_key, payer, new_owner); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, unfrozen_asset), + (MPL_CORE_ID, Account::default()), + (payer, payer_account()), + (new_owner, Account::default()), + (system_program::ID, Account::default()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + + // An unfrozen valid asset should allow transfer by the owner. + assert!( + matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Expected transfer to succeed with valid unfrozen asset, got: {:?}", + result.program_result + ); +} diff --git a/programs/mpl-core/tests/agent_identity.rs b/programs/mpl-core/tests/agent_identity.rs new file mode 100644 index 00000000..7933acd6 --- /dev/null +++ b/programs/mpl-core/tests/agent_identity.rs @@ -0,0 +1,918 @@ +// Agent Identity External Plugin Mollusk Tests +// +// These tests verify the AgentIdentity external plugin adapter behavior using +// Mollusk, which allows us to force the agent identity PDA to be a signer +// without needing the mpl-agent-identity program deployed. Mollusk bypasses +// transaction-level signature verification, so we can set `signer: true` on +// the PDA's AccountMeta and the program's `assert_signer()` check will pass. + +#[allow(deprecated)] +use { + borsh::BorshSerialize, + mollusk_svm::Mollusk, + mpl_core_program::{ + plugins::{ + AgentIdentity, AgentIdentityInitInfo, AgentIdentityUpdateInfo, ExternalCheckResult, + ExternalPluginAdapter, ExternalPluginAdapterInitInfo, ExternalPluginAdapterKey, + ExternalPluginAdapterType, ExternalPluginAdapterUpdateInfo, ExternalRegistryRecord, + HookableLifecycleEvent, PluginHeaderV1, PluginRegistryV1, + }, + state::{AssetV1, Authority, CollectionV1, DataBlob, Key, UpdateAuthority}, + ID as MPL_CORE_ID, + }, + solana_program::program_error::ProgramError, + solana_sdk::{ + account::Account, + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_program, + }, +}; + +// The mpl-agent-identity program ID used for PDA derivation. +const AGENT_IDENTITY_PROGRAM_ID: Pubkey = + solana_sdk::pubkey!("1DREGFgysWYxLnRnKQnwrxnJQeSMk2HmGaC6whw2B2p"); + +/// Minimum lamports for accounts to be rent-exempt-ish in tests. +const ACCOUNT_LAMPORTS: u64 = 1_000_000_000; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +/// Creates a Mollusk instance for the mpl-core program. +fn core_mollusk() -> Mollusk { + Mollusk::new(&MPL_CORE_ID, "mpl_core_program") +} + +/// Creates a payer account with lamports. +fn payer_account() -> Account { + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + } +} + +/// Normalizes accounts for Mollusk by replacing any system program entry with +/// the proper executable account. +fn to_mollusk_accounts(accounts: Vec<(Pubkey, Account)>) -> Vec<(Pubkey, Account)> { + let mut result = accounts; + + // Remove duplicate system program if present. + if let Some(pos) = result.iter().position(|(k, _)| *k == system_program::ID) { + result.remove(pos); + } + + let (sys_key, sys_account) = mollusk_svm::program::keyed_account_for_system_program(); + result.push((sys_key, sys_account)); + + result +} + +/// Derive the agent identity PDA for an asset. +fn agent_identity_pda(asset: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address( + &[b"agent_identity", asset.as_ref()], + &AGENT_IDENTITY_PROGRAM_ID, + ) +} + +fn assert_success(result: &mollusk_svm::result::InstructionResult) { + assert!( + matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Expected instruction to succeed, got: {:?}", + result.program_result + ); +} + +fn assert_failure( + result: &mollusk_svm::result::InstructionResult, + expected: solana_program::program_error::ProgramError, +) { + match &result.program_result { + mollusk_svm::result::ProgramResult::Success => { + panic!( + "Expected instruction to fail with {:?}, but it succeeded", + expected + ); + } + mollusk_svm::result::ProgramResult::Failure(err) => { + assert_eq!( + *err, expected, + "Expected error {:?}, got {:?}", + expected, err + ); + } + mollusk_svm::result::ProgramResult::UnknownError(err) => { + panic!( + "Expected ProgramError {:?}, got UnknownError({:?})", + expected, err + ); + } + } +} + +// --------------------------------------------------------------------------- +// Account data builders +// --------------------------------------------------------------------------- + +/// Serializes a bare AssetV1 (no plugins) owned by mpl-core. +fn valid_asset_account(owner: &Pubkey) -> Account { + let asset = AssetV1::new( + *owner, + UpdateAuthority::Address(*owner), + "Test Asset".to_string(), + "https://example.com/test".to_string(), + ); + let data = asset.try_to_vec().unwrap(); + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + } +} + +/// Builds an Account containing an AssetV1 with an AgentIdentity external +/// plugin already initialized. +fn build_asset_with_agent_identity( + owner: &Pubkey, + uri: &str, + plugin_authority: Authority, + lifecycle_checks: Vec<(HookableLifecycleEvent, ExternalCheckResult)>, +) -> Account { + let asset = AssetV1::new( + *owner, + UpdateAuthority::Address(*owner), + "Test Asset".to_string(), + "https://example.com/test".to_string(), + ); + let asset_data = asset.try_to_vec().unwrap(); + let asset_len = asset.len(); + + // Plugin header sits immediately after core data. + let header_offset = asset_len; + // PluginHeaderV1 is 9 bytes: 1 (Key) + 8 (usize). + let plugin_data_start = header_offset + 9; + + // Serialize the external plugin adapter data. + let plugin = ExternalPluginAdapter::AgentIdentity(AgentIdentity { + uri: uri.to_string(), + }); + let plugin_bytes = plugin.try_to_vec().unwrap(); + + // The registry sits after the plugin data. + let registry_offset = plugin_data_start + plugin_bytes.len(); + + let header = PluginHeaderV1 { + key: Key::PluginHeaderV1, + plugin_registry_offset: registry_offset, + }; + + let external_record = ExternalRegistryRecord { + plugin_type: ExternalPluginAdapterType::AgentIdentity, + authority: plugin_authority, + lifecycle_checks: Some(lifecycle_checks), + offset: plugin_data_start, + data_offset: None, + data_len: None, + }; + + let registry = PluginRegistryV1 { + key: Key::PluginRegistryV1, + registry: vec![], + external_registry: vec![external_record], + }; + + let header_bytes = header.try_to_vec().unwrap(); + let registry_bytes = registry.try_to_vec().unwrap(); + + let mut data = Vec::new(); + data.extend_from_slice(&asset_data); + data.extend_from_slice(&header_bytes); + data.extend_from_slice(&plugin_bytes); + data.extend_from_slice(®istry_bytes); + + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + } +} + +// --------------------------------------------------------------------------- +// Instruction builders +// --------------------------------------------------------------------------- + +/// Builds a CreateV2 instruction with an AgentIdentity external plugin. +/// +/// Discriminator: 20 +/// Account layout: +/// 0: asset (writable, signer) +/// 1: collection (optional) - use program ID as placeholder +/// 2: authority (optional, signer) - use program ID as placeholder +/// 3: payer (writable, signer) +/// 4: owner (optional) - use program ID as placeholder +/// 5: update_authority (optional) - use program ID as placeholder +/// 6: system_program +/// 7: log_wrapper (optional) - use program ID as placeholder +/// 8: agent_identity_pda (signer) - remaining account +fn create_v2_with_agent_identity( + asset: Pubkey, + payer: Pubkey, + agent_identity_pda: Pubkey, + init_info: &AgentIdentityInitInfo, +) -> Instruction { + // Serialize instruction data manually: discriminator + CreateV2Args fields. + let mut data = vec![20u8]; // CreateV2 discriminator + + // DataState::AccountState = variant 0 + 0u8.serialize(&mut data).unwrap(); + // name: String + "Test Asset".to_string().serialize(&mut data).unwrap(); + // uri: String + "https://example.com/test" + .to_string() + .serialize(&mut data) + .unwrap(); + // plugins: Option> = None + 0u8.serialize(&mut data).unwrap(); + // external_plugin_adapters: Option> = Some(vec![...]) + let adapters = vec![ExternalPluginAdapterInitInfo::AgentIdentity( + init_info.clone(), + )]; + Some(adapters).serialize(&mut data).unwrap(); + + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, true), // 0: asset (writable, signer) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: collection (optional) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 2: authority (optional) + AccountMeta::new(payer, true), // 3: payer (writable, signer) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 4: owner (optional) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 5: update_authority (optional) + AccountMeta::new_readonly(system_program::ID, false), // 6: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 7: log_wrapper (optional) + AccountMeta::new_readonly(agent_identity_pda, true), // 8: PDA (signer!) + ], + ) +} + +/// Builds a CreateCollectionV2 instruction with an AgentIdentity external plugin. +/// +/// Discriminator: 21 +/// Account layout: +/// 0: collection (writable, signer) +/// 1: update_authority (optional) +/// 2: payer (writable, signer) +/// 3: system_program +fn create_collection_v2_with_agent_identity( + collection: Pubkey, + payer: Pubkey, + init_info: &AgentIdentityInitInfo, +) -> Instruction { + let mut data = vec![21u8]; // CreateCollectionV2 discriminator + + // name: String + "Test Collection".to_string().serialize(&mut data).unwrap(); + // uri: String + "https://example.com/collection" + .to_string() + .serialize(&mut data) + .unwrap(); + // plugins: Option> = None + 0u8.serialize(&mut data).unwrap(); + // external_plugin_adapters: Option> = Some(vec![...]) + let adapters = vec![ExternalPluginAdapterInitInfo::AgentIdentity( + init_info.clone(), + )]; + Some(adapters).serialize(&mut data).unwrap(); + + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(collection, true), // 0: collection (writable, signer) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: update_authority (optional) + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(system_program::ID, false), // 3: system_program + ], + ) +} + +/// Builds an AddExternalPluginAdapterV1 instruction for AgentIdentity. +/// +/// Discriminator: 22 +/// Account layout: +/// 0: asset (writable) +/// 1: collection (optional) +/// 2: payer (writable, signer) +/// 3: authority (optional, signer) +/// 4: system_program +/// 5: log_wrapper (optional) +/// 6: agent_identity_pda (signer!) - remaining account +fn add_agent_identity_instruction( + asset: Pubkey, + payer: Pubkey, + agent_identity_pda: Pubkey, + init_info: &AgentIdentityInitInfo, +) -> Instruction { + let mut data = vec![22u8]; // AddExternalPluginAdapterV1 discriminator + + // init_info: ExternalPluginAdapterInitInfo + ExternalPluginAdapterInitInfo::AgentIdentity(init_info.clone()) + .serialize(&mut data) + .unwrap(); + + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, false), // 0: asset (writable) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: collection (optional) + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 3: authority (signer) + AccountMeta::new_readonly(system_program::ID, false), // 4: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 5: log_wrapper (optional) + AccountMeta::new_readonly(agent_identity_pda, true), // 6: PDA (signer!) + ], + ) +} + +/// Builds an AddCollectionExternalPluginAdapterV1 instruction for AgentIdentity. +/// +/// Discriminator: 23 +/// Account layout: +/// 0: collection (writable) +/// 1: payer (writable, signer) +/// 2: authority (optional, signer) +/// 3: system_program +/// 4: log_wrapper (optional) +fn add_collection_agent_identity_instruction( + collection: Pubkey, + payer: Pubkey, + init_info: &AgentIdentityInitInfo, +) -> Instruction { + let mut data = vec![23u8]; // AddCollectionExternalPluginAdapterV1 discriminator + + ExternalPluginAdapterInitInfo::AgentIdentity(init_info.clone()) + .serialize(&mut data) + .unwrap(); + + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(collection, false), // 0: collection (writable) + AccountMeta::new(payer, true), // 1: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 2: authority (signer) + AccountMeta::new_readonly(system_program::ID, false), // 3: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 4: log_wrapper (optional) + ], + ) +} + +/// Builds an UpdateExternalPluginAdapterV1 instruction. +/// +/// Discriminator: 26 +/// Account layout: +/// 0: asset (writable) +/// 1: collection (optional) +/// 2: payer (writable, signer) +/// 3: authority (optional, signer) +/// 4: system_program +/// 5: log_wrapper (optional) +fn update_agent_identity_instruction( + asset: Pubkey, + payer: Pubkey, + update_info: &AgentIdentityUpdateInfo, +) -> Instruction { + let mut data = vec![26u8]; // UpdateExternalPluginAdapterV1 discriminator + + // key: ExternalPluginAdapterKey + ExternalPluginAdapterKey::AgentIdentity + .serialize(&mut data) + .unwrap(); + // update_info: ExternalPluginAdapterUpdateInfo + ExternalPluginAdapterUpdateInfo::AgentIdentity(update_info.clone()) + .serialize(&mut data) + .unwrap(); + + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, false), // 0: asset (writable) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: collection (optional) + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 3: authority (signer) + AccountMeta::new_readonly(system_program::ID, false), // 4: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 5: log_wrapper (optional) + ], + ) +} + +/// Builds a RemoveExternalPluginAdapterV1 instruction. +/// +/// Discriminator: 24 +/// Account layout: +/// 0: asset (writable) +/// 1: collection (optional) +/// 2: payer (writable, signer) +/// 3: authority (optional, signer) +/// 4: system_program +/// 5: log_wrapper (optional) +fn remove_agent_identity_instruction(asset: Pubkey, payer: Pubkey) -> Instruction { + let mut data = vec![24u8]; // RemoveExternalPluginAdapterV1 discriminator + + // key: ExternalPluginAdapterKey + ExternalPluginAdapterKey::AgentIdentity + .serialize(&mut data) + .unwrap(); + + Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset, false), // 0: asset (writable) + AccountMeta::new_readonly(MPL_CORE_ID, false), // 1: collection (optional) + AccountMeta::new(payer, true), // 2: payer (writable, signer) + AccountMeta::new_readonly(payer, true), // 3: authority (signer) + AccountMeta::new_readonly(system_program::ID, false), // 4: system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // 5: log_wrapper (optional) + ], + ) +} + +// --------------------------------------------------------------------------- +// Default init/update info helpers +// --------------------------------------------------------------------------- + +fn default_agent_identity_init_info() -> AgentIdentityInitInfo { + AgentIdentityInitInfo { + uri: "https://example.com/agent.json".to_string(), + init_plugin_authority: None, // defaults to UpdateAuthority + lifecycle_checks: vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, // CAN_LISTEN + )], + } +} + +/// An empty Account (system-program owned, zero data) for a new asset key. +fn empty_asset_account() -> Account { + Account { + lamports: 0, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + } +} + +// =========================================================================== +// Happy-path tests +// =========================================================================== + +#[test] +fn create_asset_with_agent_identity() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset = Pubkey::new_unique(); + let (pda, _) = agent_identity_pda(&asset); + + let instruction = + create_v2_with_agent_identity(asset, payer, pda, &default_agent_identity_init_info()); + + let accounts = to_mollusk_accounts(vec![ + (asset, empty_asset_account()), + (payer, payer_account()), + (pda, payer_account()), // PDA account needs lamports to exist + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +#[test] +fn add_agent_identity_to_existing_asset() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (pda, _) = agent_identity_pda(&asset_key); + + let instruction = + add_agent_identity_instruction(asset_key, payer, pda, &default_agent_identity_init_info()); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, valid_asset_account(&payer)), + (payer, payer_account()), + (pda, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +#[test] +fn update_agent_identity_uri() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &payer, + "https://example.com/agent.json", + Authority::UpdateAuthority, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, + )], + ); + + let instruction = update_agent_identity_instruction( + asset_key, + payer, + &AgentIdentityUpdateInfo { + uri: Some("https://example.com/updated-agent.json".to_string()), + lifecycle_checks: None, + }, + ); + + let accounts = to_mollusk_accounts(vec![(asset_key, asset_account), (payer, payer_account())]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +#[test] +fn update_agent_identity_lifecycle_checks() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &payer, + "https://example.com/agent.json", + Authority::UpdateAuthority, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, + )], + ); + + let instruction = update_agent_identity_instruction( + asset_key, + payer, + &AgentIdentityUpdateInfo { + uri: None, + lifecycle_checks: Some(vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, // CAN_LISTEN | CAN_APPROVE + )]), + }, + ); + + let accounts = to_mollusk_accounts(vec![(asset_key, asset_account), (payer, payer_account())]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +#[test] +fn update_agent_identity_uri_and_lifecycle_checks() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &payer, + "https://example.com/agent.json", + Authority::UpdateAuthority, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, + )], + ); + + let instruction = update_agent_identity_instruction( + asset_key, + payer, + &AgentIdentityUpdateInfo { + uri: Some("https://example.com/agent-v3.json".to_string()), + lifecycle_checks: Some(vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x7 }, // CAN_LISTEN | CAN_APPROVE | CAN_REJECT + )]), + }, + ); + + let accounts = to_mollusk_accounts(vec![(asset_key, asset_account), (payer, payer_account())]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +#[test] +fn remove_agent_identity() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &payer, + "https://example.com/agent.json", + Authority::UpdateAuthority, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, + )], + ); + + let instruction = remove_agent_identity_instruction(asset_key, payer); + + let accounts = to_mollusk_accounts(vec![(asset_key, asset_account), (payer, payer_account())]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +#[test] +fn create_asset_with_agent_identity_multiple_lifecycle_checks() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset = Pubkey::new_unique(); + let (pda, _) = agent_identity_pda(&asset); + + let init_info = AgentIdentityInitInfo { + uri: "https://example.com/agent.json".to_string(), + init_plugin_authority: None, + lifecycle_checks: vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, // CAN_LISTEN | CAN_APPROVE + )], + }; + + let instruction = create_v2_with_agent_identity(asset, payer, pda, &init_info); + + let accounts = to_mollusk_accounts(vec![ + (asset, empty_asset_account()), + (payer, payer_account()), + (pda, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +#[test] +fn create_asset_with_agent_identity_address_authority() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset = Pubkey::new_unique(); + let (pda, _) = agent_identity_pda(&asset); + let plugin_authority = Pubkey::new_unique(); + + let init_info = AgentIdentityInitInfo { + uri: "https://example.com/agent.json".to_string(), + init_plugin_authority: Some(Authority::Address { + address: plugin_authority, + }), + lifecycle_checks: vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, + )], + }; + + let instruction = create_v2_with_agent_identity(asset, payer, pda, &init_info); + + let accounts = to_mollusk_accounts(vec![ + (asset, empty_asset_account()), + (payer, payer_account()), + (pda, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_success(&result); +} + +// =========================================================================== +// Negative / security tests +// =========================================================================== + +#[test] +fn cannot_create_collection_with_agent_identity() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let collection = Pubkey::new_unique(); + + let instruction = create_collection_v2_with_agent_identity( + collection, + payer, + &default_agent_identity_init_info(), + ); + + let accounts = to_mollusk_accounts(vec![ + (collection, empty_asset_account()), + (payer, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // AgentIdentity rejects collections via validate_create → InvalidPluginAdapterTarget (46). + assert_failure(&result, ProgramError::Custom(46)); +} + +#[test] +fn cannot_add_agent_identity_to_collection() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let collection_key = Pubkey::new_unique(); + + // Build a valid collection account. + let collection = CollectionV1::new( + payer, + "Test".to_string(), + "https://example.com".to_string(), + 0, + 0, + ); + let data = collection.try_to_vec().unwrap(); + let collection_account = Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + }; + + let instruction = add_collection_agent_identity_instruction( + collection_key, + payer, + &default_agent_identity_init_info(), + ); + + let accounts = to_mollusk_accounts(vec![ + (collection_key, collection_account), + (payer, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // AgentIdentity rejects collections via validate_add_external_plugin_adapter → InvalidPluginAdapterTarget (46). + assert_failure(&result, ProgramError::Custom(46)); +} + +#[test] +fn cannot_add_agent_identity_without_pda_remaining_account() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + // Build the instruction WITHOUT the PDA remaining account. + let mut data = vec![22u8]; // AddExternalPluginAdapterV1 discriminator + ExternalPluginAdapterInitInfo::AgentIdentity(default_agent_identity_init_info()) + .serialize(&mut data) + .unwrap(); + + let instruction = Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset_key, false), + AccountMeta::new_readonly(MPL_CORE_ID, false), // collection (optional) + AccountMeta::new(payer, true), // payer + AccountMeta::new_readonly(payer, true), // authority + AccountMeta::new_readonly(system_program::ID, false), // system_program + AccountMeta::new_readonly(MPL_CORE_ID, false), // log_wrapper (optional) + // NO PDA remaining account! + ], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, valid_asset_account(&payer)), + (payer, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // Last account is the log_wrapper placeholder (not a signer) → MissingRequiredSignature. + assert_failure(&result, ProgramError::MissingRequiredSignature); +} + +#[test] +fn cannot_add_agent_identity_with_wrong_pda() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + + // Use a completely wrong PDA (derived from a different asset). + let wrong_asset = Pubkey::new_unique(); + let (wrong_pda, _) = agent_identity_pda(&wrong_asset); + + let instruction = add_agent_identity_instruction( + asset_key, + payer, + wrong_pda, + &default_agent_identity_init_info(), + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, valid_asset_account(&payer)), + (payer, payer_account()), + (wrong_pda, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // PDA doesn't match derivation for asset_key → AgentIdentityMustSign (51). + assert_failure(&result, ProgramError::Custom(51)); +} + +#[test] +fn cannot_add_agent_identity_with_unsigned_pda() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (pda, _) = agent_identity_pda(&asset_key); + + // Build instruction with PDA present but NOT marked as signer. + let mut data = vec![22u8]; // AddExternalPluginAdapterV1 discriminator + ExternalPluginAdapterInitInfo::AgentIdentity(default_agent_identity_init_info()) + .serialize(&mut data) + .unwrap(); + + let instruction = Instruction::new_with_bytes( + MPL_CORE_ID, + &data, + vec![ + AccountMeta::new(asset_key, false), + AccountMeta::new_readonly(MPL_CORE_ID, false), + AccountMeta::new(payer, true), + AccountMeta::new_readonly(payer, true), + AccountMeta::new_readonly(system_program::ID, false), + AccountMeta::new_readonly(MPL_CORE_ID, false), + AccountMeta::new_readonly(pda, false), // PDA present but NOT signer + ], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, valid_asset_account(&payer)), + (payer, payer_account()), + (pda, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // PDA is present but not a signer → MissingRequiredSignature. + assert_failure(&result, ProgramError::MissingRequiredSignature); +} + +#[test] +fn cannot_add_duplicate_agent_identity() { + let mollusk = core_mollusk(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (pda, _) = agent_identity_pda(&asset_key); + + // Asset already has an agent identity plugin. + let asset_account = build_asset_with_agent_identity( + &payer, + "https://example.com/agent.json", + Authority::UpdateAuthority, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, + )], + ); + + let instruction = add_agent_identity_instruction( + asset_key, + payer, + pda, + &AgentIdentityInitInfo { + uri: "https://example.com/agent2.json".to_string(), + init_plugin_authority: None, + lifecycle_checks: vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x1 }, + )], + }, + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (payer, payer_account()), + (pda, payer_account()), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // Plugin already exists → ExternalPluginAdapterAlreadyExists (32). + assert_failure(&result, ProgramError::Custom(32)); +} diff --git a/programs/mpl-core/tests/execution_delegate.rs b/programs/mpl-core/tests/execution_delegate.rs new file mode 100644 index 00000000..25eb5a8f --- /dev/null +++ b/programs/mpl-core/tests/execution_delegate.rs @@ -0,0 +1,1139 @@ +// Execution Delegate Mollusk Tests +// +// These tests verify the execution delegate mechanism in the AgentIdentity +// plugin's `validate_execute`. When an ExecutionDelegateRecordV1 account is +// passed as the first remaining account (index 7 in the full accounts list), +// and the signing authority matches the record, the plugin approves execution +// for non-owner authorities. + +#[allow(deprecated)] +use { + borsh::BorshSerialize, + mollusk_svm::Mollusk, + mpl_core_program::{ + plugins::{ + AgentIdentity, ExternalCheckResult, ExternalPluginAdapter, ExternalPluginAdapterType, + ExternalRegistryRecord, HookableLifecycleEvent, PluginHeaderV1, PluginRegistryV1, + }, + state::{AssetV1, Authority, DataBlob, Key, UpdateAuthority}, + ID as MPL_CORE_ID, + }, + solana_program::program_error::ProgramError, + solana_sdk::{ + account::Account, + instruction::{AccountMeta, Instruction}, + pubkey::Pubkey, + system_program, + }, +}; + +/// The mpl-agent-tools program ID (owner of ExecutionDelegateRecordV1 accounts). +const MPL_AGENT_TOOLS_ID: Pubkey = + solana_sdk::pubkey!("TLREGni9ZEyGC3vnPZtqUh95xQ8oPqJSvNjvB7FGK8S"); + +/// Minimum lamports for accounts to be rent-exempt-ish in tests. +const ACCOUNT_LAMPORTS: u64 = 1_000_000_000; + +// --------------------------------------------------------------------------- +// Helpers +// --------------------------------------------------------------------------- + +fn core_mollusk() -> Mollusk { + Mollusk::new(&MPL_CORE_ID, "mpl_core_program") +} + +fn payer_account() -> Account { + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + } +} + +fn to_mollusk_accounts(accounts: Vec<(Pubkey, Account)>) -> Vec<(Pubkey, Account)> { + let mut result = accounts; + + if let Some(pos) = result.iter().position(|(k, _)| *k == system_program::ID) { + result.remove(pos); + } + + let (sys_key, sys_account) = mollusk_svm::program::keyed_account_for_system_program(); + result.push((sys_key, sys_account)); + + result +} + +fn assert_failure(result: &mollusk_svm::result::InstructionResult, expected: ProgramError) { + match &result.program_result { + mollusk_svm::result::ProgramResult::Success => { + panic!( + "Expected instruction to fail with {:?}, but it succeeded", + expected + ); + } + mollusk_svm::result::ProgramResult::Failure(err) => { + assert_eq!( + *err, expected, + "Expected error {:?}, got {:?}", + expected, err + ); + } + mollusk_svm::result::ProgramResult::UnknownError(err) => { + panic!( + "Expected ProgramError {:?}, got UnknownError({:?})", + expected, err + ); + } + } +} + +/// Derive the asset signer PDA for the Execute instruction. +fn asset_signer_pda(asset: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address(&[b"mpl-core-execute", asset.as_ref()], &MPL_CORE_ID) +} + +// --------------------------------------------------------------------------- +// Account data builders +// --------------------------------------------------------------------------- + +/// Builds an Account containing an AssetV1 with an AgentIdentity external +/// plugin that has the given lifecycle checks. +fn build_asset_with_agent_identity( + owner: &Pubkey, + lifecycle_checks: Vec<(HookableLifecycleEvent, ExternalCheckResult)>, +) -> Account { + let asset = AssetV1::new( + *owner, + UpdateAuthority::Address(*owner), + "Test Asset".to_string(), + "https://example.com/test".to_string(), + ); + let asset_data = asset.try_to_vec().unwrap(); + let asset_len = asset.len(); + + let header_offset = asset_len; + // PluginHeaderV1 is 9 bytes: 1 (Key) + 8 (usize). + let plugin_data_start = header_offset + 9; + + let plugin = ExternalPluginAdapter::AgentIdentity(AgentIdentity { + uri: "https://example.com/agent.json".to_string(), + }); + let plugin_bytes = plugin.try_to_vec().unwrap(); + + let registry_offset = plugin_data_start + plugin_bytes.len(); + + let header = PluginHeaderV1 { + key: Key::PluginHeaderV1, + plugin_registry_offset: registry_offset, + }; + + let external_record = ExternalRegistryRecord { + plugin_type: ExternalPluginAdapterType::AgentIdentity, + authority: Authority::UpdateAuthority, + lifecycle_checks: Some(lifecycle_checks), + offset: plugin_data_start, + data_offset: None, + data_len: None, + }; + + let registry = PluginRegistryV1 { + key: Key::PluginRegistryV1, + registry: vec![], + external_registry: vec![external_record], + }; + + let header_bytes = header.try_to_vec().unwrap(); + let registry_bytes = registry.try_to_vec().unwrap(); + + let mut data = Vec::new(); + data.extend_from_slice(&asset_data); + data.extend_from_slice(&header_bytes); + data.extend_from_slice(&plugin_bytes); + data.extend_from_slice(®istry_bytes); + + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + } +} + +/// Builds a bare AssetV1 (no plugins) owned by mpl-core. +fn valid_asset_account(owner: &Pubkey) -> Account { + let asset = AssetV1::new( + *owner, + UpdateAuthority::Address(*owner), + "Test Asset".to_string(), + "https://example.com/test".to_string(), + ); + let data = asset.try_to_vec().unwrap(); + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_CORE_ID, + executable: false, + rent_epoch: 0, + } +} + +/// Manually constructs a 104-byte ExecutionDelegateRecordV1 account. +/// +/// Layout (104 bytes): +/// [0] = 0x02 (Key::ExecutionDelegateRecordV1) +/// [1] = bump (u8) +/// [2..8] = padding [0u8; 6] +/// [8..40] = executive_profile (Pubkey) +/// [40..72] = authority (Pubkey) +/// [72..104] = agent_asset (Pubkey) +fn build_execution_delegate_record( + executive_profile: &Pubkey, + authority: &Pubkey, + agent_asset: &Pubkey, +) -> Account { + let mut data = vec![0u8; 104]; + data[0] = 0x02; // Key::ExecutionDelegateRecordV1 + data[1] = 255; // bump (arbitrary) + // [2..8] padding already zeroed + data[8..40].copy_from_slice(executive_profile.as_ref()); + data[40..72].copy_from_slice(authority.as_ref()); + data[72..104].copy_from_slice(agent_asset.as_ref()); + + Account { + lamports: ACCOUNT_LAMPORTS, + data, + owner: MPL_AGENT_TOOLS_ID, + executable: false, + rent_epoch: 0, + } +} + +// --------------------------------------------------------------------------- +// Instruction builder +// --------------------------------------------------------------------------- + +/// Builds an ExecuteV1 instruction (discriminator 31). +/// +/// Account layout (7 fixed): +/// 0: asset (writable) +/// 1: collection (optional, writable) -- MPL_CORE_ID placeholder +/// 2: asset_signer -- PDA from ["mpl-core-execute", asset] +/// 3: payer (writable, signer) +/// 4: authority (optional, signer) -- MPL_CORE_ID placeholder if same as payer +/// 5: system_program +/// 6: program_id -- target CPI program +/// +/// Remaining accounts (index 7+): delegate record (if any), then CPI accounts. +fn execute_v1_instruction( + asset: Pubkey, + asset_signer: Pubkey, + payer: Pubkey, + authority: Option, + program_id: Pubkey, + delegate_record: Option<(Pubkey, Account)>, + cpi_remaining_accounts: Vec, + instruction_data: Vec, +) -> Instruction { + let mut data = vec![31u8]; // ExecuteV1 discriminator + + // ExecuteV1Args: { instruction_data: Vec } + instruction_data.serialize(&mut data).unwrap(); + + let authority_meta = match authority { + Some(auth) => AccountMeta::new_readonly(auth, true), + None => AccountMeta::new_readonly(MPL_CORE_ID, false), // placeholder + }; + + let mut accounts = vec![ + AccountMeta::new(asset, false), // 0: asset + AccountMeta::new(MPL_CORE_ID, false), // 1: collection (optional) + AccountMeta::new_readonly(asset_signer, false), // 2: asset_signer + AccountMeta::new(payer, true), // 3: payer + authority_meta, // 4: authority + AccountMeta::new_readonly(system_program::ID, false), // 5: system_program + AccountMeta::new_readonly(program_id, false), // 6: program_id + ]; + + if let Some((delegate_key, _)) = &delegate_record { + accounts.push(AccountMeta::new_readonly(*delegate_key, false)); // 7: delegate record + } + + accounts.extend(cpi_remaining_accounts); + + Instruction::new_with_bytes(MPL_CORE_ID, &data, accounts) +} + +// =========================================================================== +// Happy-path tests +// =========================================================================== + +/// Owner calls execute -- no delegate needed, owner authority approves. +/// The CPI to spl_noop will fail (program not loaded) but validation passes. +/// We verify the error is NOT NoApprovals (Custom(26)). +#[test] +fn execute_as_owner() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + + // Asset with AgentIdentity plugin (Execute: CAN_LISTEN | CAN_APPROVE) + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, // CAN_LISTEN | CAN_APPROVE + )], + ); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + owner, + None, // authority = payer (owner) + spl_noop::ID, + None, // no delegate record + vec![], // no CPI remaining accounts + vec![], // instruction_data + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (owner, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // Validation should pass (owner is authority). CPI may fail if spl_noop + // binary isn't loaded, but we should NOT get NoApprovals. + match &result.program_result { + mollusk_svm::result::ProgramResult::Success => { /* great */ } + mollusk_svm::result::ProgramResult::Failure(err) => { + assert_ne!( + *err, + ProgramError::Custom(26), // NoApprovals + "Owner execute should not fail with NoApprovals" + ); + } + mollusk_svm::result::ProgramResult::UnknownError(_) => { /* CPI failure is OK */ } + } +} + +// =========================================================================== +// Execution delegate happy-path tests +// =========================================================================== + +/// Non-owner authority with a valid ExecutionDelegateRecordV1 that matches +/// (authority + agent_asset). The AgentIdentity plugin has Execute with +/// CAN_APPROVE, so validation should approve. +#[test] +fn execute_with_valid_delegate_record() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let delegate_authority = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + let executive_profile = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, // CAN_LISTEN | CAN_APPROVE + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + let delegate_record_account = + build_execution_delegate_record(&executive_profile, &delegate_authority, &asset_key); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + delegate_authority, + None, // authority = payer + spl_noop::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (delegate_authority, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + // Validation should pass. CPI may fail but NOT NoApprovals. + match &result.program_result { + mollusk_svm::result::ProgramResult::Success => { /* great */ } + mollusk_svm::result::ProgramResult::Failure(err) => { + assert_ne!( + *err, + ProgramError::Custom(26), // NoApprovals + "Valid delegate should not fail with NoApprovals" + ); + } + mollusk_svm::result::ProgramResult::UnknownError(_) => { /* CPI failure is OK */ } + } +} + +/// Delegate is also the payer (authority == payer), with separate authority account. +#[test] +fn execute_with_delegate_as_separate_authority() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let delegate_authority = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + let executive_profile = Pubkey::new_unique(); + let payer = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + let delegate_record_account = + build_execution_delegate_record(&executive_profile, &delegate_authority, &asset_key); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + payer, + Some(delegate_authority), // separate authority + spl_noop::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (payer, payer_account()), + (delegate_authority, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + match &result.program_result { + mollusk_svm::result::ProgramResult::Success => { /* great */ } + mollusk_svm::result::ProgramResult::Failure(err) => { + assert_ne!( + *err, + ProgramError::Custom(26), + "Valid delegate with separate authority should not fail with NoApprovals" + ); + } + mollusk_svm::result::ProgramResult::UnknownError(_) => { /* CPI failure is OK */ } + } +} + +// =========================================================================== +// Negative / security tests +// =========================================================================== + +/// Non-owner, no remaining accounts (<=7 total) -- plugin abstains -- NoApprovals. +#[test] +fn execute_non_owner_without_remaining_accounts() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let non_owner = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + non_owner, + None, + spl_noop::ID, + None, // no delegate record + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (non_owner, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_failure(&result, ProgramError::Custom(26)); // NoApprovals +} + +/// Wrong PDA for asset_signer -- InvalidExecutePda (Custom(49)). +#[test] +fn execute_with_invalid_asset_signer_pda() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let wrong_signer = Pubkey::new_unique(); // not a valid PDA + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let instruction = execute_v1_instruction( + asset_key, + wrong_signer, + owner, + None, + spl_noop::ID, + None, + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (owner, payer_account()), + (wrong_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_failure(&result, ProgramError::Custom(49)); // InvalidExecutePda +} + +/// Asset has no AgentIdentity plugin, non-owner tries execute -- NoApprovals. +#[test] +fn execute_non_owner_without_agent_identity_plugin() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let non_owner = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + + // Bare asset, no plugins. + let asset_account = valid_asset_account(&owner); + + let delegate_record_key = Pubkey::new_unique(); + let delegate_record_account = + build_execution_delegate_record(&Pubkey::new_unique(), &non_owner, &asset_key); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + non_owner, + None, + spl_noop::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (non_owner, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_failure(&result, ProgramError::Custom(26)); // NoApprovals +} + +/// Delegate record has different authority than signer -- Abstain -- NoApprovals. +#[test] +fn execute_with_wrong_authority_delegate() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let actual_signer = Pubkey::new_unique(); + let different_authority = Pubkey::new_unique(); // doesn't match signer + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + // Record authority is different_authority, but signer is actual_signer + let delegate_record_account = + build_execution_delegate_record(&Pubkey::new_unique(), &different_authority, &asset_key); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + actual_signer, + None, + spl_noop::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (actual_signer, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_failure(&result, ProgramError::Custom(26)); // NoApprovals +} + +/// Delegate record has different agent_asset -- Abstain -- NoApprovals. +#[test] +fn execute_with_wrong_asset_delegate() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let delegate_authority = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let wrong_asset = Pubkey::new_unique(); // doesn't match asset_key + let (asset_signer, _) = asset_signer_pda(&asset_key); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + // Record agent_asset is wrong_asset, not asset_key + let delegate_record_account = + build_execution_delegate_record(&Pubkey::new_unique(), &delegate_authority, &wrong_asset); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + delegate_authority, + None, + spl_noop::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (delegate_authority, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_failure(&result, ProgramError::Custom(26)); // NoApprovals +} + +/// Delegate record account NOT owned by mpl_agent_tools::ID -- Abstain -- NoApprovals. +#[test] +fn execute_with_wrong_program_owner_delegate() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let delegate_authority = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + let mut delegate_record_account = + build_execution_delegate_record(&Pubkey::new_unique(), &delegate_authority, &asset_key); + // Override owner to system_program (wrong owner) + delegate_record_account.owner = system_program::ID; + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + delegate_authority, + None, + spl_noop::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (delegate_authority, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_failure(&result, ProgramError::Custom(26)); // NoApprovals +} + +/// Delegate record with Key byte != 0x02 -- Abstain -- NoApprovals. +#[test] +fn execute_with_invalid_discriminator_delegate() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let delegate_authority = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + let mut delegate_record_account = + build_execution_delegate_record(&Pubkey::new_unique(), &delegate_authority, &asset_key); + // Override discriminator byte to invalid value + delegate_record_account.data[0] = 0xFF; + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + delegate_authority, + None, + spl_noop::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![], + vec![], + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (delegate_authority, payer_account()), + (asset_signer, payer_account()), + ( + spl_noop::ID, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: solana_sdk::bpf_loader::ID, + executable: true, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert_failure(&result, ProgramError::Custom(26)); // NoApprovals +} + +// =========================================================================== +// CPI account shift bug tests +// =========================================================================== + +/// Baseline: owner executes a system transfer via CPI with no delegate record. +/// The asset_signer PDA is the source. This should succeed end-to-end. +#[test] +fn execute_system_transfer_owner_no_delegate() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + let dest = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + // Build a system transfer instruction: asset_signer -> dest, 1 lamport. + let transfer_ix = solana_sdk::system_instruction::transfer(&asset_signer, &dest, 1); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + owner, + None, + system_program::ID, // CPI target = system program + None, // no delegate record + vec![ + AccountMeta::new(asset_signer, false), // CPI account 0: source + AccountMeta::new(dest, false), // CPI account 1: dest + ], + transfer_ix.data, + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (owner, payer_account()), + ( + asset_signer, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + ( + dest, + Account { + lamports: 0, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert!( + matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Owner system transfer CPI should succeed, got: {:?}", + result.program_result + ); +} + +/// Delegate execute with system transfer CPI. The delegate record at +/// remaining_accounts[0] must be stripped before CPI so the target program +/// receives only the real CPI accounts. +#[test] +fn execute_system_transfer_with_delegate_record_stripped() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let delegate_authority = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + let executive_profile = Pubkey::new_unique(); + let dest = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + let delegate_record_account = + build_execution_delegate_record(&executive_profile, &delegate_authority, &asset_key); + + let transfer_ix = solana_sdk::system_instruction::transfer(&asset_signer, &dest, 1); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + delegate_authority, + None, + system_program::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![ + AccountMeta::new(asset_signer, false), + AccountMeta::new(dest, false), + ], + transfer_ix.data, + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (delegate_authority, payer_account()), + ( + asset_signer, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + ( + dest, + Account { + lamports: 0, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert!( + matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Delegate system transfer CPI should succeed after stripping delegate record, got: {:?}", + result.program_result + ); +} + +/// Delegate execute with separate authority and system transfer CPI. +#[test] +fn execute_system_transfer_delegate_separate_authority() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let delegate_authority = Pubkey::new_unique(); + let payer = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + let executive_profile = Pubkey::new_unique(); + let dest = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let delegate_record_key = Pubkey::new_unique(); + let delegate_record_account = + build_execution_delegate_record(&executive_profile, &delegate_authority, &asset_key); + + let transfer_ix = solana_sdk::system_instruction::transfer(&asset_signer, &dest, 1); + + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + payer, + Some(delegate_authority), + system_program::ID, + Some((delegate_record_key, delegate_record_account.clone())), + vec![ + AccountMeta::new(asset_signer, false), + AccountMeta::new(dest, false), + ], + transfer_ix.data, + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (payer, payer_account()), + (delegate_authority, payer_account()), + ( + asset_signer, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + ( + dest, + Account { + lamports: 0, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + (delegate_record_key, delegate_record_account), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert!( + matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Delegate (separate authority) system transfer should succeed, got: {:?}", + result.program_result + ); +} + +/// Non-delegate remaining account (not owned by mpl_agent_tools) should NOT be +/// stripped -- it should be passed through to the CPI as-is. +#[test] +fn execute_system_transfer_non_delegate_remaining_account_preserved() { + let mollusk = core_mollusk(); + let owner = Pubkey::new_unique(); + let asset_key = Pubkey::new_unique(); + let (asset_signer, _) = asset_signer_pda(&asset_key); + let dest = Pubkey::new_unique(); + + let asset_account = build_asset_with_agent_identity( + &owner, + vec![( + HookableLifecycleEvent::Execute, + ExternalCheckResult { flags: 0x3 }, + )], + ); + + let transfer_ix = solana_sdk::system_instruction::transfer(&asset_signer, &dest, 1); + + // No delegate record -- just CPI accounts in remaining. + let instruction = execute_v1_instruction( + asset_key, + asset_signer, + owner, + None, + system_program::ID, + None, + vec![ + AccountMeta::new(asset_signer, false), + AccountMeta::new(dest, false), + ], + transfer_ix.data, + ); + + let accounts = to_mollusk_accounts(vec![ + (asset_key, asset_account), + (owner, payer_account()), + ( + asset_signer, + Account { + lamports: ACCOUNT_LAMPORTS, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + ( + dest, + Account { + lamports: 0, + data: vec![], + owner: system_program::ID, + executable: false, + rent_epoch: 0, + }, + ), + ]); + + let result = mollusk.process_instruction(&instruction, &accounts); + assert!( + matches!( + result.program_result, + mollusk_svm::result::ProgramResult::Success + ), + "Owner CPI without delegate should pass all remaining accounts through, got: {:?}", + result.program_result + ); +} diff --git a/rust-toolchain.toml b/rust-toolchain.toml new file mode 100644 index 00000000..908d2ecb --- /dev/null +++ b/rust-toolchain.toml @@ -0,0 +1,3 @@ +[toolchain] +channel = "1.89.0" +components = ["rustfmt", "clippy"]